前端验证 / verify (push) Failing after 15m3s
- 统一页面标题、圆角、字体和响应式断点,调整暗色主题及图表配色 - 新增表格列标签插件,在窄屏下将表格转换为卡片布局,优化实例、订单、工单等列表展示 - 支持移动端点击订单行进入详情,并完善订单凭据的打印布局 - 在财务中心展示本月及累计消费,补充充值关闭时的提示 - 优化工单详情布局,将附件上传入口整合至富文本编辑器工具栏 - 调整实例操作按钮、SSH 密钥操作及安全菜单图标 - 为多个页面显式导入 definePageMeta,完善页面元数据声明
751 lines
30 KiB
Vue
751 lines
30 KiB
Vue
<script>
|
|
/**
|
|
* 帮助中心:支持独立文章路由和资源中心嵌入模式;目录与文章分别加载,通过请求序号防止快速切换文章时出现旧正文。
|
|
*/
|
|
import { definePageMeta } from "#imports";
|
|
import "~/assets/styles/help.BSOB30LE.css";
|
|
definePageMeta({
|
|
scrollToTop: !0,
|
|
alias: [`/help/article`],
|
|
});
|
|
import { toDisplayString } from "vue";
|
|
import { renderList } from "vue";
|
|
import { onMounted } 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 { 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 { useRoute } from "#app";
|
|
import { navigateTo } from "#app";
|
|
import { NuxtLink } from "#components";
|
|
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 inputtext from "primevue/inputtext";
|
|
import iconfield from "primevue/iconfield";
|
|
import inputicon from "primevue/inputicon";
|
|
import ListEmpty from "~/components/ListEmpty.vue";
|
|
import skeleton from "primevue/skeleton";
|
|
import { n as sanitize_n } from "~/lib/sanitize.js";
|
|
import { t as sanitize_t } from "~/lib/sanitize.js";
|
|
import { n as ticketAttachments_n } from "~/lib/ticketAttachments.js";
|
|
import { t as composables_t } from "~/lib/composables-2.js";
|
|
import { t as content_route_t } from "~/lib/content-route.js";
|
|
var me = {
|
|
class: `help-page`,
|
|
},
|
|
he = {
|
|
key: 0,
|
|
class: `page-head`,
|
|
},
|
|
ge = {
|
|
class: `help-body`,
|
|
},
|
|
_e = {
|
|
class: `help-nav`,
|
|
"aria-label": `帮助目录`,
|
|
},
|
|
ve = {
|
|
class: `nav-heading`,
|
|
},
|
|
ye = {
|
|
key: 0,
|
|
},
|
|
be = {
|
|
key: 0,
|
|
class: `nav-sk`,
|
|
},
|
|
C = {
|
|
key: 1,
|
|
class: `nav-groups`,
|
|
"aria-label": `帮助文章`,
|
|
},
|
|
w = {
|
|
class: `nav-group-title`,
|
|
},
|
|
T = {
|
|
key: 0,
|
|
class: `nav-empty`,
|
|
},
|
|
E = [`aria-busy`],
|
|
D = {
|
|
key: 0,
|
|
class: `content-sk`,
|
|
},
|
|
O = {
|
|
key: 1,
|
|
class: `content-error`,
|
|
},
|
|
k = {
|
|
key: 2,
|
|
},
|
|
A = {
|
|
class: `article-category`,
|
|
},
|
|
j = {
|
|
class: `content-title`,
|
|
},
|
|
M = [`innerHTML`],
|
|
N = {
|
|
key: 0,
|
|
class: `article-attachments`,
|
|
"aria-label": `文章附件`,
|
|
},
|
|
xe = [`href`],
|
|
P = {
|
|
class: `article-footer`,
|
|
},
|
|
F = _plugin_vue_export_helper_t(
|
|
defineComponent({
|
|
__name: `help`,
|
|
props: {
|
|
embedded: {
|
|
type: Boolean,
|
|
},
|
|
},
|
|
setup(h) {
|
|
composables_t({
|
|
scrollToTop: !0,
|
|
alias: `/help/article`,
|
|
});
|
|
let x = h,
|
|
F = useRoute(),
|
|
I = useApi(),
|
|
L = ref([]),
|
|
R = ref(!0),
|
|
z = ref(``),
|
|
B = ref(``),
|
|
V = ref(``),
|
|
H = computed(() =>
|
|
L.value.reduce((e, t) => e + (t.helps?.length ?? 0), 0),
|
|
),
|
|
U = computed(() => {
|
|
let e = V.value.trim().toLocaleLowerCase();
|
|
return L.value
|
|
.map((t) => ({
|
|
...t,
|
|
helps: (t.helps ?? []).filter(
|
|
(n) =>
|
|
!e ||
|
|
t.name.toLocaleLowerCase().includes(e) ||
|
|
n.title.toLocaleLowerCase().includes(e),
|
|
),
|
|
}))
|
|
.filter((e) => e.helps.length > 0);
|
|
}),
|
|
W = ref(null),
|
|
G = computed(() =>
|
|
ticketAttachments_n(W.value?.attachment).filter((e) => e.href),
|
|
),
|
|
K = ref(!1),
|
|
q = ref(null),
|
|
J = 0,
|
|
Y = 0,
|
|
X = !1,
|
|
Se = computed(
|
|
() =>
|
|
L.value.find((e) => e.helps?.some((e) => e.id === q.value))
|
|
?.name ?? ``,
|
|
);
|
|
// 嵌入模式使用资源中心地址,独立模式使用帮助文章地址,链接统一保留文章 ID。
|
|
function Ce(e) {
|
|
return x?.embedded
|
|
? `/resources?section=help&id=${e}`
|
|
: `/help/article?id=${e}`;
|
|
}
|
|
// 从路由校验文章 ID;未明确指定文章时选择目录首篇,无效编号不继续请求详情。
|
|
async function Z() {
|
|
if (X) return;
|
|
let e = F.query.id !== void 0 || F.path === `/help/article`,
|
|
t = content_route_t(F.query.id);
|
|
if (e && !t) {
|
|
(J++,
|
|
(q.value = null),
|
|
(W.value = null),
|
|
(K.value = !1),
|
|
(z.value = `帮助文档编号无效,请从目录重新选择`));
|
|
return;
|
|
}
|
|
let n = t ?? L.value.flatMap((e) => e.helps ?? [])[0]?.id;
|
|
n
|
|
? await $(n)
|
|
: (J++,
|
|
(q.value = null),
|
|
(W.value = null),
|
|
(K.value = !1),
|
|
(z.value = ``));
|
|
}
|
|
// 加载帮助目录后再解析当前文章;目录请求代次与文章请求代次互相独立。
|
|
async function Q() {
|
|
let e = ++Y;
|
|
((R.value = !0), (B.value = ``));
|
|
try {
|
|
let t = await I.get(`/help`);
|
|
if (X || e !== Y) return;
|
|
L.value = t.list ?? [];
|
|
} catch (t) {
|
|
if (X || e !== Y) return;
|
|
B.value = t instanceof Error ? t.message : `目录加载失败`;
|
|
} finally {
|
|
!X && e === Y && (R.value = !1);
|
|
}
|
|
!X && e === Y && (await Z());
|
|
}
|
|
// 每次切换文章先清除旧正文,再读取详情;仅当前请求且页面仍存活时更新状态。
|
|
async function $(e) {
|
|
let t = ++J;
|
|
((q.value = e), (K.value = !0), (W.value = null), (z.value = ``));
|
|
try {
|
|
let n = await I.get(`/help/${e}`);
|
|
if (X || t !== J) return;
|
|
if (!n.help) throw Error(`帮助文档不存在或已删除`);
|
|
W.value = n.help;
|
|
} catch (e) {
|
|
!X &&
|
|
t === J &&
|
|
(z.value = e instanceof Error ? e.message : `加载失败`);
|
|
} finally {
|
|
!X && t === J && (K.value = !1);
|
|
}
|
|
}
|
|
return (
|
|
onMounted(Q),
|
|
watch(
|
|
() => F.query.id,
|
|
() => {
|
|
R.value || Z();
|
|
},
|
|
),
|
|
onBeforeUnmount(() => {
|
|
((X = !0), J++, Y++);
|
|
}),
|
|
// 目录与文章分别显示加载/错误,正文与附件使用公共清理/解析工具;嵌入模式不改变业务请求。
|
|
(n, r) => {
|
|
let i = button,
|
|
o = inputicon,
|
|
l = inputtext,
|
|
h = iconfield,
|
|
v = skeleton,
|
|
b = NuxtLink,
|
|
x = message,
|
|
S = ListEmpty;
|
|
return (
|
|
openBlock(),
|
|
createElementBlock(`div`, me, [
|
|
n.$props.embedded
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(`div`, he, [
|
|
(r[6] ||= 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) =>
|
|
(`navigateTo` in n
|
|
? n.navigateTo
|
|
: unref(navigateTo))(`/tickets/create`)),
|
|
}),
|
|
])),
|
|
createElementVNode(`div`, ge, [
|
|
createElementVNode(`aside`, _e, [
|
|
createElementVNode(`div`, ve, [
|
|
(r[7] ||= createElementVNode(`h3`, null, `帮助目录`, -1)),
|
|
unref(R)
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(
|
|
`span`,
|
|
ye,
|
|
toDisplayString(unref(H)) + ` 篇`,
|
|
1,
|
|
)),
|
|
]),
|
|
createVNode(
|
|
h,
|
|
{
|
|
class: `help-search`,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
createVNode(o, {
|
|
class: `pi pi-search`,
|
|
}),
|
|
createVNode(
|
|
l,
|
|
{
|
|
modelValue: unref(V),
|
|
"onUpdate:modelValue": (r[1] ||= (e) =>
|
|
isRef(V) ? (V.value = e) : null),
|
|
placeholder: `搜索文章或分类`,
|
|
"aria-label": `搜索帮助文章或分类`,
|
|
},
|
|
null,
|
|
8,
|
|
[`modelValue`],
|
|
),
|
|
]),
|
|
_: 1,
|
|
},
|
|
),
|
|
unref(R)
|
|
? (openBlock(),
|
|
createElementBlock(`div`, be, [
|
|
(openBlock(),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(6, (e) =>
|
|
createVNode(v, {
|
|
key: e,
|
|
height: `20px`,
|
|
}),
|
|
),
|
|
64,
|
|
)),
|
|
]))
|
|
: (openBlock(),
|
|
createElementBlock(`nav`, C, [
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
unref(U),
|
|
(n) => (
|
|
openBlock(),
|
|
createElementBlock(
|
|
`div`,
|
|
{
|
|
key: n.id,
|
|
class: `nav-group`,
|
|
},
|
|
[
|
|
createElementVNode(`div`, w, [
|
|
createTextVNode(
|
|
toDisplayString(n.name),
|
|
1,
|
|
),
|
|
createElementVNode(
|
|
`span`,
|
|
null,
|
|
toDisplayString(n.helps.length),
|
|
1,
|
|
),
|
|
]),
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
n.helps,
|
|
(t) => (
|
|
openBlock(),
|
|
createBlock(
|
|
b,
|
|
{
|
|
key: t.id,
|
|
to: Ce(t.id),
|
|
class: normalizeClass([
|
|
`nav-item`,
|
|
{
|
|
active: unref(q) === t.id,
|
|
},
|
|
]),
|
|
"aria-current":
|
|
unref(q) === t.id
|
|
? `page`
|
|
: void 0,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
(r[8] ||= createElementVNode(
|
|
`i`,
|
|
{
|
|
class: `pi pi-file`,
|
|
"aria-hidden": `true`,
|
|
},
|
|
null,
|
|
-1,
|
|
)),
|
|
createElementVNode(
|
|
`span`,
|
|
null,
|
|
toDisplayString(t.title),
|
|
1,
|
|
),
|
|
]),
|
|
_: 2,
|
|
},
|
|
1032,
|
|
[`to`, `class`, `aria-current`],
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
],
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
unref(U).length
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createElementBlock(`div`, T, [
|
|
createElementVNode(
|
|
`p`,
|
|
null,
|
|
toDisplayString(
|
|
unref(V).trim()
|
|
? `没有找到匹配的文章`
|
|
: `暂无帮助内容`,
|
|
),
|
|
1,
|
|
),
|
|
unref(V).trim()
|
|
? (openBlock(),
|
|
createBlock(i, {
|
|
key: 0,
|
|
label: `清除搜索`,
|
|
size: `small`,
|
|
severity: `secondary`,
|
|
text: ``,
|
|
onClick: (r[2] ||= (e) => (V.value = ``)),
|
|
}))
|
|
: createCommentVNode(``, !0),
|
|
])),
|
|
])),
|
|
unref(B)
|
|
? (openBlock(),
|
|
createBlock(
|
|
x,
|
|
{
|
|
key: 2,
|
|
severity: `warn`,
|
|
closable: !1,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
createTextVNode(toDisplayString(unref(B)), 1),
|
|
createVNode(i, {
|
|
label: `重试目录`,
|
|
text: ``,
|
|
onClick: Q,
|
|
}),
|
|
]),
|
|
_: 1,
|
|
},
|
|
))
|
|
: createCommentVNode(``, !0),
|
|
(r[9] ||= createElementVNode(
|
|
`div`,
|
|
{
|
|
class: `support-note`,
|
|
},
|
|
[
|
|
createElementVNode(`i`, {
|
|
class: `pi pi-question-circle`,
|
|
"aria-hidden": `true`,
|
|
}),
|
|
createElementVNode(
|
|
`span`,
|
|
null,
|
|
`仍有疑问?创建工单,联系我们协助处理。`,
|
|
),
|
|
],
|
|
-1,
|
|
)),
|
|
]),
|
|
createElementVNode(
|
|
`section`,
|
|
{
|
|
class: `help-content`,
|
|
"aria-label": `帮助文章正文`,
|
|
"aria-busy": unref(K),
|
|
},
|
|
[
|
|
unref(K) || unref(R)
|
|
? (openBlock(),
|
|
createElementBlock(`div`, D, [
|
|
createVNode(v, {
|
|
width: `60%`,
|
|
height: `28px`,
|
|
}),
|
|
(openBlock(),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(5, (e) =>
|
|
createVNode(
|
|
v,
|
|
{
|
|
key: e,
|
|
width: e === 5 ? `70%` : `100%`,
|
|
height: `18px`,
|
|
},
|
|
null,
|
|
8,
|
|
[`width`],
|
|
),
|
|
),
|
|
64,
|
|
)),
|
|
]))
|
|
: unref(z)
|
|
? (openBlock(),
|
|
createElementBlock(`div`, O, [
|
|
createVNode(
|
|
S,
|
|
{
|
|
icon: `pi pi-exclamation-circle`,
|
|
title: `帮助内容暂时无法显示`,
|
|
description: unref(z),
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
unref(q)
|
|
? (openBlock(),
|
|
createBlock(i, {
|
|
key: 0,
|
|
label: `重新加载文章`,
|
|
icon: `pi pi-refresh`,
|
|
severity: `secondary`,
|
|
outlined: ``,
|
|
onClick: (r[3] ||= (e) =>
|
|
$(unref(q))),
|
|
}))
|
|
: (openBlock(),
|
|
createBlock(i, {
|
|
key: 1,
|
|
label: `重新加载帮助目录`,
|
|
icon: `pi pi-refresh`,
|
|
severity: `secondary`,
|
|
outlined: ``,
|
|
onClick: Q,
|
|
})),
|
|
]),
|
|
_: 1,
|
|
},
|
|
8,
|
|
[`description`],
|
|
),
|
|
]))
|
|
: unref(W)
|
|
? (openBlock(),
|
|
createElementBlock(`article`, k, [
|
|
createElementVNode(`div`, A, [
|
|
(r[10] ||= createElementVNode(
|
|
`i`,
|
|
{
|
|
class: `pi pi-book`,
|
|
"aria-hidden": `true`,
|
|
},
|
|
null,
|
|
-1,
|
|
)),
|
|
createElementVNode(
|
|
`span`,
|
|
null,
|
|
toDisplayString(unref(Se) || `帮助文档`),
|
|
1,
|
|
),
|
|
]),
|
|
createElementVNode(
|
|
`h3`,
|
|
j,
|
|
toDisplayString(unref(W).title),
|
|
1,
|
|
),
|
|
createElementVNode(
|
|
`div`,
|
|
{
|
|
class: `content-html`,
|
|
innerHTML: (`sanitizeHtml` in n
|
|
? n.sanitizeHtml
|
|
: unref(sanitize_n))(
|
|
(`decodeEntities` in n
|
|
? n.decodeEntities
|
|
: unref(sanitize_t))(
|
|
unref(W).content || ``,
|
|
),
|
|
),
|
|
},
|
|
null,
|
|
8,
|
|
M,
|
|
),
|
|
unref(G).length
|
|
? (openBlock(),
|
|
createElementBlock(`section`, N, [
|
|
(r[13] ||= createElementVNode(
|
|
`h4`,
|
|
null,
|
|
`相关附件`,
|
|
-1,
|
|
)),
|
|
createElementVNode(`ul`, null, [
|
|
(openBlock(!0),
|
|
createElementBlock(
|
|
Fragment,
|
|
null,
|
|
renderList(
|
|
unref(G),
|
|
(t) => (
|
|
openBlock(),
|
|
createElementBlock(
|
|
`li`,
|
|
{
|
|
key: t.href || t.name,
|
|
},
|
|
[
|
|
createElementVNode(
|
|
`a`,
|
|
{
|
|
href: t.href,
|
|
target: `_blank`,
|
|
rel: `noopener noreferrer`,
|
|
},
|
|
[
|
|
(r[11] ||=
|
|
createElementVNode(
|
|
`i`,
|
|
{
|
|
class: `pi pi-file`,
|
|
"aria-hidden": `true`,
|
|
},
|
|
null,
|
|
-1,
|
|
)),
|
|
createElementVNode(
|
|
`span`,
|
|
null,
|
|
toDisplayString(t.name),
|
|
1,
|
|
),
|
|
(r[12] ||=
|
|
createElementVNode(
|
|
`i`,
|
|
{
|
|
class: `pi pi-download`,
|
|
"aria-hidden": `true`,
|
|
},
|
|
null,
|
|
-1,
|
|
)),
|
|
],
|
|
8,
|
|
xe,
|
|
),
|
|
],
|
|
)
|
|
),
|
|
),
|
|
128,
|
|
)),
|
|
]),
|
|
]))
|
|
: createCommentVNode(``, !0),
|
|
createElementVNode(`footer`, P, [
|
|
(r[14] ||= createElementVNode(
|
|
`span`,
|
|
null,
|
|
`没有解决你的问题?`,
|
|
-1,
|
|
)),
|
|
createVNode(i, {
|
|
label: `创建工单`,
|
|
size: `small`,
|
|
severity: `secondary`,
|
|
outlined: ``,
|
|
onClick: (r[4] ||= (e) =>
|
|
(`navigateTo` in n
|
|
? n.navigateTo
|
|
: unref(navigateTo))(
|
|
`/tickets/create`,
|
|
)),
|
|
}),
|
|
]),
|
|
]))
|
|
: (openBlock(),
|
|
createBlock(
|
|
S,
|
|
{
|
|
key: 3,
|
|
icon: `pi pi-book`,
|
|
title: unref(H)
|
|
? `选择一篇帮助文档`
|
|
: `帮助文档正在准备中`,
|
|
description: unref(H)
|
|
? `从左侧目录选择文章,查看详细操作指引。`
|
|
: `如需协助,可以创建工单联系我们。`,
|
|
},
|
|
{
|
|
default: withCtx(() => [
|
|
unref(H)
|
|
? createCommentVNode(``, !0)
|
|
: (openBlock(),
|
|
createBlock(i, {
|
|
key: 0,
|
|
label: `创建工单`,
|
|
icon: `pi pi-plus`,
|
|
onClick: (r[5] ||= (e) =>
|
|
(`navigateTo` in n
|
|
? n.navigateTo
|
|
: unref(navigateTo))(
|
|
`/tickets/create`,
|
|
)),
|
|
})),
|
|
]),
|
|
_: 1,
|
|
},
|
|
8,
|
|
[`title`, `description`],
|
|
)),
|
|
],
|
|
8,
|
|
E,
|
|
),
|
|
]),
|
|
])
|
|
);
|
|
}
|
|
);
|
|
},
|
|
}),
|
|
[[`__scopeId`, `data-v-2e1fbf8d`]],
|
|
);
|
|
export {};
|
|
export default F;
|
|
</script>
|