Files
console-dev/app/pages/vouchers/index.vue
T

1046 lines
50 KiB
Vue

<script>
/**
* 代金券:领券中心与我的券分别分页、缓存加载状态及错误;当前时间用于有效期展示,领取后刷新两侧列表,最终订单可用性由后端确认。
*/
import "~/assets/styles/vouchers.5FV4ozrh.css";
import { toDisplayString } from "vue";
import { renderList } from "vue";
import { onMounted } from "vue";
import { normalizeClass } from "vue";
import { onBeforeUnmount } from "vue";
import { createStaticVNode } from "vue";
import { createBlock } from "vue";
import { ref } from "vue";
import { withCtx } from "vue";
import { createCommentVNode } from "vue";
import { computed } 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 { navigateTo } from "#app";
import { useApi } from "~/lib/auth.js";
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 { n as product_name_n } from "~/lib/product-name.js";
import { r as dict_r } from "~/lib/dict.js";
import paginator from "primevue/paginator";
import ListEmpty from "~/components/ListEmpty.vue";
import { t as interval_t } from "~/lib/interval.js";
import tag from "primevue/tag";
import skeleton from "primevue/skeleton";
import tabs from "primevue/tabs";
import tabpanels from "primevue/tabpanels";
import tabpanel from "primevue/tabpanel";
import tablist from "primevue/tablist";
import tab from "primevue/tab";
var he = {
class: `voucher-page`,
},
ge = {
class: `page-head`,
},
_e = {
key: 0,
class: `tab-count`,
},
ve = {
key: 0,
class: `tab-count`,
},
ye = {
class: `voucher-toolbar`,
},
be = {
key: 0,
class: `voucher-grid`,
"aria-label": `正在加载代金券`,
"aria-busy": `true`,
},
xe = {
key: 1,
class: `voucher-state`,
},
Se = {
key: 2,
class: `voucher-state`,
},
Ce = {
key: 3,
class: `voucher-grid`,
},
we = [`aria-label`],
Te = {
class: `voucher-face`,
},
Ee = {
class: `face-value`,
},
De = {
class: `face-threshold`,
},
Oe = {
class: `voucher-details`,
},
ke = {
class: `voucher-title`,
},
Ae = {
class: `voucher-code`,
},
je = {
class: `voucher-rules`,
},
Me = {
class: `voucher-uses`,
"aria-label": `订单类型限制`,
},
Ne = {
class: `voucher-footer`,
},
Pe = {
key: 1,
class: `use-tip`,
},
Fe = {
key: 2,
class: `use-tip`,
},
Ie = {
key: 4,
class: `voucher-pagination`,
},
x = _plugin_vue_export_helper_t(
defineComponent({
__name: `index`,
setup(h) {
let v = useApi(),
x = ref(`mine`),
S = ref([]),
C = ref(0),
w = ref(1),
T = ref(12),
E = ref(!1),
D = ref(``),
O = ref(!1),
Le = ref([]),
k = ref(0),
A = ref(1),
j = ref(12),
M = ref(!1),
N = ref(``),
P = ref(!1),
F = ref(0),
I = ref(``),
L = ref(``),
R = ref([]),
z = ref(Math.floor(Date.now() / 1e3)),
B = 0,
V = 0,
H = !1,
U,
Re = computed(() => (x.value === `mine` ? Le.value : S.value)),
W = computed(() => (x.value === `mine` ? k.value : C.value)),
G = computed(() => (x.value === `mine` ? M.value : E.value)),
K = computed(() => (x.value === `mine` ? N.value : D.value)),
ze = computed(() => (x.value === `mine` ? A.value : w.value)),
Be = computed(() => (x.value === `mine` ? j.value : T.value));
// 加载领券中心当前页,用已领取 ID 集合补齐界面标记;旧响应或离页结果不写回。
async function q() {
let e = ++B;
((E.value = !0), (D.value = ``));
try {
let t = await v.get(`/voucher`, {
page: w.value,
limit: T.value,
});
if (H || e !== B) return;
((S.value = (t.list ?? []).map((e) =>
R.value.includes(e.id)
? {
...e,
is_get: !0,
}
: e,
)),
(C.value = t.count ?? 0),
(O.value = !0));
} catch (t) {
if (H || e !== B) return;
D.value =
t instanceof Error ? t.message : `领券中心加载失败,请重试`;
} finally {
!H && e === B && (E.value = !1);
}
}
// 我的代金券使用独立请求序号,不能被领券中心响应覆盖。
async function J() {
let e = ++V;
((M.value = !0), (N.value = ``));
try {
let t = await v.get(`/voucher/mine`, {
page: A.value,
limit: j.value,
});
if (H || e !== V) return;
((Le.value = t.list ?? []),
(k.value = t.count ?? 0),
(P.value = !0));
} catch (t) {
if (H || e !== V) return;
N.value =
t instanceof Error ? t.message : `我的代金券加载失败,请重试`;
} finally {
!H && e === V && (M.value = !1);
}
}
// 归一化布尔/数字/字符串的开关标记。
function Y(e) {
return e === !0 || e === 1 || e === `1`;
}
// 领取状态同时参考服务端标记与本页成功领取记录,避免刷新间隙允许重复领取。
function X(e) {
return Y(e.is_get) || R.value.includes(e.id);
}
// 显式 expired 状态或已到结束时间都视为过期。
function Z(e) {
return (
e.status === `expired` ||
(Number(e.end_time) > 0 && Number(e.end_time) <= z.value)
);
}
// 判断是否尚未到使用开始时间,不与领取资格混为一谈。
function Ve(e) {
return Number(e.start_time) > z.value;
}
// 领取入口只排除已领取和过期;是否满足额外业务资格仍由服务端决定。
function Q(e) {
return !X(e) && !Z(e);
}
// 展示状态区分领券中心与我的券,已使用/过期/未开始各有独立文案。
function $(e) {
return x.value === `available`
? X(e)
? {
label: `已领取`,
severity: `secondary`,
}
: Z(e)
? {
label: `已过期`,
severity: `secondary`,
}
: {
label: `可领取`,
severity: `success`,
}
: e.status === `used`
? {
label: `已使用`,
severity: `secondary`,
}
: Z(e)
? {
label: `已过期`,
severity: `secondary`,
}
: Ve(e)
? {
label: `未到使用时间`,
severity: `warn`,
}
: e.status === `normal`
? {
label: `可使用`,
severity: `success`,
}
: {
label: e.status || `状态待确认`,
severity: `secondary`,
};
}
// 本页只在 normal 状态且处于有效期内展示可使用入口,订单仍需重新校验券资格。
function He(e) {
return e.status === `normal` && !Z(e) && !Ve(e);
}
// 金额只有在非空、有限且非负时才格式化,无效值显示占位而不是零元。
function Ue(e) {
let t = Number(e);
return e != null &&
String(e).trim() !== `` &&
Number.isFinite(t) &&
t >= 0
? t.toLocaleString(`zh-CN`, {
maximumFractionDigits: 2,
})
: `—`;
}
// 缺失使用门槛时明确以订单为准,不把未知条件显示成无门槛。
function We(e) {
let t = Number(e.min_price);
return !Number.isFinite(t) ||
e.min_price === null ||
e.min_price === void 0 ||
String(e.min_price).trim() === ``
? `使用门槛以订单为准`
: t > 0
? `满 ¥${Ue(t)} 可用`
: `无金额门槛`;
}
// 根据存在的起止时间组成有效期文字,零值表示没有该边界。
function Ge(e) {
let t = Number(e.start_time) > 0 ? dict_r(e.start_time) : ``,
n = Number(e.end_time) > 0 ? dict_r(e.end_time) : ``;
return t && n
? `${t} 至 ${n}`
: n
? `有效期至 ${n}`
: t
? `${t} 起,长期有效`
: `长期有效`;
}
// 能解析产品名称时逐一显示,否则只展示限制数量,不把内部商品 ID 当商品名。
function Ke(e) {
if (!e.product?.length) return `全场产品通用`;
let t = e.product.flatMap((e) =>
typeof e == `object` && e
? product_name_n(e.name || e.product_name) || []
: typeof e == `string` && !/^\d+$/.test(e)
? product_name_n(e)
: [],
);
return t.length === e.product.length
? t.join(`、`)
: `限指定 ${e.product.length} 款产品,以付款时可用代金券为准`;
}
// 列出新购、续费和升降级的允许标记,保留既有新购缺省允许契约。
function qe(e) {
return [
{
label: `新购`,
allowed: e.new_use === void 0 || Y(e.new_use),
},
{
label: `续费`,
allowed: Y(e.renew_use),
},
{
label: `升降级`,
allowed: Y(e.upgrade_use),
},
];
}
// 领取成功先记录本地防重标记,再从第一页刷新我的券与领券中心;不在本页自动抵扣订单。
async function Je(e) {
if (!(H || F.value || !Q(e))) {
((F.value = e.id), (I.value = ``), (L.value = ``));
try {
if (
(await v.post(`/voucher/${e.id}/get`, {
id: e.id,
}),
H)
)
return;
((R.value = [...new Set([...R.value, e.id])]),
(e.is_get = !0),
(S.value = S.value.map((t) =>
t.id === e.id
? {
...t,
is_get: !0,
}
: t,
)),
(L.value = `领取成功。可在「我的代金券」中查看,并在订单付款时选择使用。`),
(A.value = 1),
await Promise.all([q(), J()]));
} catch (e) {
H ||
(I.value =
e instanceof Error ? e.message : `领取失败,请稍后重试`);
} finally {
H || (F.value = 0);
}
}
}
// 切换标签刷新当前时间,尚未加载过的列表才惰性加载,保留各自分页。
function Ye(e) {
((x.value = e === `available` ? `available` : `mine`),
(z.value = Math.floor(Date.now() / 1e3)),
x.value === `mine`
? !P.value && !M.value && J()
: !O.value && !E.value && q());
}
// 手动刷新当前标签列表前同步时间,避免沿用旧的有效期展示。
function Xe() {
return (
(z.value = Math.floor(Date.now() / 1e3)),
x.value === `mine` ? J() : q()
);
}
// 分页事件只更新当前标签对应的页码和每页条数。
function Ze(e) {
x.value === `mine`
? ((A.value = e.page + 1), (j.value = e.rows), J())
: ((w.value = e.page + 1), (T.value = e.rows), q());
}
return (
onMounted(() => {
(J(),
(U = interval_t(() => {
z.value = Math.floor(Date.now() / 1e3);
}, 3e4)));
}),
onBeforeUnmount(() => {
((H = !0), (B += 1), (V += 1), U && clearInterval(U));
}),
// 根据当前标签选择列表、分页与错误,状态文案区分未开始/过期/已用,实际抵扣留待订单支付校验。
(n, i) => {
let o = button,
l = message,
h = tab,
ne = tablist,
v = skeleton,
y = ListEmpty,
b = tag,
se = paginator,
S = tabpanel,
w = tabpanels,
T = tabs;
return (
openBlock(),
createElementBlock(`div`, he, [
createElementVNode(`div`, ge, [
(i[3] ||= createElementVNode(
`div`,
{
class: `page-heading`,
},
[
createElementVNode(`h2`, null, `代金券`),
createElementVNode(
`p`,
null,
`管理已领取的代金券,发现新的产品优惠`,
),
],
-1,
)),
createVNode(o, {
label: `订购产品`,
icon: `pi pi-plus`,
severity: `secondary`,
outlined: ``,
onClick: (i[0] ||= (e) =>
(`navigateTo` in n ? n.navigateTo : unref(navigateTo))(
`/products`,
)),
}),
]),
(i[10] ||= createStaticVNode(
`<div class="voucher-guide" data-v-b08e3df0><span class="guide-icon" data-v-b08e3df0><i class="pi pi-ticket" aria-hidden="true" data-v-b08e3df0></i></span><div data-v-b08e3df0><h3 data-v-b08e3df0>在订单付款时抵扣费用</h3><p data-v-b08e3df0>领取代金券后,在订单付款页面选择符合条件的券即可抵扣。</p></div><span class="guide-note" data-v-b08e3df0><i class="pi pi-info-circle" aria-hidden="true" data-v-b08e3df0></i>金额门槛与产品范围以券面规则为准</span></div>`,
1,
)),
unref(L)
? (openBlock(),
createBlock(
l,
{
key: 0,
severity: `success`,
closable: !1,
"aria-live": `polite`,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(L)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(I)
? (openBlock(),
createBlock(
l,
{
key: 1,
severity: `error`,
closable: !1,
"aria-live": `assertive`,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(I)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
createVNode(
T,
{
class: `voucher-tabs`,
value: unref(x),
"onUpdate:value": Ye,
},
{
default: withCtx(() => [
createVNode(ne, null, {
default: withCtx(() => [
createVNode(
h,
{
value: `mine`,
},
{
default: withCtx(() => [
(i[4] ||= createTextVNode(`我的代金券 `, -1)),
unref(P)
? (openBlock(),
createElementBlock(
`span`,
_e,
toDisplayString(unref(k)),
1,
))
: createCommentVNode(``, !0),
]),
_: 1,
},
),
createVNode(
h,
{
value: `available`,
},
{
default: withCtx(() => [
(i[5] ||= createTextVNode(`领券中心 `, -1)),
unref(O)
? (openBlock(),
createElementBlock(
`span`,
ve,
toDisplayString(unref(C)),
1,
))
: createCommentVNode(``, !0),
]),
_: 1,
},
),
]),
_: 1,
}),
createVNode(w, null, {
default: withCtx(() => [
createVNode(
S,
{
value: unref(x),
},
{
default: withCtx(() => [
createElementVNode(`div`, ye, [
createElementVNode(
`p`,
null,
toDisplayString(
unref(x) === `mine`
? `已领取的代金券及其使用状态`
: `领取优惠,下次付款时使用`,
),
1,
),
createVNode(
o,
{
label: `刷新`,
icon: `pi pi-refresh`,
size: `small`,
severity: `secondary`,
text: ``,
loading: unref(G),
disabled: !!unref(F),
onClick: Xe,
},
null,
8,
[`loading`, `disabled`],
),
]),
unref(G) &&
!(unref(x) === `mine` ? unref(P) : unref(O))
? (openBlock(),
createElementBlock(`div`, be, [
(openBlock(),
createElementBlock(
Fragment,
null,
renderList(4, (e) =>
createElementVNode(
`div`,
{
key: e,
class: `voucher-skeleton`,
},
[
createVNode(v, {
width: `35%`,
height: `42px`,
}),
createVNode(v, {
height: `20px`,
}),
createVNode(v, {
height: `16px`,
width: `80%`,
}),
createVNode(v, {
height: `16px`,
width: `65%`,
}),
],
),
),
64,
)),
]))
: unref(K)
? (openBlock(),
createElementBlock(`div`, xe, [
createVNode(
y,
{
icon: `pi pi-exclamation-circle`,
title:
unref(x) === `mine`
? `暂时无法加载我的代金券`
: `领券中心暂时无法加载`,
description: unref(K),
},
{
default: withCtx(() => [
createVNode(o, {
label: `重新加载`,
icon: `pi pi-refresh`,
severity: `secondary`,
outlined: ``,
onClick: Xe,
}),
]),
_: 1,
},
8,
[`title`, `description`],
),
]))
: unref(Re).length
? (openBlock(),
createElementBlock(`div`, Ce, [
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
unref(Re),
(n) => (
openBlock(),
createElementBlock(
`article`,
{
key: `${unref(x)}-${n.id}`,
class: normalizeClass([
`voucher-card`,
{
inactive:
Z(n) ||
n.status === `used`,
},
]),
"aria-label": `面额 ${n.price} 元代金券 ${n.code || ``}`,
},
[
createElementVNode(
`div`,
Te,
[
(i[7] ||=
createElementVNode(
`span`,
{
class: `face-label`,
},
`代金券`,
-1,
)),
createElementVNode(
`div`,
Ee,
[
(i[6] ||=
createElementVNode(
`small`,
null,
`¥`,
-1,
)),
createElementVNode(
`strong`,
null,
toDisplayString(
Ue(n.price),
),
1,
),
],
),
createElementVNode(
`span`,
De,
toDisplayString(
We(n),
),
1,
),
],
),
createElementVNode(
`div`,
Oe,
[
createElementVNode(
`div`,
ke,
[
createElementVNode(
`span`,
Ae,
toDisplayString(
n.code ||
`产品代金券`,
),
1,
),
createVNode(
b,
{
value:
$(n).label,
severity:
$(n).severity,
},
null,
8,
[
`value`,
`severity`,
],
),
],
),
createElementVNode(
`dl`,
je,
[
createElementVNode(
`div`,
null,
[
(i[8] ||=
createElementVNode(
`dt`,
null,
`使用范围`,
-1,
)),
createElementVNode(
`dd`,
null,
toDisplayString(
Ke(n),
),
1,
),
],
),
createElementVNode(
`div`,
null,
[
(i[9] ||=
createElementVNode(
`dt`,
null,
`有效期限`,
-1,
)),
createElementVNode(
`dd`,
null,
toDisplayString(
Ge(n),
),
1,
),
],
),
],
),
createElementVNode(
`div`,
Me,
[
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
qe(n),
(t) => (
openBlock(),
createElementBlock(
`span`,
{
key: t.label,
class:
normalizeClass(
{
restricted:
!t.allowed,
},
),
},
[
createElementVNode(
`i`,
{
class:
normalizeClass(
t.allowed
? `pi pi-check`
: `pi pi-times`,
),
"aria-hidden": `true`,
},
null,
2,
),
createTextVNode(
toDisplayString(
t.label,
) +
toDisplayString(
t.allowed
? `可用`
: `不可用`,
),
1,
),
],
2,
)
),
),
128,
)),
],
),
createElementVNode(
`div`,
Ne,
[
createElementVNode(
`span`,
null,
toDisplayString(
Y(n.onetime)
? `一次性使用`
: `非一次性使用`,
),
1,
),
unref(x) ===
`available`
? (openBlock(),
createBlock(
o,
{
key: 0,
label: X(n)
? `已领取`
: Z(n)
? `已过期`
: `立即领取`,
size: `small`,
severity: Q(
n,
)
? void 0
: `secondary`,
disabled:
!Q(n) ||
(!!unref(
F,
) &&
unref(
F,
) !==
n.id),
loading:
unref(
F,
) ===
n.id,
onClick: (
e,
) => Je(n),
},
null,
8,
[
`label`,
`severity`,
`disabled`,
`loading`,
`onClick`,
],
))
: He(n)
? (openBlock(),
createElementBlock(
`span`,
Pe,
`付款时选择使用`,
))
: (openBlock(),
createElementBlock(
`span`,
Fe,
toDisplayString(
$(n)
.label,
),
1,
)),
],
),
],
),
],
10,
we,
)
),
),
128,
)),
]))
: (openBlock(),
createElementBlock(`div`, Se, [
createVNode(
y,
{
icon: `pi pi-ticket`,
title:
unref(x) === `mine`
? `还没有代金券`
: `暂无可领取的代金券`,
description:
unref(x) === `mine`
? `到领券中心看看,为下一次订购准备一份优惠。`
: `新的代金券会在这里展示,可以稍后再来看看。`,
},
{
default: withCtx(() => [
unref(x) === `mine`
? (openBlock(),
createBlock(o, {
key: 0,
label: `前往领券中心`,
icon: `pi pi-gift`,
onClick: (i[1] ||= (e) =>
Ye(`available`)),
}))
: (openBlock(),
createBlock(o, {
key: 1,
label: `查看我的代金券`,
severity: `secondary`,
outlined: ``,
onClick: (i[2] ||= (e) =>
Ye(`mine`)),
})),
]),
_: 1,
},
8,
[`title`, `description`],
),
])),
!unref(K) && unref(W) > 0
? (openBlock(),
createElementBlock(`div`, Ie, [
createElementVNode(
`span`,
null,
`共 ` +
toDisplayString(unref(W)) +
` 张代金券`,
1,
),
createVNode(
se,
{
rows: unref(Be),
totalRecords: unref(W),
first: (unref(ze) - 1) * unref(Be),
rowsPerPageOptions: [12, 24, 48],
disabled: unref(G),
onPage: Ze,
},
null,
8,
[
`rows`,
`totalRecords`,
`first`,
`disabled`,
],
),
]))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`value`],
),
]),
_: 1,
}),
]),
_: 1,
},
8,
[`value`],
),
])
);
}
);
},
}),
[[`__scopeId`, `data-v-b08e3df0`]],
);
export {};
export default x;
</script>