Files
console-dev/app/components/instance/ImagePurchaseDialog.vue
T

294 lines
10 KiB
Vue

<script>
// 付费镜像授权弹窗:复查实时价格和已建订单状态,并在支付后重新检查授权。
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
import { toDisplayString } from "vue";
import { onBeforeUnmount } from "vue";
import { mergeModels } from "vue";
import { useModel } from "vue";
import { watch } from "vue";
import { createBlock } from "vue";
import { ref } from "vue";
import { withCtx } from "vue";
import { createCommentVNode } from "vue";
import { isRef } from "vue";
import { createElementBlock } from "vue";
import { Fragment } from "vue";
import { createElementVNode } from "vue";
import { createTextVNode } from "vue";
import { unref } from "vue";
import { defineComponent } from "vue";
import { createVNode } from "vue";
import { openBlock } from "vue";
import { useApi } from "~/lib/auth.js";
import dialog from "primevue/dialog";
import button from "primevue/button";
import message from "primevue/message";
import PaymentDialog from "~/components/PaymentDialog.vue";
var C = {
key: 0,
},
w = Object.assign(
defineComponent({
__name: `ImagePurchaseDialog`,
props: {
modelValue: {
default: null,
},
modelModifiers: {},
},
emits: mergeModels([`authorized`], [`update:modelValue`]),
setup(n, { emit: h }) {
let w = useModel(n, `modelValue`),
T = h,
E = useApi(),
D = ref(!1),
O = ref(``),
k = ref(!1),
A = ref(null),
j = new Map(),
M = 0,
N = !1,
P = (e) => `${e.module}:${e.hostId}:${e.imageId}`;
function F(e) {
if (
(typeof e != `string` && typeof e != `number`) ||
String(e).trim() === `` ||
!Number.isFinite(Number(e)) ||
Number(e) < 0
)
throw Error(`镜像费用信息无效,请重试`);
return Number(e).toFixed(2);
}
// 免费或已授权镜像直接放行;价格变化需用户重新确认,不能沿用旧金额创建订单。
async function I() {
let e = w.value;
if (!e || D.value || N) return;
let t = M,
n = () => !N && M === t && w.value === e;
((D.value = !0), (O.value = ``));
try {
let t = await E.get(`/${e.module}/${e.hostId}/image/check`, {
image_id: e.imageId,
});
if (!n()) return;
let r = F(t.price);
if (Number(r) === 0) {
(j.delete(P(e)), (w.value = null), T(`authorized`));
return;
}
if (r !== F(e.price)) {
((w.value = {
...e,
price: r,
}),
(O.value = `镜像费用已更新,请确认最新金额`));
return;
}
let i = j.get(P(e));
if (i) {
// 订单可在其他标签页取消;缓存只负责去重,是否可复用必须以服务端状态为准。
let { order } = await E.get(`/order/${i}`);
if (!n()) return;
if (!order || String(order.id) !== String(i))
throw Error(`镜像订单信息无效,请稍后重试`);
if (order.status === `Cancelled`) {
j.delete(P(e));
i = null;
} else if (order.status === `Paid`)
// 已付款不等于授权已同步,不能因授权延迟再创建一张收费订单。
throw Error(`镜像订单已支付,授权尚未生效,请稍后重新检查`);
else if (order.status !== `Unpaid`)
throw Error(`当前镜像订单状态不支持支付,请稍后重试`);
}
if (!i) {
let t = await E.post(`/${e.module}/${e.hostId}/image/order`, {
image_id: e.imageId,
});
if (!/^[1-9]\d*$/.test(String(t.id)))
throw Error(`镜像购买订单无效,请重试`);
((i = t.id), j.set(P(e), i));
}
if (!n()) return;
((A.value = i), (k.value = !0));
} catch (e) {
n() &&
(O.value = e instanceof Error ? e.message : `创建镜像订单失败`);
} finally {
t === M && (D.value = !1);
}
}
// 支付回调不等于授权已生效,只有检查接口费用变为 0 才通知调用方继续操作。
async function L() {
let e = w.value;
if (!e || N) return;
let t = M;
((D.value = !0), (O.value = ``), (k.value = !1));
try {
let n = await E.get(`/${e.module}/${e.hostId}/image/check`, {
image_id: e.imageId,
});
if (t !== M || N) return;
if (Number(F(n.price)) !== 0)
throw Error(`镜像授权尚未生效,请稍后重新检查`);
(j.delete(P(e)), (w.value = null), T(`authorized`));
} catch (e) {
t === M &&
(O.value = e instanceof Error ? e.message : `镜像授权校验失败`);
} finally {
t === M && (D.value = !1);
}
}
return (
watch(
w,
() => {
(M++,
(D.value = !1),
(k.value = !1),
(O.value = ``),
(A.value = null));
},
{
flush: `sync`,
},
),
onBeforeUnmount(() => {
((N = !0), M++);
}),
(t, n) => {
let r = message,
i = button,
o = dialog,
h = PaymentDialog;
return (
openBlock(),
createElementBlock(
Fragment,
null,
[
createVNode(
o,
{
visible: !!w.value && !unref(k),
header: `购买系统镜像`,
modal: ``,
closable: !unref(D),
"close-on-escape": !unref(D),
style: {
width: `480px`,
},
"onUpdate:visible": (n[1] ||= (e) => {
!e && !unref(D) && (w.value = null);
}),
},
{
footer: withCtx(() => [
createVNode(
i,
{
label: `取消`,
outlined: ``,
severity: `secondary`,
disabled: unref(D),
onClick: (n[0] ||= (e) => (w.value = null)),
},
null,
8,
[`disabled`],
),
createVNode(
i,
{
label: `确认购买 / 继续支付`,
loading: unref(D),
onClick: I,
},
null,
8,
[`loading`],
),
]),
default: withCtx(() => [
createElementVNode(`p`, null, [
createTextVNode(
`实例 #` +
toDisplayString(w.value?.hostId) +
` 所选镜像需要购买,费用为 `,
1,
),
createElementVNode(
`strong`,
null,
`¥` + toDisplayString(w.value?.price),
1,
),
(n[3] ||= createTextVNode(`。`, -1)),
]),
w.value?.description
? (openBlock(),
createElementBlock(
`p`,
C,
toDisplayString(w.value.description),
1,
))
: createCommentVNode(``, !0),
(n[4] ||= createElementVNode(
`p`,
null,
`支付并确认授权后,请再次确认重装。支付不会自动清除服务器数据。`,
-1,
)),
unref(O)
? (openBlock(),
createBlock(
r,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(O)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`, `closable`, `close-on-escape`],
),
createVNode(
h,
{
modelValue: unref(k),
"onUpdate:modelValue": (n[2] ||= (e) =>
isRef(k) ? (k.value = e) : null),
"order-id": unref(A),
amount: w.value?.price ?? ``,
onSuccess: L,
},
null,
8,
[`modelValue`, `order-id`, `amount`],
),
],
64,
)
);
}
);
},
}),
{
__name: `ImagePurchaseDialog`,
},
);
export {};
export default w;
</script>