Files

1400 lines
53 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
/**
* 购物车:读取服务端购物车、逐项重新报价、保留选择并结算。修改使用 revision 或 expected_cart 进行并发校验,不能把列表下标当作永久商品标识。
*/
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
import "~/assets/styles/cart.CSS2vTmS.css";
import { toDisplayString } from "vue";
import { renderList } from "vue";
import { onMounted } from "vue";
import { onBeforeUnmount } from "vue";
import { watch } from "vue";
import { createBlock } from "vue";
import { ref } from "vue";
import { withCtx } from "vue";
import { createCommentVNode } from "vue";
import { computed } 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 { useRouter } from "#app";
import { useApi } from "~/lib/auth.js";
import { useAuth } from "~/lib/auth.js";
import dialog from "primevue/dialog";
import button from "primevue/button";
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
import message from "primevue/message";
import inputtext from "primevue/inputtext";
import { n as product_name_n } from "~/lib/product-name.js";
import checkbox from "primevue/checkbox";
import ListEmpty from "~/components/ListEmpty.vue";
import PaymentDialog from "~/components/PaymentDialog.vue";
import skeleton from "primevue/skeleton";
import { t as os_name_t } from "~/lib/os-name.js";
import { r as configuration_display_r } from "~/lib/configuration-display.js";
import { t as configuration_display_t } from "~/lib/configuration-display.js";
import { t as purchase_limit_state_t } from "~/lib/purchase-limit-state.js";
import { a as cart_edit_a } from "~/lib/cart-edit.js";
import { i as cart_edit_i } from "~/lib/cart-edit.js";
import { t as cart_edit_t } from "~/lib/cart-edit.js";
// 只接受普通对象形状的数据,供配置摘要解析使用。
function E(e) {
return typeof e == `object` && e && !Array.isArray(e) ? e : void 0;
}
// 将可展示的配置值限制为文本;疑似 HTML 或编码标签不作为摘要内容。
function D(e) {
if (typeof e != `string` && (typeof e != `number` || !Number.isFinite(e)))
return ``;
let t = String(e).trim();
return /<\/?[a-z!]|&(?:amp;)*(?:lt|gt|quot|#0*60|#x0*3c);/i.test(t) ? `` : t;
}
// 仅在数值格式与单位明确时生成 CPU/内存/带宽等展示值。
function O(e, t) {
let n = D(e);
return n
? /^\d+(?:\.\d+)?$/.test(n)
? `${n} ${t}`
: RegExp(`^\\d+(?:\\.\\d+)?\\s*${t}$`, `i`).test(n)
? n
: ``
: ``;
}
var k = {
monthly: `月`,
quarterly: `季`,
semiannually: `半年`,
annually: `年`,
biennially: `两年`,
triennially: `三年`,
onetime: `一次性`,
free: `免费`,
hour: `小时`,
hourly: `小时`,
day: `天`,
daily: `天`,
};
// 将计费周期转换为可读名称,未识别的机器枚举不直接展示。
function A(e) {
let t = D(e);
return k[t.toLowerCase()] ?? (/^(?:[a-z_]+|\d+)$/i.test(t) ? `` : t);
}
// 归一化不同模块的配置标签,用于摘要去重和识别 CPU、内存、周期、镜像等字段。
function j(e, t = ``) {
return /^(?:cpu|cpu_num)$/i.test(t) ||
/^(?:cpu|CPU核数|处理器|核数)$/i.test(e)
? `cpu`
: t === `memory` || /^(?:内存|内存容量|memory)$/i.test(e)
? `memory`
: /^(?:时长|购买时长|周期|计费周期)$/.test(e) ||
/^(?:duration|billing_cycle)(?:_name)?$/.test(t)
? `duration`
: e === `套餐` || t === `package`
? `package`
: /^(?:镜像|系统|系统镜像|操作系统|系统版本|镜像版本)$/.test(e) ||
/^(?:image|image_name|os|os_name|version_name)$/.test(t)
? `os`
: e;
}
// 摘要排除密码、令牌、私钥及内部 ID 等字段;不能直接遍历配置对象展示所有内容。
function M(e, t = ``) {
return (
/(?:password|passwd|secret|token|private.?key|ssh.?key|credential|description|密码|口令|密钥|令牌|产品介绍|商品介绍|产品描述|商品描述)/i.test(
`${e} ${t}`,
) ||
/(?:^|[_\s])id$/i.test(t) ||
/(?:^|\s)id$/i.test(e)
);
}
// 当报价接口未提供 preview 时,从已知配置字段整理摘要。
function N(e, t) {
let n = [],
r = (e, t) => {
t &&
n.push({
label: e,
value: t,
});
};
(t || r(`区域`, D(e.region_name) || D(e.data_center_name)),
r(t ? `区域` : `线路`, D(e.line_name)),
t ? r(`线路`, D(e.network_name)) : r(`CPU 型号`, D(e.cpu_model_name)),
r(`CPU`, O(e.cpu_num, `核`) || O(e.cpu, `核`)),
r(`内存`, O(e.memory, `GB`)));
let i = (e) => {
let t = E(e);
if (!t) return ``;
let n = O(t.size, `GB`),
r = D(t.type ?? t.disk_type);
return n ? `${n}${r && !/^\d+$/.test(r) ? ` ${r}` : ``}` : ``;
};
return (
r(`系统盘`, i(e.system_disk)),
Array.isArray(e.data_disk) &&
e.data_disk.forEach((e, t) => r(`数据盘 ${t + 1}`, i(e))),
r(`网络类型`, t ? `经典网络` : D(e.network_type) || D(e.network_name)),
r(`带宽计费方式`, D(e.bill_method_name)),
r(`带宽`, O(e.bandwidth ?? e.bw, `Mbps`)),
r(`操作系统`, os_name_t(D(e.version_name))),
n
);
}
// 优先使用报价 preview,过滤敏感项并合并 CPU/内存/套餐等重复信息;缺失时才使用已知配置字段。
function pe(e, t) {
let n = E(e.config_options) ?? {},
r =
`package_config_id` in n &&
(`cpu_model_id` in n || `cpu_model_name` in n),
i = E(t),
a = [];
if (Array.isArray(i?.preview))
for (let e of i.preview) {
let t = E(e);
if (!t) continue;
let n = D(t.name),
i = r ? n : configuration_display_t(n, t.option_type),
o = D(t.value),
s = D(t.key);
if (!n || !i || !o || M(n, s)) continue;
let c = j(i, s);
(c === `os` && (o = os_name_t(o)),
!a.some((e) => e.kind === c && e.value === o) &&
a.push({
label: i,
value: o,
kind: c,
}));
}
if (r && a.length) {
let e = a.findIndex((e) => /^(?:机型|CPU\s*型号)$/i.test(e.label)),
t = a.findIndex((e) => /^(?:网络|网络类型)$/.test(e.label)),
n = !a.some((e) => e.label === `区域`);
for (let r = 0; r < a.length; r++) {
let i = a[r];
((i.label === `区域线路` || (n && i.label === `线路`)) &&
(i.label = `区域`),
r === e
? ((i.label = `网络类型`), (i.value = `经典网络`))
: r === t && e >= 0
? (i.label = `线路`)
: i.label === `网络类型` && (i.value = `经典网络`));
}
e >= 0 && t >= 0 && ([a[e], a[t]] = [a[t], a[e]]);
let r = a.findIndex((e) => e.label === `网络类型`),
i = a.findIndex((e) => e.label === `线路`);
r >= 0 && i > r && ([a[r], a[i]] = [a[i], a[r]]);
}
let o = a.length
? a.map(({ label: e, value: t }) => ({
label: e,
value: t,
}))
: N(n, r);
if (a.length) {
let e = [],
t = a
.find((e) => e.kind === `package`)
?.value.match(/^(\d+)\s*核\s*(\d+)\s*G(?:B)?$/i);
if (!a.some((e) => e.kind === `cpu`)) {
let r = O(t?.[1] ?? n.cpu_num, `核`) || O(n.cpu, `核`);
r &&
e.push({
label: `CPU`,
value: r,
});
}
if (!a.some((e) => e.kind === `memory`)) {
let r = O(t?.[2] ?? n.memory, `GB`);
r &&
e.push({
label: `内存`,
value: r,
});
}
o.unshift(...e);
let r =
o.some((e) => j(e.label) === `cpu`) || a.some((e) => e.kind === `cpu`),
i =
o.some((e) => j(e.label) === `memory`) ||
a.some((e) => e.kind === `memory`);
if (r && i)
for (let e = o.length - 1; e >= 0; e--) {
let t = o[e],
n = t.value.match(/^(\d+)\s*核\s*(\d+)\s*G(?:B)?$/i),
r = o.find((e) => j(e.label) === `cpu`)?.value.match(/^\d+/)?.[0],
i = o.find((e) => j(e.label) === `memory`)?.value.match(/^\d+/)?.[0];
j(t.label) === `package` &&
n &&
n[1] === r &&
n[2] === i &&
o.splice(e, 1);
}
}
if (!a.some((e) => e.kind === `duration`)) {
let e =
A(i?.billing_cycle_name) ||
A(i?.billing_cycle) ||
A(n.duration_name) ||
A(n.billing_cycle) ||
k[D(n.cycle).toLowerCase()];
e &&
o.push({
label: `购买时长`,
value: e,
});
}
return o.map((e) => ({
label: configuration_display_t(e.label),
value:
configuration_display_t(e.label) === `网络类型`
? configuration_display_r(e.value)
: e.value,
}));
}
var me = {
class: `page`,
},
he = {
class: `page-head`,
},
ge = {
key: 3,
class: `panel`,
},
_e = {
key: 4,
class: `cart-layout`,
},
ve = {
class: `panel cart-products`,
},
ye = {
class: `cart-head`,
},
be = {
class: `head-text`,
},
xe = {
class: `item-count`,
},
Se = [`disabled`],
Ce = [`disabled`],
we = {
class: `item-main`,
},
Te = {
class: `item-name`,
},
Ee = {
key: 0,
class: `item-configuration`,
},
De = {
key: 1,
class: `item-configuration-empty`,
},
Oe = {
class: `item-qty`,
},
ke = {
class: `qty-num`,
},
Ae = {
class: `item-price`,
"aria-live": `polite`,
},
je = {
key: 0,
class: `quote-status`,
},
Me = {
class: `quote-error`,
},
Ne = {
class: `panel cart-foot`,
"aria-label": `订单确认`,
},
Pe = {
class: `summary-line`,
},
Fe = {
class: `foot-promo`,
},
Ie = {
key: 0,
class: `promo-count`,
},
Le = {
class: `foot-total`,
},
Re = {
class: `total`,
},
ze = {
class: `checkout-note`,
},
Be = {
key: 5,
class: `panel empty-panel`,
},
Ve = {
key: 6,
class: `panel empty-panel`,
},
P = _plugin_vue_export_helper_t(
defineComponent({
__name: `index`,
setup(h) {
let x = useApi(),
C = purchase_limit_state_t((e) =>
x.post(`/purchase_limit/check`, e, !1, {
timeoutMs: 15e3,
}),
),
w = ref(!1),
T,
E = useRouter(),
D = ref([]),
O = ref(``),
k = ref(!0),
A = ref([]),
j = ref(!1),
M = ref(``),
N = ref(!1),
P = ref(!1),
F = ref(null),
He = ref(``),
I = ref(``),
L = computed(() => [
...new Set(I.value.split(/[\s,]+/).filter(Boolean)),
]),
Ue = computed(
() => D.value.length > 0 && A.value.length === D.value.length,
),
R = ref({}),
z = ref({}),
B = computed(() => D.value.map((e, t) => pe(e, z.value[t]))),
V = ref({}),
H = ref({});
computed(() => Object.values(H.value).some(Boolean));
let U = 0,
W = 0,
G = !1,
K = new Map(),
q = () => JSON.stringify(D.value),
J = () =>
O.value
? {
expected_revision: O.value,
}
: {
expected_cart: cart_edit_t(D.value),
},
Y = (e) =>
JSON.stringify([
e.product_id,
e.config_options,
e.customfield,
e.self_defined_field,
]);
// 按商品配置签名及同签名出现次数记录选择,列表重排时不误选另一件同款商品。
function We() {
let e = new Map();
return D.value
.map((t, n) => {
let r = Y(t),
i = e.get(r) ?? 0;
return (e.set(r, i + 1), A.value.includes(n) ? `${r}:${i}` : ``);
})
.filter(Boolean);
}
// 根据重新加载后的列表重建选择下标,避免沿用过期的位置。
function Ge(e) {
let t = new Map();
A.value = D.value.flatMap((n, r) => {
let i = Y(n),
a = t.get(i) ?? 0;
return (t.set(i, a + 1), e.includes(`${i}:${a}`) ? [r] : []);
});
}
// 金额必须是非空且有限的非负数字;未返回报价不能当作零元。
function Ke(e) {
return (
e != null &&
String(e).trim() !== `` &&
Number.isFinite(Number(e)) &&
Number(e) >= 0
);
}
// 逐项请求最新报价;同时核对购物车代次、列表快照和单项请求序号,旧响应不覆盖新配置。
async function qe(e = D.value.map((e, t) => t)) {
let t = U,
n = q();
await Promise.all(
e.map(async (e) => {
let r = D.value[e];
if (!r) return;
let i = (K.get(e) ?? 0) + 1;
K.set(e, i);
let a = () => !G && t === U && n === q() && K.get(e) === i;
((H.value[e] = !0), delete R.value[e], delete V.value[e]);
try {
let t = await x.post(`/product/${r.product_id}/config_option`, {
id: r.product_id,
config_options: {
...(r.config_options ?? {}),
promo_code: ``,
event_promotion: ``,
},
qty: r.qty ?? 1,
});
if (!a()) return;
let n = t?.price_total ?? t?.price;
if (!Ke(n)) throw Error(`未获得有效报价`);
((R.value[e] = String(n)),
(z.value[e] = {
preview: t.preview,
billing_cycle_name: t.billing_cycle_name,
billing_cycle: t.billing_cycle,
}));
} catch (t) {
a() &&
(delete z.value[e],
(V.value[e] =
t instanceof Error ? t.message : `报价加载失败`));
} finally {
a() && (H.value[e] = !1);
}
}),
);
}
function Je(e) {
return R.value[e] ?? ``;
}
let X = computed(() => {
let e = 0;
for (let t of A.value) {
if (!D.value[t] || H.value[t] || !Ke(R.value[t])) return null;
e += Number(R.value[t]);
}
return e.toFixed(2);
}),
Ye = computed(() =>
A.value.reduce((e, t) => e + (D.value[t]?.qty ?? 1), 0),
),
Xe = computed(
() =>
!k.value &&
!j.value &&
!P.value &&
A.value.length > 0 &&
X.value !== null &&
(!w.value || (C.checked.value && C.allowed.value)),
);
// 结算限购预检针对当前选择的位置;没有选择或仍在加载时清除旧预检。
function Ze() {
if (!w.value || k.value || !A.value.length) {
C.reset();
return;
}
return C.check({
mode: `cart_settle`,
positions: [...A.value],
});
}
// 刷新购物车时先废弃旧报价,再按配置签名恢复摘要与选择,最后重新报价。
async function Z(e = !1) {
let t = ++W,
n = e ? We() : [],
r = new Map(D.value.map((e, t) => [Y(e), z.value[t]]));
((U += 1),
(H.value = {}),
(R.value = {}),
(V.value = {}),
(k.value = !0),
(N.value = !1),
(M.value = ``));
try {
let i = await x.get(`/cart`);
if (G || t !== W) return;
if (
((D.value = i.list ?? []),
(O.value =
typeof i.revision == `string` &&
/^[a-f0-9]{64}$/.test(i.revision)
? i.revision
: ``),
(z.value = Object.fromEntries(
D.value.flatMap((e, t) => {
let n = r.get(Y(e));
return n ? [[t, n]] : [];
}),
)),
e)
)
Ge(n);
else {
let e = await cart_edit_a(D.value);
if (G || t !== W) return;
A.value = e ?? D.value.map((e, t) => t);
}
} catch (e) {
if (G || t !== W) return;
((N.value = !0),
(D.value = []),
(O.value = ``),
(A.value = []),
(M.value = e instanceof Error ? e.message : `购物车加载失败`));
} finally {
!G && t === W && (k.value = !1);
}
!G && t === W && !N.value && (await qe());
}
function Qe() {
j.value || (A.value = Ue.value ? [] : D.value.map((e, t) => t));
}
function $e(e) {
if (j.value) return;
let t = A.value.indexOf(e);
t === -1 ? A.value.push(e) : A.value.splice(t, 1);
}
// 遇到 409 并发冲突时重载购物车并清空选择,要求用户重新确认,避免误改已移动的下标。
async function Q(e, t) {
let n = e instanceof Error ? e.message : t;
e && typeof e == `object` && `status` in e && e.status === 409
? (($.value = null),
(A.value = []),
await Z(),
(A.value = []),
(M.value = N.value ? `${n};${M.value}` : n))
: (M.value = n);
}
// 先保存购物车编辑上下文,再进入对应商品页;商品页会再次确认该位置仍匹配商品。
async function et(e) {
if (!j.value && D.value[e]) {
j.value = !0;
try {
(await cart_edit_i(D.value, A.value),
await E.push({
path: `/products/${D.value[e].product_id}`,
query: {
edit_position: String(e),
},
}));
} catch (e) {
M.value = e instanceof Error ? e.message : `打开配置失败,请重试`;
} finally {
j.value = !1;
}
}
}
// 修改数量必须为正整数,并携带当前购物车并发校验信息。
async function tt(e, t) {
if (!(j.value || !Number.isInteger(t) || t < 1 || !D.value[e])) {
((j.value = !0), (M.value = ``));
try {
(await x.put(`/cart/${e}/qty`, {
qty: t,
...J(),
}),
await Z(!0));
} catch (e) {
await Q(e, `修改数量失败`);
} finally {
j.value = !1;
}
}
}
let $ = ref(null);
// 确认删除前记录位置与整个购物车签名,等待确认期间列表变化则不得继续使用旧位置。
function nt(e) {
let t = D.value[e];
!j.value &&
t &&
($.value = {
kind: `item`,
positions: [e],
signature: q(),
label: `删除“${product_name_n(t.name)}”`,
});
}
// 清空操作记录当时的全部位置与签名,最终仍由统一确认函数校验。
function rt() {
!j.value &&
D.value.length &&
($.value = {
kind: `all`,
positions: D.value.map((e, t) => t),
signature: q(),
label: `清空购物车`,
});
}
// 批量删除仅暂存当前选中位置,不立即发送删除请求。
function it() {
!j.value &&
A.value.length &&
($.value = {
kind: `selected`,
positions: [...A.value],
signature: q(),
label: `删除选中的 ${A.value.length} 项商品`,
});
}
// 确认时再核对购物车签名;单项、批量、清空分别调用对应接口并携带并发校验。
async function at() {
let e = $.value;
if (e && !j.value) {
if (e.signature !== q()) {
(($.value = null),
(M.value = `购物车已变化,请重新选择要删除的商品`));
return;
}
((j.value = !0), (M.value = ``));
try {
(e.kind === `all`
? await x.del(`/cart`, void 0, J())
: e.kind === `item`
? await x.del(`/cart/${e.positions[0]}`, void 0, J())
: await x.del(`/cart/batch`, void 0, {
positions: e.positions,
...J(),
}),
($.value = null),
(A.value = []),
await Z(!0));
} catch (e) {
await Q(e, `删除失败`);
} finally {
j.value = !1;
}
}
}
// 结算要求选择项报价均已确认;服务端返回订单后打开支付并刷新购物车。
async function ot() {
if (!(j.value || P.value)) {
if (((M.value = ``), !A.value.length)) {
M.value = `请选择要结算的商品`;
return;
}
if (k.value || X.value === null) {
M.value = `所选商品报价尚未确认,请等待或重试报价`;
return;
}
j.value = !0;
try {
let e = await x.post(`/cart/settle`, {
positions: [...A.value],
...J(),
...(L.value.length
? {
customfield: {
promo_code: L.value,
},
}
: {}),
});
((F.value = e.order_id),
(He.value = e.amount),
(P.value = !0),
(A.value = []),
await Z(!0));
} catch (e) {
await Q(e, `结算失败`);
} finally {
j.value = !1;
}
}
}
// 支付完成后进入订单列表,订单与支付状态仍以服务端为准。
function st() {
E.push(`/orders`);
}
return (
onBeforeUnmount(() => {
((G = !0), (U += 1), (W += 1), T?.(), C.reset());
}),
onMounted(() => {
let e = useAuth();
return (
(T = watch(
() => [
e.token,
e.isLoggedIn,
k.value,
q(),
JSON.stringify(A.value),
],
() => ((w.value = e.isLoggedIn), Ze()),
{
immediate: !0,
flush: `sync`,
},
)),
Z()
);
}),
// 渲染当前购物车行与逐项报价,合计不可用时禁用结算;删除确认和订单支付各自保留独立目标。
(n, r) => {
let i = button,
o = message,
l = skeleton,
h = checkbox,
v = inputtext,
y = ListEmpty,
b = dialog,
x = PaymentDialog;
return (
openBlock(),
createElementBlock(`div`, me, [
createElementVNode(`div`, he, [
(r[7] ||= createElementVNode(
`div`,
{
class: `page-heading`,
},
[
createElementVNode(`h2`, null, `购物车`),
createElementVNode(
`p`,
null,
`确认产品配置与数量,统一提交订单`,
),
],
-1,
)),
createVNode(i, {
label: `订购产品`,
icon: `pi pi-plus`,
severity: `secondary`,
outlined: ``,
onClick: (r[0] ||= (e) => unref(E).push(`/products`)),
}),
]),
unref(M)
? (openBlock(),
createBlock(
o,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(M)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(C).message.value
? (openBlock(),
createBlock(
o,
{
key: 1,
severity: `warn`,
closable: !1,
role: `alert`,
},
{
default: withCtx(() => [
createTextVNode(
toDisplayString(unref(C).message.value),
1,
),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(C).message.value
? (openBlock(),
createBlock(
i,
{
key: 2,
label: `重新检查购买限制`,
icon: `pi pi-refresh`,
severity: `secondary`,
size: `small`,
outlined: ``,
disabled:
unref(k) || unref(j) || unref(C).pending.value,
onClick: Ze,
},
null,
8,
[`disabled`],
))
: createCommentVNode(``, !0),
unref(k) && !unref(D).length
? (openBlock(),
createElementBlock(`div`, ge, [
createVNode(l, {
height: `180px`,
}),
]))
: unref(D).length
? (openBlock(),
createElementBlock(`div`, _e, [
createElementVNode(`section`, ve, [
createElementVNode(`div`, ye, [
createVNode(
h,
{
modelValue: unref(Ue),
binary: ``,
"aria-label": `选择全部商品`,
disabled: unref(j),
"onUpdate:modelValue": Qe,
},
null,
8,
[`modelValue`, `disabled`],
),
createElementVNode(`span`, be, [
(r[8] ||= createTextVNode(`全选 `, -1)),
createElementVNode(
`span`,
xe,
`共 ` +
toDisplayString(unref(D).length) +
` 项商品`,
1,
),
]),
unref(A).length
? (openBlock(),
createElementBlock(
`button`,
{
key: 0,
type: `button`,
class: `clear-btn`,
disabled: unref(j),
onClick: it,
},
` 删除选中(` +
toDisplayString(unref(A).length) +
`) `,
9,
Se,
))
: createCommentVNode(``, !0),
createElementVNode(
`button`,
{
type: `button`,
class: `clear-btn`,
disabled: unref(j),
onClick: rt,
},
`清空购物车`,
8,
Ce,
),
]),
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
unref(D),
(n, a) => (
openBlock(),
createElementBlock(
`div`,
{
key: a,
class: `cart-item`,
},
[
createVNode(
h,
{
modelValue: unref(A).includes(a),
"aria-label": `选择 ${unref(product_name_n)(n.name)}`,
disabled: unref(j),
binary: ``,
"onUpdate:modelValue": (e) => $e(a),
},
null,
8,
[
`modelValue`,
`aria-label`,
`disabled`,
`onUpdate:modelValue`,
],
),
createElementVNode(`div`, we, [
createElementVNode(
`div`,
Te,
toDisplayString(
unref(product_name_n)(n.name),
),
1,
),
unref(B)[a]?.length
? (openBlock(),
createElementBlock(`dl`, Ee, [
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
unref(B)[a],
(t, n) => (
openBlock(),
createElementBlock(
`div`,
{
key: `${t.label}-${n}`,
class: `item-configuration-row`,
},
[
createElementVNode(
`dt`,
null,
toDisplayString(
t.label,
),
1,
),
createElementVNode(
`dd`,
null,
toDisplayString(
t.value,
),
1,
),
],
)
),
),
128,
)),
]))
: (openBlock(),
createElementBlock(
`p`,
De,
toDisplayString(
unref(H)[a]
? `正在加载所选配置…`
: `暂无配置明细`,
),
1,
)),
]),
createElementVNode(`div`, Oe, [
createVNode(
i,
{
icon: `pi pi-minus`,
"aria-label": `减少 ${unref(product_name_n)(n.name)} 的数量`,
size: `small`,
severity: `secondary`,
outlined: ``,
disabled:
unref(j) || (n.qty || 1) <= 1,
onClick: (e) =>
tt(a, (n.qty || 1) - 1),
},
null,
8,
[`aria-label`, `disabled`, `onClick`],
),
createElementVNode(
`span`,
ke,
toDisplayString(n.qty || 1),
1,
),
createVNode(
i,
{
icon: `pi pi-plus`,
"aria-label": `增加 ${unref(product_name_n)(n.name)} 的数量`,
size: `small`,
severity: `secondary`,
outlined: ``,
disabled: unref(j),
onClick: (e) =>
tt(a, (n.qty || 1) + 1),
},
null,
8,
[`aria-label`, `disabled`, `onClick`],
),
]),
createElementVNode(`div`, Ae, [
unref(H)[a]
? (openBlock(),
createElementBlock(
`span`,
je,
`正在报价…`,
))
: unref(V)[a]
? (openBlock(),
createElementBlock(
Fragment,
{
key: 1,
},
[
(r[9] ||= createElementVNode(
`span`,
{
class: `quote-status`,
},
`报价失败`,
-1,
)),
createVNode(
i,
{
label: `重试报价`,
size: `small`,
text: ``,
"aria-label": `重新获取 ${unref(product_name_n)(n.name)} 的报价`,
disabled: unref(j),
onClick: (e) => qe([a]),
},
null,
8,
[
`aria-label`,
`disabled`,
`onClick`,
],
),
createElementVNode(
`small`,
Me,
toDisplayString(unref(V)[a]),
1,
),
],
64,
))
: (openBlock(),
createElementBlock(
Fragment,
{
key: 2,
},
[
(r[10] ||= createElementVNode(
`small`,
{
class: `quote-status`,
},
`小计`,
-1,
)),
createTextVNode(
` ¥` +
toDisplayString(
Je(a) || `—`,
),
1,
),
],
64,
)),
]),
createVNode(
i,
{
label: `编辑配置`,
icon: `pi pi-pencil`,
size: `small`,
severity: `secondary`,
text: ``,
disabled: unref(j),
onClick: (e) => et(a),
},
null,
8,
[`disabled`, `onClick`],
),
createVNode(
i,
{
icon: `pi pi-trash`,
"aria-label": `删除 ${unref(product_name_n)(n.name)}`,
size: `small`,
severity: `danger`,
text: ``,
disabled: unref(j),
onClick: (e) => nt(a),
},
null,
8,
[`aria-label`, `disabled`, `onClick`],
),
],
)
),
),
128,
)),
]),
createElementVNode(`aside`, Ne, [
(r[14] ||= createElementVNode(
`h3`,
null,
`订单确认`,
-1,
)),
createElementVNode(`div`, Pe, [
(r[11] ||= createElementVNode(
`span`,
null,
`已选商品`,
-1,
)),
createElementVNode(
`span`,
null,
toDisplayString(unref(A).length) +
` 项 / ` +
toDisplayString(unref(Ye)) +
` 件`,
1,
),
]),
createElementVNode(`div`, Fe, [
(r[12] ||= createElementVNode(
`label`,
{
for: `cart-promo`,
},
`优惠码`,
-1,
)),
createVNode(
v,
{
id: `cart-promo`,
modelValue: unref(I),
"onUpdate:modelValue": (r[1] ||= (e) =>
isRef(I) ? (I.value = e) : null),
placeholder: `选填,多个用空格或逗号分隔`,
disabled: unref(j),
class: `promo-input`,
},
null,
8,
[`modelValue`, `disabled`],
),
unref(L).length
? (openBlock(),
createElementBlock(
`span`,
Ie,
toDisplayString(unref(L).length) +
` 个待使用`,
1,
))
: createCommentVNode(``, !0),
]),
createElementVNode(`div`, Le, [
(r[13] ||= createElementVNode(
`span`,
null,
`合计费用`,
-1,
)),
createElementVNode(
`span`,
Re,
toDisplayString(
unref(X) === null ? `待确认` : `¥${unref(X)}`,
),
1,
),
]),
createElementVNode(
`p`,
ze,
toDisplayString(
unref(A).length
? unref(X) === null
? `所选商品的报价尚未确认,请等待报价或重试。`
: `优惠码折扣以订单确认后的应付金额为准。`
: `选择商品后即可提交订单。`,
),
1,
),
createVNode(
i,
{
label: `提交订单`,
loading: unref(j),
disabled: !unref(Xe),
onClick: ot,
},
null,
8,
[`loading`, `disabled`],
),
]),
]))
: unref(N)
? (openBlock(),
createElementBlock(`div`, Be, [
createVNode(
y,
{
icon: `pi pi-exclamation-circle`,
title: `暂时无法加载购物车`,
description: `请重新加载,已有商品会继续保留。`,
},
{
default: withCtx(() => [
createVNode(i, {
label: `重新加载`,
icon: `pi pi-refresh`,
severity: `secondary`,
outlined: ``,
onClick: (r[2] ||= (e) => Z()),
}),
]),
_: 1,
},
),
]))
: (openBlock(),
createElementBlock(`div`, Ve, [
createVNode(
y,
{
icon: `pi pi-shopping-cart`,
title: `购物车是空的`,
description: `选好产品并加入购物车后,可在这里统一结算。`,
},
{
default: withCtx(() => [
createVNode(i, {
label: `订购产品`,
icon: `pi pi-plus`,
onClick: (r[3] ||= (e) =>
unref(E).push(`/products`)),
}),
]),
_: 1,
},
),
])),
createVNode(
b,
{
visible: !!unref($),
header: unref($)?.label,
modal: ``,
draggable: !1,
closable: !unref(j),
closeOnEscape: !unref(j),
style: {
width: `440px`,
},
"onUpdate:visible": (r[5] ||= (e) =>
!unref(j) && ($.value = null)),
},
{
footer: withCtx(() => [
createVNode(
i,
{
label: `取消`,
severity: `secondary`,
text: ``,
disabled: unref(j),
onClick: (r[4] ||= (e) => ($.value = null)),
},
null,
8,
[`disabled`],
),
createVNode(
i,
{
label: `确认删除`,
severity: `danger`,
loading: unref(j),
onClick: at,
},
null,
8,
[`loading`],
),
]),
default: withCtx(() => [
createElementVNode(
`p`,
null,
`将移除 ` +
toDisplayString(unref($)?.positions.length) +
` 项商品,需要时可重新选购。`,
1,
),
unref(M)
? (openBlock(),
createBlock(
o,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(M)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`, `header`, `closable`, `closeOnEscape`],
),
createVNode(
x,
{
modelValue: unref(P),
"onUpdate:modelValue": (r[6] ||= (e) =>
isRef(P) ? (P.value = e) : null),
"order-id": unref(F),
amount: unref(He),
onSuccess: st,
},
null,
8,
[`modelValue`, `order-id`, `amount`],
),
])
);
}
);
},
}),
[[`__scopeId`, `data-v-11d8a39a`]],
);
export {};
export default P;
</script>