Files
cneicy 42dfead9cd
前端验证 / verify (push) Failing after 15m3s
feat(ui): 优化控制台响应式布局与视觉体验
- 统一页面标题、圆角、字体和响应式断点,调整暗色主题及图表配色
- 新增表格列标签插件,在窄屏下将表格转换为卡片布局,优化实例、订单、工单等列表展示
- 支持移动端点击订单行进入详情,并完善订单凭据的打印布局
- 在财务中心展示本月及累计消费,补充充值关闭时的提示
- 优化工单详情布局,将附件上传入口整合至富文本编辑器工具栏
- 调整实例操作按钮、SSH 密钥操作及安全菜单图标
- 为多个页面显式导入 definePageMeta,完善页面元数据声明
2026-11-07 00:09:57 +08:00

589 lines
20 KiB
Vue

<script>
/**
* 新闻资讯:分类与关键词分页查询,文章可独立打开或嵌入资源中心;正文加载和列表状态分开维护。
*/
import { definePageMeta } from "#imports";
import "~/assets/styles/news.CbIzdrjt.css";
definePageMeta({
scrollToTop: !0,
alias: [`/news/article`],
});
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 { 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 { withKeys } from "vue";
import { useRoute } from "#app";
import { useRouter } from "#app";
import { NuxtLink } from "#components";
import { useApi } 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 { r as dict_r } from "~/lib/dict.js";
import paginator from "primevue/paginator";
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";
import skeleton from "primevue/skeleton";
import { n as sanitize_n } from "~/lib/sanitize.js";
import { t as sanitize_t } from "~/lib/sanitize.js";
import { t as composables_t } from "~/lib/composables-2.js";
import { t as content_route_t } from "~/lib/content-route.js";
var fe = {
class: `list-page`,
},
pe = {
key: 0,
class: `list-head`,
},
me = {
class: `list-toolbar`,
},
he = {
class: `list-toolbar-right`,
},
ge = {
class: `list-search`,
},
_e = {
key: 2,
class: `news-list`,
},
ve = {
key: 3,
class: `news-list`,
},
ye = [`src`],
be = {
class: `news-main`,
},
D = {
class: `news-title`,
},
O = {
class: `news-excerpt`,
},
k = {
class: `news-meta`,
},
A = {
key: 5,
class: `list-foot`,
},
j = {
key: 0,
},
M = {
key: 2,
class: `news-detail`,
},
N = {
class: `news-detail-time`,
},
xe = [`innerHTML`],
P = _plugin_vue_export_helper_t(
defineComponent({
__name: `news`,
props: {
embedded: {
type: Boolean,
},
},
setup(h) {
composables_t({
scrollToTop: !0,
alias: `/news/article`,
});
let x = h,
P = useRoute(),
Se = useRouter(),
F = useApi(),
I = ref([]),
L = ref(``),
R = ref(``),
{
list: z,
total: B,
loading: Ce,
error: V,
page: we,
limit: H,
onPage: Te,
reload: U,
} = useListPage_t(`/news`, {
limit: 10,
params: () => ({
addon_idcsmart_news_type_id: L.value,
keywords: R.value,
}),
});
// 新闻分类加载失败不阻止列表使用,保留空分类选项。
async function Ee() {
try {
let e = await F.get(`/news/type`);
I.value = e.list ?? [];
} catch {
I.value = [];
}
}
// 选择分类后应用其 ID 并重新查询列表。
function De(e) {
((L.value = e === `` || e === void 0 ? `` : Number(e)), U());
}
// 摘要先经过公共清理函数,再移除标签、尾部截断实体和多余空格;不能把摘要当可信 HTML。
function Oe(e) {
return sanitize_t(e || ``)
.replace(/<[^>]*>/g, ``)
.replace(/<[^>]*$/, ``)
.replace(/&(?:#(?:x[\da-f]*|\d*)|[a-z]+)(?=(?:…|\.{3})?\s*$)/gi, ``)
.replace(/&nbsp;/g, ` `)
.replace(/\s+/g, ` `)
.trim();
}
let W = ref(!1),
G = ref(!1),
K = ref(null),
q = ref(``),
J = ref(null),
Y = 0,
X = !1;
// 根据嵌入模式生成资源中心或独立新闻文章地址。
function ke(e) {
return x?.embedded
? `/resources?section=news&id=${e}`
: `/news/article?id=${e}`;
}
// 解析文章路由并校验 ID;缺失或无效时取消旧详情请求并清空正文。
async function Z() {
if (X) return;
let e = P.query.id !== void 0 || P.path === `/news/article`,
t = content_route_t(P.query.id);
if (!e || !t) {
(Y++,
(W.value = e),
(G.value = !1),
(K.value = null),
(J.value = null),
(q.value = e ? `新闻编号无效,请从列表重新选择` : ``));
return;
}
await $({
id: t,
title: `新闻详情`,
create_time: 0,
});
}
// 关闭详情时废弃旧请求,并移除 URL 中的文章 ID,保留其余筛选查询。
function Q() {
if (
((W.value = !1),
Y++,
(G.value = !1),
P.query.id !== void 0 || P.path === `/news/article`)
) {
let e = {
...P.query,
};
(delete e.id,
Se.replace({
path: x?.embedded ? `/resources` : `/news`,
query: e,
}));
}
}
// 按文章 ID 获取正文,确认新闻对象存在;只有最新请求且未卸载时才写入弹窗。
async function $(e) {
let t = ++Y;
((W.value = !0),
(G.value = !0),
(J.value = e),
(q.value = ``),
(K.value = null));
try {
let n = await F.get(`/news/${e.id}`);
if (X || t !== Y) return;
if (!n.news) throw Error(`新闻不存在或已删除`);
K.value = n.news;
} catch (e) {
!X &&
t === Y &&
(q.value =
e instanceof Error ? e.message : `正文加载失败,请重试`);
} finally {
!X && t === Y && (G.value = !1);
}
}
return (
onMounted(async () => {
await Promise.all([Ee(), Z()]);
}),
watch(
() => P.query.id,
() => {
Z();
},
),
onBeforeUnmount(() => {
((X = !0), Y++);
}),
// 列表摘要为纯文本,详情 HTML 经公共清理工具处理后展示;正文失败不覆盖列表查询状态。
(n, r) => {
let i = ListSegments,
o = inputtext,
h = button,
v = message,
y = skeleton,
b = tag,
x = NuxtLink,
C = ListEmpty,
T = paginator,
E = dialog;
return (
openBlock(),
createElementBlock(`div`, fe, [
n.$props.embedded
? createCommentVNode(``, !0)
: (openBlock(),
createElementBlock(`div`, pe, [
...(r[3] ||= [
createElementVNode(`h2`, null, `新闻中心`, -1),
]),
])),
createElementVNode(`div`, me, [
createVNode(
i,
{
options: [
{
label: `全部`,
value: ``,
},
...unref(I).map((e) => ({
label: `${e.name}(${e.news_num})`,
value: e.id,
})),
],
"model-value": unref(L),
"onUpdate:modelValue": De,
},
null,
8,
[`options`, `model-value`],
),
createElementVNode(`div`, he, [
createElementVNode(`span`, ge, [
createVNode(
o,
{
modelValue: unref(R),
"onUpdate:modelValue": (r[0] ||= (e) =>
isRef(R) ? (R.value = e) : null),
placeholder: `搜索标题`,
onKeyup: withKeys(unref(U), [`enter`]),
},
null,
8,
[`modelValue`, `onKeyup`],
),
]),
createVNode(
h,
{
label: `查询`,
size: `small`,
severity: `secondary`,
outlined: ``,
onClick: unref(U),
},
null,
8,
[`onClick`],
),
]),
]),
unref(V)
? (openBlock(),
createBlock(
v,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(V)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(Ce) && !unref(z).length
? (openBlock(),
createElementBlock(`div`, _e, [
(openBlock(),
createElementBlock(
Fragment,
null,
renderList(4, (e) =>
createElementVNode(
`div`,
{
key: e,
class: `news-card`,
},
[
createVNode(y, {
height: `72px`,
}),
],
),
),
64,
)),
]))
: unref(z).length
? (openBlock(),
createElementBlock(`div`, ve, [
(openBlock(!0),
createElementBlock(
Fragment,
null,
renderList(
unref(z),
(t) => (
openBlock(),
createBlock(
x,
{
key: t.id,
to: ke(t.id),
class: `news-card`,
},
{
default: withCtx(() => [
t.img
? (openBlock(),
createElementBlock(
`img`,
{
key: 0,
src: t.img,
class: `news-img`,
alt: ``,
},
null,
8,
ye,
))
: createCommentVNode(``, !0),
createElementVNode(`div`, be, [
createElementVNode(
`div`,
D,
toDisplayString(t.title),
1,
),
createElementVNode(
`div`,
O,
toDisplayString(Oe(t.excerpt)),
1,
),
createElementVNode(`div`, k, [
t.type
? (openBlock(),
createBlock(
b,
{
key: 0,
value: t.type,
severity: `secondary`,
},
null,
8,
[`value`],
))
: createCommentVNode(``, !0),
createElementVNode(
`span`,
null,
toDisplayString(
(`formatTime` in n
? n.formatTime
: unref(dict_r))(t.create_time),
),
1,
),
]),
]),
]),
_: 2,
},
1032,
[`to`],
)
),
),
128,
)),
]))
: (openBlock(),
createBlock(C, {
key: 4,
icon: `pi pi-megaphone`,
title: `暂无新闻`,
description: `站点发布的新闻与公告会显示在这里`,
})),
unref(B) > 0
? (openBlock(),
createElementBlock(`div`, A, [
(r[4] ||= createElementVNode(
`div`,
{
class: `list-bulk`,
},
null,
-1,
)),
createVNode(
T,
{
rows: unref(H),
totalRecords: unref(B),
first: (unref(we) - 1) * unref(H),
rowsPerPageOptions: [10, 20, 50],
onPage: unref(Te),
},
null,
8,
[`rows`, `totalRecords`, `first`, `onPage`],
),
]))
: createCommentVNode(``, !0),
createVNode(
E,
{
visible: unref(W),
header: unref(K)?.title || unref(J)?.title || `新闻详情`,
modal: ``,
draggable: !1,
style: {
width: `760px`,
},
"onUpdate:visible": (r[2] ||= (e) => {
e || Q();
}),
},
{
footer: withCtx(() => [
unref(q) && unref(J)
? (openBlock(),
createBlock(h, {
key: 0,
label: `重新加载正文`,
icon: `pi pi-refresh`,
severity: `secondary`,
onClick: (r[1] ||= (e) => $(unref(J))),
}))
: createCommentVNode(``, !0),
createVNode(h, {
label: `关闭`,
severity: `secondary`,
text: ``,
onClick: Q,
}),
]),
default: withCtx(() => [
unref(G)
? (openBlock(),
createElementBlock(`div`, j, [
createVNode(y, {
height: `220px`,
}),
]))
: unref(q)
? (openBlock(),
createBlock(
v,
{
key: 1,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(q)), 1),
]),
_: 1,
},
))
: unref(K)
? (openBlock(),
createElementBlock(`div`, M, [
createElementVNode(
`div`,
N,
toDisplayString(
(`formatTime` in n
? n.formatTime
: unref(dict_r))(unref(K).create_time),
),
1,
),
createElementVNode(
`div`,
{
class: `news-detail-html`,
innerHTML: (`sanitizeHtml` in n
? n.sanitizeHtml
: unref(sanitize_n))(
(`decodeEntities` in n
? n.decodeEntities
: unref(sanitize_t))(
unref(K).content || ``,
),
),
},
null,
8,
xe,
),
]))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`, `header`],
),
])
);
}
);
},
}),
[[`__scopeId`, `data-v-0f61b69d`]],
);
export {};
export default P;
</script>