优化支付宝支付流程与 Web 端体验
- 支付宝新窗口跳转,轮询与手动刷新增加加载反馈 - 支付回跳先校验订单状态,避免未付款误报成功 - 门户登录回调统一,云文件打开加载与版本冲突同步 - 精简本地 start.bat 与 README 说明 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -135,6 +135,7 @@
|
||||
}
|
||||
|
||||
function soonReportSaveError(err) {
|
||||
if (err && err.conflictSynced) return;
|
||||
if (typeof window.soonShowApiError === 'function') {
|
||||
window.soonShowApiError({
|
||||
status: err && err.status,
|
||||
@@ -656,9 +657,22 @@
|
||||
}
|
||||
|
||||
function soonReportOpenLoadError(message) {
|
||||
soonHideOpenFileLoading();
|
||||
soonToast(message || '文件加载失败', 'error');
|
||||
}
|
||||
|
||||
function soonShowOpenFileLoading() {
|
||||
if (typeof layer === 'undefined' || !layer.load) return;
|
||||
soonHideOpenFileLoading();
|
||||
window._soonOpenLoadIdx = layer.load(1, { shade: [0.12, '#000'] });
|
||||
}
|
||||
|
||||
function soonHideOpenFileLoading() {
|
||||
if (window._soonOpenLoadIdx == null) return;
|
||||
if (typeof layer !== 'undefined' && layer.close) layer.close(window._soonOpenLoadIdx);
|
||||
window._soonOpenLoadIdx = null;
|
||||
}
|
||||
|
||||
function soonToast(message, type) {
|
||||
if (typeof window.soonToast === 'function') window.soonToast(message, type);
|
||||
}
|
||||
@@ -737,29 +751,60 @@
|
||||
return String(pathOrKey).split(/[/\\]/).pop();
|
||||
}
|
||||
|
||||
function soonFetchOrderStatus(orderNo) {
|
||||
var url = soonApiBase() + '/pay/orders/' + encodeURIComponent(orderNo);
|
||||
var fetchFn = typeof window.soonAuthedFetch === 'function'
|
||||
? window.soonAuthedFetch(url, { headers: { Accept: 'application/json' } })
|
||||
: fetch(url, { headers: { Authorization: 'Bearer ' + soonGetAccessToken(), Accept: 'application/json' } });
|
||||
return fetchFn.then(function (r) {
|
||||
if (!r.ok) return null;
|
||||
return r.json();
|
||||
}).then(function (j) {
|
||||
return j && j.ok && j.data ? j.data : null;
|
||||
}).catch(function () {
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
function soonPollOrderPaid(orderNo, attemptsLeft, delayMs) {
|
||||
return soonFetchOrderStatus(orderNo).then(function (data) {
|
||||
if (data && data.status === 'paid') return data;
|
||||
if (attemptsLeft <= 1) return data;
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(function () {
|
||||
resolve(soonPollOrderPaid(orderNo, attemptsLeft - 1, delayMs));
|
||||
}, delayMs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function soonHandlePayReturn() {
|
||||
var paid = null;
|
||||
var flag = false;
|
||||
var orderNo = null;
|
||||
try {
|
||||
paid = new URLSearchParams(location.search).get('paid');
|
||||
orderNo = new URLSearchParams(location.search).get('paid');
|
||||
} catch (e) { /* ignore */ }
|
||||
try {
|
||||
flag = !!sessionStorage.getItem('soon_pay_return');
|
||||
} catch (e) { /* ignore */ }
|
||||
if (!paid && !flag) return;
|
||||
try {
|
||||
sessionStorage.removeItem('soon_pay_return');
|
||||
} catch (e) { /* ignore */ }
|
||||
if (paid) {
|
||||
try {
|
||||
var u = new URL(location.href);
|
||||
u.searchParams.delete('paid');
|
||||
history.replaceState(null, '', u.pathname + (u.search || '') + (u.hash || ''));
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
soonLoadMembership(true).then(function () {
|
||||
soonRefreshPortalIdentity();
|
||||
soonToast('支付成功,会员已激活', 'success');
|
||||
if (!orderNo) return;
|
||||
try {
|
||||
var u = new URL(location.href);
|
||||
u.searchParams.delete('paid');
|
||||
history.replaceState(null, '', u.pathname + (u.search || '') + (u.hash || ''));
|
||||
} catch (e) { /* ignore */ }
|
||||
if (!soonGetAccessToken()) return;
|
||||
soonPollOrderPaid(orderNo, 10, 3000).then(function (data) {
|
||||
if (data && data.status === 'paid') {
|
||||
return soonLoadMembership(true).then(function () {
|
||||
soonRefreshPortalIdentity();
|
||||
soonToast('支付成功,会员已激活', 'success');
|
||||
});
|
||||
}
|
||||
if (data && data.status === 'cancelled') {
|
||||
soonToast('订单已取消', 'warn');
|
||||
return;
|
||||
}
|
||||
soonToast('支付尚未完成,如已付款请稍后在会员中心查看', 'warn');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -783,6 +828,8 @@
|
||||
window.soonTryConsumeCloudImport = soonTryConsumeCloudImport;
|
||||
window.soonClearPendingImport = soonClearPendingImport;
|
||||
window.soonReportOpenLoadError = soonReportOpenLoadError;
|
||||
window.soonShowOpenFileLoading = soonShowOpenFileLoading;
|
||||
window.soonHideOpenFileLoading = soonHideOpenFileLoading;
|
||||
window.soonParseTemplateKey = soonParseTemplateKey;
|
||||
window.soonMakeTemplateKey = soonMakeTemplateKey;
|
||||
window.soonSoonTypeFromJson = soonSoonTypeFromJson;
|
||||
|
||||
@@ -77,12 +77,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
function submitAlipayForm(payForm) {
|
||||
var ALIPAY_WINDOW_NAME = 'soon_alipay_pay';
|
||||
|
||||
function openAlipayPayWindow() {
|
||||
try {
|
||||
var w = window.open('about:blank', ALIPAY_WINDOW_NAME);
|
||||
if (w) {
|
||||
w.document.title = '支付宝收银台';
|
||||
w.document.body.innerHTML =
|
||||
'<p style="font-family:sans-serif;text-align:center;padding:48px 24px;color:#333">正在跳转支付宝…</p>';
|
||||
}
|
||||
return w;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function submitAlipayForm(payForm, payWindow) {
|
||||
if (!payForm || !payForm.gateway || !payForm.params) return false;
|
||||
if (!isSafeAlipayGateway(payForm.gateway)) return false;
|
||||
var win = payWindow;
|
||||
if (!win || win.closed) {
|
||||
win = openAlipayPayWindow();
|
||||
}
|
||||
if (!win) return false;
|
||||
var form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = payForm.gateway;
|
||||
form.target = ALIPAY_WINDOW_NAME;
|
||||
form.acceptCharset = 'UTF-8';
|
||||
form.style.display = 'none';
|
||||
Object.keys(payForm.params).forEach(function (key) {
|
||||
@@ -96,6 +118,11 @@
|
||||
});
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
setTimeout(function () {
|
||||
try {
|
||||
document.body.removeChild(form);
|
||||
} catch (e) { /* ignore */ }
|
||||
}, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -218,27 +245,34 @@
|
||||
'<p class="soon-pay-checkout-empty__desc">点击下方按钮,将使用' + esc(ui.name) + '(' + esc(ui.hint) + ')</p></div>';
|
||||
}
|
||||
|
||||
function renderPayPayload(data, qrEl, orderNoEl) {
|
||||
function renderPayPayload(data, qrEl, orderNoEl, launchOpts) {
|
||||
launchOpts = launchOpts || {};
|
||||
if (orderNoEl && data.order_no) {
|
||||
orderNoEl.textContent = '订单号 ' + data.order_no;
|
||||
orderNoEl.style.display = '';
|
||||
}
|
||||
if (data.pay_form && data.pay_form.gateway) {
|
||||
if (!isSafeAlipayGateway(data.pay_form.gateway)) return '支付网关无效';
|
||||
sessionStorage.setItem('soon_pay_return', '1');
|
||||
var payForm = data.pay_form;
|
||||
var launched = launchOpts.launched === true;
|
||||
qrEl.innerHTML =
|
||||
'<div class="soon-pay-checkout-ready soon-pay-checkout-ready--alipay">' +
|
||||
'<div class="soon-pay-checkout-ready__brand soon-pay-checkout-ready__brand--alipay">支</div>' +
|
||||
'<p class="soon-pay-checkout-ready__title">支付宝电脑网站支付</p>' +
|
||||
'<p class="soon-pay-checkout-ready__desc">点击下方按钮跳转至支付宝收银台,支付完成后将自动返回</p>' +
|
||||
'<button type="button" class="soon-btn soon-pay-checkout-ready__btn" id="goAlipay">前往支付宝付款</button></div>';
|
||||
'<p class="soon-pay-checkout-ready__desc">' +
|
||||
(launched
|
||||
? '支付窗口已打开,请在新窗口完成付款;本页将自动检测支付结果'
|
||||
: '未能自动打开支付窗口,请允许弹窗后点击下方按钮') +
|
||||
'</p>' +
|
||||
'<button type="button" class="soon-btn soon-pay-checkout-ready__btn" id="goAlipay">' +
|
||||
(launched ? '重新打开支付页面' : '打开支付宝付款') +
|
||||
'</button></div>';
|
||||
var alipayBtn = qrEl.querySelector('#goAlipay');
|
||||
if (alipayBtn) {
|
||||
alipayBtn.onclick = function () {
|
||||
if (!submitAlipayForm(payForm)) {
|
||||
if (typeof window.soonToast === 'function') {
|
||||
window.soonToast('无法跳转支付宝,请检查支付配置', 'warn');
|
||||
window.soonToast('无法打开支付窗口,请允许浏览器弹窗', 'warn');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -298,6 +332,9 @@
|
||||
'<div class="soon-pay-qr-panel" id="payQr">' + payEmptyStateHtml(channel) + '</div></section>' +
|
||||
'<div class="soon-pay-sheet__foot">' +
|
||||
'<p class="soon-pay-status" id="payStatus"></p>' +
|
||||
'<div class="soon-pay-poll" id="payPollHint" aria-live="polite">' +
|
||||
'<span class="soon-pay-poll__spin" aria-hidden="true"></span>' +
|
||||
'<span class="soon-pay-poll__text">正在检测支付结果</span></div>' +
|
||||
'<button type="button" class="soon-btn soon-pay-sheet__cta" id="payConfirm">' +
|
||||
(resumeOrderNo ? '继续支付' : '确认并支付') + '</button>' +
|
||||
'<button type="button" class="soon-btn soon-btn--ghost soon-btn--sm soon-pay-sheet__cta soon-pay-sheet__cta--secondary" id="payManualRefresh" style="display:none">已完成支付,刷新状态</button>' +
|
||||
@@ -322,10 +359,14 @@
|
||||
|
||||
var manualBtn = sheetRoot.querySelector('#payManualRefresh');
|
||||
var statusEl = sheetRoot.querySelector('#payStatus');
|
||||
var pollHint = sheetRoot.querySelector('#payPollHint');
|
||||
var confirmBtn = sheetRoot.querySelector('#payConfirm');
|
||||
var qrEl = sheetRoot.querySelector('#payQr');
|
||||
var orderNoEl = sheetRoot.querySelector('#payOrderNo');
|
||||
var backBtn = sheetRoot.querySelector('#payBack');
|
||||
var checking = false;
|
||||
var pollTickTimer = null;
|
||||
var MANUAL_REFRESH_LABEL = '已完成支付,刷新状态';
|
||||
|
||||
function setStatus(text, type) {
|
||||
if (!statusEl) return;
|
||||
@@ -334,6 +375,20 @@
|
||||
statusEl.style.display = text ? 'block' : 'none';
|
||||
}
|
||||
|
||||
function setPolling(active) {
|
||||
sheetRoot.classList.toggle('soon-pay-sheet--polling', !!active);
|
||||
if (!active && pollHint) pollHint.classList.remove('is-tick');
|
||||
}
|
||||
|
||||
function flashPollTick() {
|
||||
if (!pollHint) return;
|
||||
pollHint.classList.add('is-tick');
|
||||
if (pollTickTimer) clearTimeout(pollTickTimer);
|
||||
pollTickTimer = setTimeout(function () {
|
||||
pollHint.classList.remove('is-tick');
|
||||
}, 450);
|
||||
}
|
||||
|
||||
function setStep(step) {
|
||||
updatePayStep(sheetRoot, step, channel);
|
||||
sheetRoot.classList.toggle('soon-pay-sheet--checkout', step >= 2);
|
||||
@@ -346,18 +401,21 @@
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
}
|
||||
setPolling(false);
|
||||
}
|
||||
|
||||
function startPoll() {
|
||||
stopPoll();
|
||||
setPolling(true);
|
||||
pollStartedAt = Date.now();
|
||||
checkOrderStatus(false);
|
||||
pollTimer = setInterval(function () {
|
||||
if (Date.now() - pollStartedAt > POLL_TIMEOUT_MS) {
|
||||
stopPoll();
|
||||
setStatus('自动检测超时,如已支付请点击下方按钮', 'err');
|
||||
return;
|
||||
}
|
||||
checkOrderStatus();
|
||||
checkOrderStatus(false);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
@@ -368,14 +426,37 @@
|
||||
setTimeout(onPaid, 600);
|
||||
}
|
||||
|
||||
function checkOrderStatus() {
|
||||
if (!orderNo) return;
|
||||
function checkOrderStatus(manual) {
|
||||
if (!orderNo || checking) return;
|
||||
checking = true;
|
||||
if (statusEl) statusEl.classList.add('is-checking');
|
||||
if (manual && manualBtn) {
|
||||
manualBtn.disabled = true;
|
||||
manualBtn.classList.add('is-loading');
|
||||
manualBtn.textContent = '查询中…';
|
||||
} else {
|
||||
flashPollTick();
|
||||
}
|
||||
apiGet('/pay/orders/' + encodeURIComponent(orderNo)).then(function (st) {
|
||||
if (st.ok && st.data && st.data.status === 'paid') handlePaid();
|
||||
if (st.ok && st.data && st.data.status === 'paid') {
|
||||
handlePaid();
|
||||
return;
|
||||
}
|
||||
if (manual) {
|
||||
setStatus('暂未收到支付结果,请完成付款后再试', 'warn');
|
||||
}
|
||||
}).finally(function () {
|
||||
checking = false;
|
||||
if (statusEl) statusEl.classList.remove('is-checking');
|
||||
if (manual && manualBtn) {
|
||||
manualBtn.disabled = false;
|
||||
manualBtn.classList.remove('is-loading');
|
||||
manualBtn.textContent = MANUAL_REFRESH_LABEL;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (manualBtn) manualBtn.onclick = checkOrderStatus;
|
||||
if (manualBtn) manualBtn.onclick = function () { checkOrderStatus(true); };
|
||||
|
||||
function resetPaymentView() {
|
||||
paymentReady = false;
|
||||
@@ -391,9 +472,13 @@
|
||||
setStatus('');
|
||||
}
|
||||
|
||||
function applyCheckout(data) {
|
||||
function applyCheckout(data, payWindow) {
|
||||
orderNo = data.order_no;
|
||||
var err = renderPayPayload(data, qrEl, orderNoEl);
|
||||
var launched = false;
|
||||
if (channel === 'alipay' && data.pay_form && data.pay_form.gateway) {
|
||||
launched = submitAlipayForm(data.pay_form, payWindow);
|
||||
}
|
||||
var err = renderPayPayload(data, qrEl, orderNoEl, { launched: launched });
|
||||
if (err) {
|
||||
setStatus(err, 'err');
|
||||
return;
|
||||
@@ -402,7 +487,14 @@
|
||||
setStep(2);
|
||||
if (confirmBtn) confirmBtn.style.display = 'none';
|
||||
if (manualBtn) manualBtn.style.display = '';
|
||||
setStatus('等待支付结果,完成后将自动刷新', 'ok');
|
||||
if (channel === 'alipay') {
|
||||
setStatus(
|
||||
launched ? '支付窗口已打开,请在新窗口完成付款' : '未能自动打开支付窗口,请允许弹窗或点击下方按钮',
|
||||
launched ? 'ok' : 'err'
|
||||
);
|
||||
} else {
|
||||
setStatus('请扫码完成支付,本页将自动检测支付结果', 'ok');
|
||||
}
|
||||
startPoll();
|
||||
}
|
||||
|
||||
@@ -411,6 +503,7 @@
|
||||
setStatus('正在生成付款信息…');
|
||||
qrEl.innerHTML = '<div class="soon-pay-checkout-loading"><div class="soon-skeleton soon-skeleton--h200"></div>' +
|
||||
'<p>正在连接支付渠道…</p></div>';
|
||||
var payWindow = channel === 'alipay' ? openAlipayPayWindow() : null;
|
||||
var req;
|
||||
if (resumeOrderNo || orderNo) {
|
||||
var existingNo = orderNo || resumeOrderNo;
|
||||
@@ -421,13 +514,15 @@
|
||||
req.then(function (j) {
|
||||
if (confirmBtn) confirmBtn.disabled = false;
|
||||
if (!j.ok) {
|
||||
if (payWindow && !payWindow.closed) payWindow.close();
|
||||
setStatus(j.message || '下单失败', 'err');
|
||||
qrEl.innerHTML = payEmptyStateHtml(channel);
|
||||
return;
|
||||
}
|
||||
applyCheckout(j.data);
|
||||
applyCheckout(j.data, payWindow);
|
||||
}).catch(function () {
|
||||
if (confirmBtn) confirmBtn.disabled = false;
|
||||
if (payWindow && !payWindow.closed) payWindow.close();
|
||||
setStatus('网络错误,请重试', 'err');
|
||||
qrEl.innerHTML = payEmptyStateHtml(channel);
|
||||
});
|
||||
@@ -448,6 +543,10 @@
|
||||
|
||||
function destroy() {
|
||||
stopPoll();
|
||||
if (pollTickTimer) {
|
||||
clearTimeout(pollTickTimer);
|
||||
pollTickTimer = null;
|
||||
}
|
||||
paymentReady = false;
|
||||
orderNo = resumeOrderNo;
|
||||
}
|
||||
@@ -537,6 +636,7 @@
|
||||
payEmptyStateHtml: payEmptyStateHtml,
|
||||
renderPayPayload: renderPayPayload,
|
||||
submitAlipayForm: submitAlipayForm,
|
||||
openAlipayPayWindow: openAlipayPayWindow,
|
||||
loadDisplayChannels: loadDisplayChannels,
|
||||
displayChannels: displayChannels,
|
||||
defaultChannel: defaultChannel,
|
||||
|
||||
@@ -77,28 +77,42 @@
|
||||
? window.soonAuthedFetch(base + '/auth/me', { headers: { Authorization: 'Bearer ' + tok } })
|
||||
: fetch(base + '/auth/me', { headers: { Authorization: 'Bearer ' + tok } });
|
||||
meFetch
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (r) {
|
||||
if (r.status === 401) {
|
||||
clearSession();
|
||||
location.reload();
|
||||
return null;
|
||||
}
|
||||
if (!r.ok) {
|
||||
if (typeof window.soonToast === 'function') window.soonToast('网络异常,部分功能可能不可用', 'warn');
|
||||
return null;
|
||||
}
|
||||
return r.json();
|
||||
})
|
||||
.then(function (j) {
|
||||
if (!j) return;
|
||||
if (!j.ok || !j.data) {
|
||||
clearSession();
|
||||
location.reload();
|
||||
return;
|
||||
}
|
||||
if (typeof window.soonApplyMembership === 'function') {
|
||||
window.soonApplyMembership(j.data);
|
||||
}
|
||||
if (j.data.role === 'admin' && admin) admin.style.display = 'inline-flex';
|
||||
if (avatar && j.data.email) {
|
||||
avatar.style.display = 'inline-flex';
|
||||
avatar.textContent = j.data.email.charAt(0).toUpperCase();
|
||||
avatar.title = j.data.email;
|
||||
}
|
||||
if (typeof window.soonLoadMembership === 'function') {
|
||||
window.soonLoadMembership().then(function () {
|
||||
if (typeof window.soonRefreshPortalIdentity === 'function') {
|
||||
window.soonRefreshPortalIdentity();
|
||||
}
|
||||
});
|
||||
if (typeof window.soonRefreshPortalIdentity === 'function') {
|
||||
window.soonRefreshPortalIdentity();
|
||||
}
|
||||
if (typeof options.onAuthed === 'function') options.onAuthed(j.data);
|
||||
})
|
||||
.catch(function () { /* keep authed shell */ });
|
||||
.catch(function () {
|
||||
if (typeof window.soonToast === 'function') window.soonToast('网络异常,部分功能可能不可用', 'warn');
|
||||
});
|
||||
|
||||
if (logout) {
|
||||
logout.addEventListener('click', function (e) {
|
||||
|
||||
@@ -1192,7 +1192,9 @@ window.openFile = function open(file, jAlready) {
|
||||
return;
|
||||
}
|
||||
if (window.platformBridge && window.platformBridge.readJsonFile) {
|
||||
if (typeof window.soonShowOpenFileLoading === 'function') window.soonShowOpenFileLoading();
|
||||
return window.platformBridge.readJsonFile(file).then(function(j) {
|
||||
if (typeof window.soonHideOpenFileLoading === 'function') window.soonHideOpenFileLoading();
|
||||
if (j) {
|
||||
doOpenWithJson(j);
|
||||
openAs.name = file;
|
||||
@@ -1201,6 +1203,7 @@ window.openFile = function open(file, jAlready) {
|
||||
}
|
||||
}).catch(function () {
|
||||
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
|
||||
else if (typeof window.soonHideOpenFileLoading === 'function') window.soonHideOpenFileLoading();
|
||||
});
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -1517,7 +1517,9 @@ window.openFile = function open(file, jAlready) {
|
||||
return;
|
||||
}
|
||||
if (window.platformBridge && window.platformBridge.readJsonFile) {
|
||||
if (typeof window.soonShowOpenFileLoading === 'function') window.soonShowOpenFileLoading();
|
||||
return window.platformBridge.readJsonFile(file).then(function(j) {
|
||||
if (typeof window.soonHideOpenFileLoading === 'function') window.soonHideOpenFileLoading();
|
||||
if (j) {
|
||||
doOpenWithJson(j);
|
||||
openAs.name = file;
|
||||
@@ -1526,6 +1528,7 @@ window.openFile = function open(file, jAlready) {
|
||||
}
|
||||
}).catch(function () {
|
||||
if (typeof window.soonReportOpenLoadError === 'function') window.soonReportOpenLoadError('模板/文件加载失败');
|
||||
else if (typeof window.soonHideOpenFileLoading === 'function') window.soonHideOpenFileLoading();
|
||||
});
|
||||
}
|
||||
try {
|
||||
|
||||
@@ -351,14 +351,22 @@ layui.use(['layer', 'form', 'jquery'], function () {
|
||||
|
||||
var start = (fileListState.page - 1) * fileListState.size;
|
||||
var slice = mapped.slice(start, start + fileListState.size);
|
||||
var thumbRows = await Promise.all(slice.map(async function (item) {
|
||||
var realType = item.type || 1;
|
||||
return {
|
||||
item: item,
|
||||
src: await resolveRecentThumb(item),
|
||||
fallbackSrc: recentFallbackThumb(realType)
|
||||
};
|
||||
}));
|
||||
let h = "";
|
||||
|
||||
for (let item of slice) {
|
||||
|
||||
for (let row of thumbRows) {
|
||||
let item = row.item;
|
||||
let filePath = item.filePath;
|
||||
let realType = item.type || 1;
|
||||
let src = await resolveRecentThumb(item);
|
||||
let fallbackSrc = recentFallbackThumb(realType);
|
||||
let src = row.src;
|
||||
let fallbackSrc = row.fallbackSrc;
|
||||
let displayName = item.name || displayNameFromPath(filePath);
|
||||
let cardTitle = displayName;
|
||||
var cardClass = 'card';
|
||||
|
||||
@@ -161,6 +161,40 @@
|
||||
.then(packCloudResult);
|
||||
}
|
||||
|
||||
function syncCloudFileAfterConflict(id) {
|
||||
var oldKey = (typeof window !== 'undefined' && window.openAs && window.openAs.name) ? window.openAs.name : '';
|
||||
return authedFetch('files/' + id, { headers: { Accept: 'application/json' } })
|
||||
.then(function (response) {
|
||||
if (!response.ok) return null;
|
||||
return response.json();
|
||||
})
|
||||
.then(function (payload) {
|
||||
if (!payload || !payload.ok || !payload.data) return null;
|
||||
var d = payload.data;
|
||||
var newKey = typeof window.soonApplyCloudMeta === 'function'
|
||||
? window.soonApplyCloudMeta(d)
|
||||
: ('soondesign_file:' + d.id + ':v' + d.version);
|
||||
if (oldKey && oldKey !== newKey && typeof window.soonLocalRemove === 'function') {
|
||||
window.soonLocalRemove(oldKey);
|
||||
}
|
||||
if (typeof window.soonRecentOnCloudSave === 'function') {
|
||||
window.soonRecentOnCloudSave({
|
||||
fileKey: newKey,
|
||||
fileId: d.id,
|
||||
name: d.name,
|
||||
version: d.version
|
||||
}, oldKey, null);
|
||||
}
|
||||
if (typeof window !== 'undefined' && window.openAs && newKey) {
|
||||
window.openAs.name = newKey;
|
||||
}
|
||||
if (typeof window.soonToast === 'function') {
|
||||
window.soonToast('文件已在其他端更新,已同步版本,请再次保存', 'warn');
|
||||
}
|
||||
return newKey;
|
||||
});
|
||||
}
|
||||
|
||||
function updateCloudFile(id, name, jsonStr, version) {
|
||||
if (!requireCloudAuth('保存')) return Promise.reject(new Error('unauthorized'));
|
||||
var body = { name: normalizeSoonName(name), json: jsonStr };
|
||||
@@ -170,7 +204,19 @@
|
||||
headers: JSON_HEADERS,
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.then(function (r) { return r.text().then(function (t) { return handleCloudResponse(r, t); }); })
|
||||
.then(function (r) {
|
||||
return r.text().then(function (t) {
|
||||
if (r.status === 409) {
|
||||
return syncCloudFileAfterConflict(id).then(function () {
|
||||
var err = new Error('version_conflict');
|
||||
err.status = 409;
|
||||
err.conflictSynced = true;
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
return handleCloudResponse(r, t);
|
||||
});
|
||||
})
|
||||
.then(packCloudResult);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user