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

1162 lines
39 KiB
Vue

<script>
/**
* 订单列表:支持账单嵌入/路由模式、筛选、取消、导出与按需订单合并;选择集在筛选或账户变化时同步清空。
*/
import "~/assets/styles/orders.BflDlvVz.css";
import { toDisplayString } from "vue";
import { normalizeClass } 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 { createElementVNode } from "vue";
import { createTextVNode } from "vue";
import { unref } from "vue";
import { defineComponent } from "vue";
import { createVNode } from "vue";
import { openBlock } from "vue";
import { withKeys } from "vue";
import { useRoute } from "#app";
import { navigateTo } from "#app";
import { NuxtLink } from "#components";
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 { a as dict_a } from "~/lib/dict.js";
import { i as dict_i } from "~/lib/dict.js";
import { o as dict_o } from "~/lib/dict.js";
import { r as dict_r } from "~/lib/dict.js";
import { s as dict_s } from "~/lib/dict.js";
import datatable from "primevue/datatable";
import paginator from "primevue/paginator";
import iconfield from "primevue/iconfield";
import inputicon from "primevue/inputicon";
import select from "primevue/select";
import column from "primevue/column";
import ListSegments from "~/components/ListSegments.vue";
import ListEmpty from "~/components/ListEmpty.vue";
import { t as useListPage_t } from "~/lib/useListPage.js";
import tag from "primevue/tag";
var x = new Set([
`Unpaid`,
`Paid`,
`Refunded`,
`WaitUpload`,
`WaitReview`,
`ReviewFail`,
]);
// 状态筛选只接受已知枚举;all 显式转换为空筛选值。
function S(e, t = ``) {
return e === `all` ? `` : typeof e == `string` && x.has(e) ? e : t;
}
// 订单/账单地址只使用正的安全整数 ID,不把任意服务端字符串拼入路由。
function C(e, t = !1) {
if (typeof e != `string` && typeof e != `number`) return null;
let n = String(e);
return !/^[1-9]\d*$/.test(n) || !Number.isSafeInteger(Number(n))
? null
: `${t ? `/bills` : `/orders`}/${n}`;
}
var Se = {
class: `list-page`,
},
Ce = {
class: `list-head`,
},
we = {
key: 0,
class: `list-head-actions`,
},
Te = [`title`],
Ee = {
key: 0,
class: `bill-description`,
},
De = {
class: `list-toolbar`,
},
Oe = {
class: `list-toolbar-right`,
},
ke = {
class: `list-table`,
},
Ae = [`title`],
je = {
class: `amount`,
},
Me = {
key: 4,
class: `list-foot`,
},
w = _plugin_vue_export_helper_t(
defineComponent({
__name: `index`,
props: {
bills: {
type: Boolean,
},
},
setup(m) {
let y = useRoute(),
x = m,
w = computed(() => x.bills || y.path === `/bills`),
T = useApi(),
E = useAuth(),
Ne = [
{
label: `全部`,
value: ``,
},
{
label: `新订单`,
value: `new`,
},
{
label: `续费订单`,
value: `renew`,
},
{
label: `升降级订单`,
value: `upgrade`,
},
{
label: `人工订单`,
value: `artificial`,
},
{
label: `按需订单`,
value: `on_demand`,
},
],
Pe = [
{
label: `全部状态`,
value: ``,
},
{
label: `未付款`,
value: `Unpaid`,
},
{
label: `已付款`,
value: `Paid`,
},
{
label: `已退款`,
value: `Refunded`,
},
{
label: `待上传凭证`,
value: `WaitUpload`,
},
{
label: `待审核`,
value: `WaitReview`,
},
{
label: `审核未通过`,
value: `ReviewFail`,
},
],
D = ref(``),
O = ref(S(y.query.status)),
k = ref(``),
A = ref(``),
j = ref(`create_time`),
M = ref(`desc`),
N = ref([]),
P = ref(!1),
F = ref(!1),
I = ref(``),
L = ref(!1),
R = ref(!1),
z = ref(``),
B = ref([]),
V = !1;
onBeforeUnmount(() => {
V = !0;
});
let {
list: H,
total: U,
loading: W,
error: G,
page: K,
limit: q,
onPage: Fe,
reload: J,
} = useListPage_t(`/order`, {
limit: 20,
identity: () => E.token,
params: () => ({
type: D.value,
status: O.value,
keywords: A.value,
orderby: j.value,
sort: M.value,
}),
});
watch(
() => y.query.status,
(e) => {
let t = S(e);
t !== O.value && ((O.value = t), J());
},
);
// 根据当前账单模式生成详情链接,无效 ID 使用安全回落地址。
function Y(e) {
return C(e, w.value) || `/bills`;
}
let X = computed(() =>
N.value.filter(
(e) => String(e.status) === `Unpaid` && e.type !== `on_demand`,
),
),
Z = computed(() => N.value.length - X.value.length),
Q = (e) =>
e.type === `on_demand` &&
e.status === `Unpaid` &&
Number.isSafeInteger(Number(e.id)) &&
Number(e.id) > 0,
Ie = computed(
() =>
!W.value &&
!G.value &&
!R.value &&
!F.value &&
N.value.length >= 2 &&
N.value.every(
(e) =>
Q(e) &&
H.value.some((t) => Number(t.id) === Number(e.id) && Q(t)),
),
),
Le = computed(() =>
H.value.some(Q)
? `请选择至少两笔未付款按需订单`
: `当前列表没有可合并的未付款按需订单`,
);
(watch(
[D, O, A, j, M, K, q, () => E.token],
() => {
((N.value = []), R.value || (L.value = !1), (z.value = ``));
},
{
flush: `sync`,
},
),
watch(
() => E.token,
() => {
((L.value = !1), (B.value = []));
},
{
flush: `sync`,
},
));
// 合并前冻结当前选中的按需订单 ID,等待确认时不再依赖可变选择数组。
function Re() {
Ie.value &&
((B.value = [...new Set(N.value.map((e) => Number(e.id)))]),
(z.value = ``),
(L.value = !0));
}
// 逐单核实仍是未付款按需订单,且账户未切换才合并;返回结果不完整时提示刷新核实,避免重复合并。
async function ze() {
if (R.value || !L.value || B.value.length < 2 || V) return;
let e = E.token,
t = [...B.value],
n = () => !V && e === E.token;
((R.value = !0), (z.value = ``));
try {
for (let e of t) {
let t = await T.get(`/order/${e}`);
if (!n()) return;
if (Number(t?.order?.id) !== e || !Q(t.order))
throw Error(`订单 #${e} 状态已变化,请刷新列表后重新选择`);
}
let e = await T.post(`/order/on_demand/combine`, {
ids: t,
});
if (!n()) return;
if (
((N.value = []),
J(),
!Number.isSafeInteger(Number(e?.id)) ||
Number(e.id) <= 0 ||
![`string`, `number`].includes(typeof e?.amount) ||
String(e.amount).trim() === `` ||
!Number.isFinite(Number(e.amount)) ||
Number(e.amount) < 0)
)
throw (
(L.value = !1),
Error(`合并结果不完整,请刷新订单列表核对,避免重复合并`)
);
((L.value = !1), await navigateTo(Y(Number(e.id))));
} catch (e) {
n() &&
(z.value =
e instanceof Error ? e.message : `合并按需订单失败,请重试`);
} finally {
R.value = !1;
}
}
// 判断普通未付款状态;具体批量取消集合还会排除按需订单。
function Be(e) {
return String(e.status) === `Unpaid`;
}
// 只允许对已选可取消订单打开确认,无法取消的选择项单独计数提示。
function Ve() {
if (((I.value = ``), !X.value.length)) {
I.value = Z.value
? `已选订单中没有可取消的未付款订单`
: `请选择要取消的订单`;
return;
}
P.value = !0;
}
// 批量取消仅发送允许取消的 ID,成功后清空选择并刷新列表。
async function He() {
if (!F.value && X.value.length) {
((F.value = !0), (I.value = ``));
try {
(await T.del(`/order`, {
id: X.value.map((e) => e.id),
}),
(N.value = []),
(P.value = !1),
await J());
} catch (e) {
I.value = e instanceof Error ? e.message : `取消订单失败,请重试`;
} finally {
F.value = !1;
}
}
}
let Ue = ref(!1),
$ = ref(``);
// 按当前类型、状态和关键词导出服务端表格,下载超时与错误由公共 API 层处理。
async function We() {
((Ue.value = !0), ($.value = ``));
try {
await T.download(
`/order/export_excel`,
{
type: D.value,
status: O.value,
keywords: A.value,
},
`orders-${Date.now()}.xlsx`,
);
} catch (e) {
$.value = e instanceof Error ? e.message : `导出失败`;
} finally {
Ue.value = !1;
}
}
// 恢复默认筛选、排序及 URL 状态值,同时清除选择后刷新。
function Ge() {
((D.value = ``),
(O.value = ``),
navigateTo(
{
path: y.path,
query: {
...y.query,
status: O.value || `all`,
},
},
{
replace: !0,
},
),
(k.value = ``),
(A.value = ``),
(j.value = `create_time`),
(M.value = `desc`),
(N.value = []),
J());
}
let Ke = computed(() => !!D.value || !!O.value || !!A.value);
// 合并仅适用于已选未付按需订单,批量取消使用另一允许集合;导出参数与当前已应用筛选一致。
return (n, r) => {
let a = button,
c = ListSegments,
m = inputicon,
te = inputtext,
_ = iconfield,
v = select,
re = ListEmpty,
y = column,
b = NuxtLink,
x = tag,
S = datatable,
C = message,
T = paginator,
E = dialog;
return (
openBlock(),
createElementBlock(`div`, Se, [
createElementVNode(`div`, Ce, [
createElementVNode(
`h2`,
null,
toDisplayString(unref(w) ? `账单` : `订单`),
1,
),
!unref(w) || unref(N).length
? (openBlock(),
createElementBlock(`div`, we, [
unref(w)
? createCommentVNode(``, !0)
: (openBlock(),
createElementBlock(
`span`,
{
key: 0,
title: unref(Le),
},
[
createVNode(
a,
{
label: `合并按需订单`,
icon: `pi pi-copy`,
severity: `secondary`,
outlined: ``,
size: `small`,
disabled: !unref(Ie),
loading: unref(R),
onClick: Re,
},
null,
8,
[`disabled`, `loading`],
),
],
8,
Te,
)),
unref(N).length
? (openBlock(),
createBlock(
a,
{
key: 1,
label: `批量取消`,
icon: `pi pi-times`,
severity: `danger`,
outlined: ``,
size: `small`,
disabled:
!unref(X).length || unref(R) || unref(F),
onClick: Ve,
},
null,
8,
[`disabled`],
))
: createCommentVNode(``, !0),
unref(w)
? createCommentVNode(``, !0)
: (openBlock(),
createBlock(
a,
{
key: 2,
label: `导出 Excel`,
icon: `pi pi-download`,
severity: `secondary`,
outlined: ``,
size: `small`,
loading: unref(Ue),
onClick: We,
},
null,
8,
[`loading`],
)),
]))
: createCommentVNode(``, !0),
]),
unref(w)
? (openBlock(),
createElementBlock(
`p`,
Ee,
`查看未付款及历史账单,点击账单号或详情查看订单明细。`,
))
: createCommentVNode(``, !0),
createElementVNode(`div`, De, [
createVNode(
c,
{
modelValue: unref(D),
"onUpdate:modelValue": [
(r[0] ||= (e) => (isRef(D) ? (D.value = e) : null)),
unref(J),
],
options: Ne,
},
null,
8,
[`modelValue`, `onUpdate:modelValue`],
),
createElementVNode(`div`, Oe, [
createVNode(_, null, {
default: withCtx(() => [
createVNode(m, {
class: `pi pi-search`,
}),
createVNode(
te,
{
modelValue: unref(k),
"onUpdate:modelValue": (r[1] ||= (e) =>
isRef(k) ? (k.value = e) : null),
"aria-label": `搜索订单`,
class: `list-search`,
placeholder: `输入关键字`,
onKeyup: (r[2] ||= withKeys(
(e) => {
((A.value = unref(k).trim()), unref(J)());
},
[`enter`],
)),
},
null,
8,
[`modelValue`],
),
]),
_: 1,
}),
unref(w)
? createCommentVNode(``, !0)
: (openBlock(),
createBlock(
v,
{
key: 0,
modelValue: unref(O),
"onUpdate:modelValue": (r[3] ||= (e) =>
isRef(O) ? (O.value = e) : null),
"aria-label": `订单状态`,
class: `list-select`,
options: Pe,
optionLabel: `label`,
optionValue: `value`,
onChange: unref(J),
},
null,
8,
[`modelValue`, `onChange`],
)),
createVNode(
v,
{
modelValue: unref(j),
"onUpdate:modelValue": (r[4] ||= (e) =>
isRef(j) ? (j.value = e) : null),
"aria-label": `订单排序字段`,
class: `list-select`,
options: [
{
label: `按下单时间`,
value: `create_time`,
},
{
label: `按金额`,
value: `amount`,
},
{
label: `按状态`,
value: `status`,
},
],
optionLabel: `label`,
optionValue: `value`,
onChange: unref(J),
},
null,
8,
[`modelValue`, `onChange`],
),
createVNode(
a,
{
label: unref(M) === `desc` ? `降序` : `升序`,
icon:
unref(M) === `desc`
? `pi pi-sort-amount-down`
: `pi pi-sort-amount-up`,
severity: `secondary`,
outlined: ``,
size: `small`,
"aria-label": `切换订单排序方向`,
onClick: (r[5] ||= (e) => {
((M.value = unref(M) === `desc` ? `asc` : `desc`),
unref(J)());
}),
},
null,
8,
[`label`, `icon`],
),
createVNode(a, {
label: `清除筛选`,
icon: `pi pi-filter-slash`,
severity: `secondary`,
outlined: ``,
size: `small`,
onClick: Ge,
}),
]),
]),
createElementVNode(`div`, ke, [
createVNode(
S,
{
selection: unref(N),
"onUpdate:selection": (r[6] ||= (e) =>
isRef(N) ? (N.value = e) : null),
value: unref(H),
loading: unref(W),
lazy: ``,
rows: unref(q),
totalRecords: unref(U),
first: (unref(K) - 1) * unref(q),
dataKey: `id`,
rowSelectable: Be,
metaKeySelection: !1,
},
{
empty: withCtx(() => [
createVNode(
re,
{
icon: `pi pi-file-edit`,
title: unref(W) ? `加载中…` : `还没有订单`,
description: unref(Ke)
? `换个筛选条件试试`
: `下单后可以在这里查看订单状态`,
},
null,
8,
[`title`, `description`],
),
]),
default: withCtx(() => [
createVNode(y, {
selectionMode: `multiple`,
header: ``,
style: {
width: `48px`,
},
}),
createVNode(
y,
{
header: `下单时间`,
style: {
"min-width": `170px`,
},
},
{
body: withCtx(({ data: t }) => [
createTextVNode(
toDisplayString(
(`formatTime` in n
? n.formatTime
: unref(dict_r))(t.create_time),
),
1,
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `ID`,
style: {
width: `120px`,
},
},
{
body: withCtx(({ data: t }) => [
createVNode(
b,
{
to: Y(t.id),
class: `order-link`,
},
{
default: withCtx(() => [
createTextVNode(
`#` + toDisplayString(t.id),
1,
),
]),
_: 2,
},
1032,
[`to`],
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `类型`,
style: {
"min-width": `100px`,
"white-space": `nowrap`,
},
},
{
body: withCtx(({ data: t }) => [
createTextVNode(
toDisplayString(
(`orderTypeLabel` in n
? n.orderTypeLabel
: unref(dict_s))(t.type),
),
1,
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `商品`,
style: {
"min-width": `220px`,
},
},
{
body: withCtx(({ data: t }) => [
createElementVNode(
`span`,
{
class: `order-description`,
title: (`orderContent` in n
? n.orderContent
: unref(dict_i))(t),
},
toDisplayString(
(`orderContent` in n
? n.orderContent
: unref(dict_i))(t),
),
9,
Ae,
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `支付方式`,
style: {
"min-width": `130px`,
},
},
{
body: withCtx(({ data: t }) => [
createTextVNode(
toDisplayString(
t.gateway_name || t.gateway || `—`,
),
1,
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `状态`,
style: {
width: `110px`,
},
},
{
body: withCtx(({ data: e }) => [
createVNode(
x,
{
value: (`orderStatusLabel` in n
? n.orderStatusLabel
: unref(dict_a))(e.status),
severity: (`orderStatusSeverity` in n
? n.orderStatusSeverity
: unref(dict_o))(e.status),
},
null,
8,
[`value`, `severity`],
),
]),
_: 1,
},
),
createVNode(
y,
{
header: `总价`,
style: {
width: `120px`,
},
},
{
body: withCtx(({ data: t }) => [
createElementVNode(
`span`,
je,
`¥` + toDisplayString(t.amount),
1,
),
]),
_: 1,
},
),
createVNode(
y,
{
header: ``,
style: {
width: `115px`,
},
},
{
body: withCtx(({ data: e }) => [
createVNode(
a,
{
"as-child": ``,
size: `small`,
severity: `secondary`,
text: ``,
},
{
default: withCtx((n) => [
createVNode(
b,
{
to: Y(e.id),
class: normalizeClass(n.class),
"aria-label": `查看订单 ${e.id} 详情`,
},
{
default: withCtx(() => [
...(r[11] ||= [
createTextVNode(`详情`, -1),
]),
]),
_: 1,
},
8,
[`to`, `class`, `aria-label`],
),
]),
_: 2,
},
1024,
),
]),
_: 1,
},
),
]),
_: 1,
},
8,
[
`selection`,
`value`,
`loading`,
`rows`,
`totalRecords`,
`first`,
],
),
]),
unref(G)
? (openBlock(),
createBlock(
C,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(G)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref($)
? (openBlock(),
createBlock(
C,
{
key: 2,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref($)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(z) && !unref(L)
? (openBlock(),
createBlock(
C,
{
key: 3,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(z)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(U) > 0
? (openBlock(),
createElementBlock(`div`, Me, [
(r[12] ||= createElementVNode(
`div`,
{
class: `list-bulk`,
},
null,
-1,
)),
createVNode(
T,
{
rows: unref(q),
totalRecords: unref(U),
first: (unref(K) - 1) * unref(q),
rowsPerPageOptions: [20, 50, 100],
onPage: unref(Fe),
},
null,
8,
[`rows`, `totalRecords`, `first`, `onPage`],
),
]))
: createCommentVNode(``, !0),
createVNode(
E,
{
visible: unref(L),
"onUpdate:visible": (r[8] ||= (e) =>
isRef(L) ? (L.value = e) : null),
header: `合并按需订单`,
modal: ``,
draggable: !1,
closable: !unref(R),
"close-on-escape": !unref(R),
style: {
width: `440px`,
maxWidth: `calc(100vw - 32px)`,
},
},
{
footer: withCtx(() => [
createVNode(
a,
{
label: `返回`,
severity: `secondary`,
text: ``,
disabled: unref(R),
onClick: (r[7] ||= (e) => (L.value = !1)),
},
null,
8,
[`disabled`],
),
createVNode(
a,
{
label: `确认合并`,
loading: unref(R),
disabled: unref(R),
onClick: ze,
},
null,
8,
[`loading`, `disabled`],
),
]),
default: withCtx(() => [
createElementVNode(
`p`,
null,
`将合并选中的 ` +
toDisplayString(unref(B).length) +
` 笔未付款按需订单,确认后前往合并订单查看并付款。`,
1,
),
unref(z)
? (openBlock(),
createBlock(
C,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(z)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`, `closable`, `close-on-escape`],
),
createVNode(
E,
{
visible: unref(P),
"onUpdate:visible": (r[10] ||= (e) =>
isRef(P) ? (P.value = e) : null),
header: `批量取消订单`,
modal: ``,
draggable: !1,
style: {
width: `420px`,
},
},
{
footer: withCtx(() => [
createVNode(
a,
{
label: `返回`,
severity: `secondary`,
text: ``,
disabled: unref(F),
onClick: (r[9] ||= (e) => (P.value = !1)),
},
null,
8,
[`disabled`],
),
createVNode(
a,
{
label: `确认取消`,
severity: `danger`,
loading: unref(F),
onClick: He,
},
null,
8,
[`loading`],
),
]),
default: withCtx(() => [
createElementVNode(
`p`,
null,
`将取消 ` +
toDisplayString(unref(X).length) +
` 笔未付款订单。已付款或已取消订单不会被提交。`,
1,
),
unref(Z)
? (openBlock(),
createBlock(
C,
{
key: 0,
severity: `warn`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(
`已跳过 ` +
toDisplayString(unref(Z)) +
` 笔不可取消订单。`,
1,
),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(I)
? (openBlock(),
createBlock(
C,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(I)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`],
),
])
);
};
},
}),
[[`__scopeId`, `data-v-d87be2e3`]],
);
export { C as n };
export default w;
</script>