smart-admin-web 10.26.0 → 10.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/api/index.d.ts +163 -0
  2. package/dist/api/index.js +195 -108
  3. package/dist/api/index.js.map +1 -1
  4. package/dist/api/schema.d.ts +1465 -109
  5. package/dist/assets/icons/ph-subset.json.js +1 -1
  6. package/dist/components/FilePathUpload/index.vue.d.ts +35 -0
  7. package/dist/components/FilePathUpload/index.vue.js +47 -0
  8. package/dist/components/FilePathUpload/index.vue.js.map +1 -0
  9. package/dist/components/FilePathUpload/index2.vue.js +5 -0
  10. package/dist/components/FilePathUpload/index2.vue.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +302 -294
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/runtime.js +1 -1
  15. package/dist/locales/en-US.d.ts +141 -0
  16. package/dist/locales/en-US.js +136 -0
  17. package/dist/locales/en-US.js.map +1 -1
  18. package/dist/locales/kernelMenuTitles.js +10 -0
  19. package/dist/locales/kernelMenuTitles.js.map +1 -1
  20. package/dist/locales/zh-CN.d.ts +141 -0
  21. package/dist/locales/zh-CN.js +136 -0
  22. package/dist/locales/zh-CN.js.map +1 -1
  23. package/dist/router/viewRegistry.js +8 -8
  24. package/dist/router/viewRegistry.js.map +1 -1
  25. package/dist/style.css +1 -1
  26. package/dist/utils/error.js +22 -18
  27. package/dist/utils/error.js.map +1 -1
  28. package/dist/utils/filePathUpload.d.ts +14 -0
  29. package/dist/utils/filePathUpload.js +84 -0
  30. package/dist/utils/filePathUpload.js.map +1 -0
  31. package/dist/views/system/file-path/access.d.ts +15 -0
  32. package/dist/views/system/file-path/access.js +49 -0
  33. package/dist/views/system/file-path/access.js.map +1 -0
  34. package/dist/views/system/file-path/components/PathForm.vue.d.ts +18 -0
  35. package/dist/views/system/file-path/components/PathForm.vue.js +8 -0
  36. package/dist/views/system/file-path/components/PathForm.vue.js.map +1 -0
  37. package/dist/views/system/file-path/components/PathForm2.vue.js +529 -0
  38. package/dist/views/system/file-path/components/PathForm2.vue.js.map +1 -0
  39. package/dist/views/system/file-path/components/PathTab.vue.d.ts +3 -0
  40. package/dist/views/system/file-path/components/PathTab.vue.js +8 -0
  41. package/dist/views/system/file-path/components/PathTab.vue.js.map +1 -0
  42. package/dist/views/system/file-path/components/PathTab2.vue.js +226 -0
  43. package/dist/views/system/file-path/components/PathTab2.vue.js.map +1 -0
  44. package/dist/views/system/file-path/components/ServerForm.vue.d.ts +20 -0
  45. package/dist/views/system/file-path/components/ServerForm.vue.js +8 -0
  46. package/dist/views/system/file-path/components/ServerForm.vue.js.map +1 -0
  47. package/dist/views/system/file-path/components/ServerForm2.vue.js +328 -0
  48. package/dist/views/system/file-path/components/ServerForm2.vue.js.map +1 -0
  49. package/dist/views/system/file-path/components/ServerTab.vue.d.ts +7 -0
  50. package/dist/views/system/file-path/components/ServerTab.vue.js +8 -0
  51. package/dist/views/system/file-path/components/ServerTab.vue.js.map +1 -0
  52. package/dist/views/system/file-path/components/ServerTab2.vue.js +181 -0
  53. package/dist/views/system/file-path/components/ServerTab2.vue.js.map +1 -0
  54. package/dist/views/system/file-path/index.vue.d.ts +3 -0
  55. package/dist/views/system/file-path/index.vue.js +8 -0
  56. package/dist/views/system/file-path/index.vue.js.map +1 -0
  57. package/dist/views/system/file-path/index2.vue.js +61 -0
  58. package/dist/views/system/file-path/index2.vue.js.map +1 -0
  59. package/dist/views/system/file-path/rules.d.ts +61 -0
  60. package/dist/views/system/file-path/rules.js +53 -0
  61. package/dist/views/system/file-path/rules.js.map +1 -0
  62. package/package.json +1 -1
@@ -0,0 +1,7 @@
1
+ import { FilePathEnvironment } from '../../../../api';
2
+ type __VLS_Props = {
3
+ environment: FilePathEnvironment | null;
4
+ };
5
+ declare const __VLS_export: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import o from "./ServerTab2.vue.js";
2
+ /* empty css */
3
+ import r from "../../../../_virtual/_plugin-vue_export-helper.js";
4
+ const m = /* @__PURE__ */ r(o, [["__scopeId", "data-v-715be878"]]);
5
+ export {
6
+ m as default
7
+ };
8
+ //# sourceMappingURL=ServerTab.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerTab.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,181 @@
1
+ import { defineComponent as _, ref as h, h as a, resolveDirective as E, openBlock as g, createElementBlock as A, Fragment as C, createVNode as l, unref as o, withCtx as m, withDirectives as x, createBlock as z, createTextVNode as B, toDisplayString as I } from "vue";
2
+ import { useMessage as L, NTag as O, NSpace as R, NButton as c, NPopconfirm as D } from "naive-ui";
3
+ import { useI18n as H } from "vue-i18n";
4
+ import { SmartTable as U } from "smart-naive-table";
5
+ import q from "../../../../components/AppIcon.vue.js";
6
+ import F from "../../../../components/StatusSwitch/index.vue.js";
7
+ import $ from "../../../../components/TableTotal/index.vue.js";
8
+ import { useConfirm as M } from "../../../../composables/useConfirm.js";
9
+ import { fileServerApi as u } from "../../../../api/index.js";
10
+ import { useAuthStore as V } from "../../../../stores/auth.js";
11
+ import { translateError as j } from "../../../../utils/error.js";
12
+ import { SEARCH_ACTIONS as G, deriveHeaderFilters as W } from "../../../../utils/tableFilter.js";
13
+ import { TABLE_MIN_ROW_HEIGHT as J, TABLE_TOOLBAR as K } from "../../../../utils/tableToolbar.js";
14
+ import { useAccessStatus as Q } from "../access.js";
15
+ import X from "./ServerForm.vue.js";
16
+ const pe = /* @__PURE__ */ _({
17
+ __name: "ServerTab",
18
+ props: {
19
+ environment: {}
20
+ },
21
+ setup(k) {
22
+ const { t } = H(), b = L(), { run: N } = M(), d = V(), f = h(), v = Q(u.status), y = () => a("span", { style: { color: "var(--text-3)" } }, "—"), w = [
23
+ { type: "index", title: () => t("common.rowNo"), width: 64, align: "center" },
24
+ // 只作搜索项,不进表格:后端的 keyword 同时匹配名称和根路径
25
+ {
26
+ key: "keyword",
27
+ title: () => t("filePath.server.keyword"),
28
+ hideInTable: !0,
29
+ search: { actions: G.fuzzy }
30
+ },
31
+ { key: "name", ellipsis: { tooltip: !0 }, title: () => t("filePath.server.name") },
32
+ {
33
+ key: "rootPath",
34
+ ellipsis: { tooltip: !0 },
35
+ title: () => t("filePath.server.rootPath"),
36
+ render: (e) => a("span", { class: "mono muted" }, e.rootPath)
37
+ },
38
+ {
39
+ key: "userName",
40
+ width: 140,
41
+ ellipsis: { tooltip: !0 },
42
+ title: () => t("filePath.server.userName"),
43
+ render: (e) => e.userName || y()
44
+ },
45
+ {
46
+ key: "hasPassword",
47
+ width: 100,
48
+ title: () => t("filePath.server.password"),
49
+ render: (e) => e.hasPassword ? a(
50
+ O,
51
+ { size: "small", bordered: !1, type: "success" },
52
+ () => t("filePath.server.passwordSet")
53
+ ) : y()
54
+ },
55
+ {
56
+ key: "status",
57
+ width: 100,
58
+ title: () => t("filePath.status.column"),
59
+ render: (e) => v.render(e.id)
60
+ },
61
+ {
62
+ key: "enabled",
63
+ title: () => t("common.status"),
64
+ width: 80,
65
+ render: (e) => a(F, {
66
+ value: e.enabled,
67
+ disabled: !d.hasPerm("PUT:/api/v1/sys/file-server/{id}"),
68
+ // 密码留空 = 不改;主机和账号没动,后端不会清密码
69
+ request: (r) => u.update(Number(e.id), {
70
+ name: e.name,
71
+ rootPath: e.rootPath,
72
+ userName: e.userName,
73
+ password: null,
74
+ enabled: r,
75
+ remark: e.remark
76
+ }),
77
+ "onUpdate:value": (r) => {
78
+ e.enabled = r;
79
+ }
80
+ })
81
+ },
82
+ {
83
+ key: "op",
84
+ title: () => t("common.operation"),
85
+ width: 140,
86
+ align: "right",
87
+ fixed: "right",
88
+ hideInSetting: !0,
89
+ render: (e) => a(R, { size: 2, wrapItem: !1, justify: "end" }, () => [
90
+ d.hasPerm("PUT:/api/v1/sys/file-server/{id}") ? a(
91
+ c,
92
+ { size: "small", quaternary: !0, type: "primary", onClick: () => T(e) },
93
+ () => t("common.edit")
94
+ ) : null,
95
+ d.hasPerm("DELETE:/api/v1/sys/file-server/{id}") ? a(
96
+ D,
97
+ {
98
+ onPositiveClick: () => N(() => u.remove(Number(e.id)), t("filePath.deleted")).then((r) => {
99
+ var n;
100
+ r && ((n = f.value) == null || n.refresh());
101
+ })
102
+ },
103
+ {
104
+ trigger: () => a(
105
+ c,
106
+ { size: "small", quaternary: !0, type: "error" },
107
+ () => t("common.delete")
108
+ ),
109
+ default: () => t("filePath.server.deleteConfirm", { name: e.name })
110
+ }
111
+ ) : null
112
+ ])
113
+ }
114
+ ];
115
+ W(w);
116
+ const s = h(!1), p = h(null);
117
+ function S() {
118
+ p.value = null, s.value = !0;
119
+ }
120
+ function T(e) {
121
+ p.value = e, s.value = !0;
122
+ }
123
+ return (e, r) => {
124
+ const n = E("auth");
125
+ return g(), A(C, null, [
126
+ l(o(U), {
127
+ ref_key: "tableRef",
128
+ ref: f,
129
+ toolbar: o(K),
130
+ columns: w,
131
+ fetcher: o(u).page,
132
+ search: { container: "table" },
133
+ "fill-height": "",
134
+ "min-row-height": o(J),
135
+ "card-on-narrow": "",
136
+ "storage-key": "sys-file-server",
137
+ onLoaded: r[0] || (r[0] = (i) => o(v).load(i)),
138
+ onError: r[1] || (r[1] = (i) => o(b).error(o(j)(i)))
139
+ }, {
140
+ "pagination-prefix": m(({ itemCount: i }) => [
141
+ l($, { count: i }, null, 8, ["count"])
142
+ ]),
143
+ "toolbar-right": m(() => [
144
+ x((g(), z(o(c), {
145
+ type: "primary",
146
+ onClick: S
147
+ }, {
148
+ icon: m(() => [
149
+ l(q, {
150
+ icon: "ph:plus",
151
+ size: 16
152
+ })
153
+ ]),
154
+ default: m(() => [
155
+ B(" " + I(o(t)("common.add")), 1)
156
+ ]),
157
+ _: 1
158
+ })), [
159
+ [n, "POST:/api/v1/sys/file-server/add"]
160
+ ])
161
+ ]),
162
+ _: 1
163
+ }, 8, ["toolbar", "fetcher", "min-row-height"]),
164
+ l(X, {
165
+ show: s.value,
166
+ "onUpdate:show": r[2] || (r[2] = (i) => s.value = i),
167
+ editing: p.value,
168
+ environment: k.environment,
169
+ onSaved: r[3] || (r[3] = (i) => {
170
+ var P;
171
+ return (P = f.value) == null ? void 0 : P.refresh();
172
+ })
173
+ }, null, 8, ["show", "editing", "environment"])
174
+ ], 64);
175
+ };
176
+ }
177
+ });
178
+ export {
179
+ pe as default
180
+ };
181
+ //# sourceMappingURL=ServerTab2.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServerTab2.vue.js","sources":["../../../../../src/views/system/file-path/components/ServerTab.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 「文件服务器」页签:列表 + 新增/编辑抽屉。在线状态在一页取完后另外问一次,见 access.ts。\nimport { h, ref } from 'vue'\nimport { NButton, NPopconfirm, NSpace, NTag, useMessage } from 'naive-ui'\nimport { useI18n } from 'vue-i18n'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport AppIcon from '#/components/AppIcon.vue'\nimport StatusSwitch from '#/components/StatusSwitch/index.vue'\nimport TableTotal from '#/components/TableTotal/index.vue'\nimport { useConfirm } from '#/composables/useConfirm'\nimport { fileServerApi, type FilePathEnvironment, type FileServerView } from '#/api'\nimport { useAuthStore } from '#/stores/auth'\nimport { translateError } from '#/utils/error'\nimport { SEARCH_ACTIONS, deriveHeaderFilters } from '#/utils/tableFilter'\nimport { TABLE_MIN_ROW_HEIGHT, TABLE_TOOLBAR } from '#/utils/tableToolbar'\nimport { useAccessStatus } from '../access'\nimport ServerForm from './ServerForm.vue'\n\ndefineProps<{ environment: FilePathEnvironment | null }>()\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst { run } = useConfirm()\nconst authStore = useAuthStore()\nconst tableRef = ref<SmartTableInst<FileServerView>>()\nconst status = useAccessStatus(fileServerApi.status)\n\nconst dash = () => h('span', { style: { color: 'var(--text-3)' } }, '—')\n\nconst columns: SmartTableColumn<FileServerView>[] = [\n { type: 'index', title: () => t('common.rowNo'), width: 64, align: 'center' },\n // 只作搜索项,不进表格:后端的 keyword 同时匹配名称和根路径\n {\n key: 'keyword',\n title: () => t('filePath.server.keyword'),\n hideInTable: true,\n search: { actions: SEARCH_ACTIONS.fuzzy },\n },\n { key: 'name', ellipsis: { tooltip: true }, title: () => t('filePath.server.name') },\n {\n key: 'rootPath',\n ellipsis: { tooltip: true },\n title: () => t('filePath.server.rootPath'),\n render: r => h('span', { class: 'mono muted' }, r.rootPath),\n },\n {\n key: 'userName',\n width: 140,\n ellipsis: { tooltip: true },\n title: () => t('filePath.server.userName'),\n render: r => r.userName || dash(),\n },\n {\n key: 'hasPassword',\n width: 100,\n title: () => t('filePath.server.password'),\n render: r =>\n r.hasPassword\n ? h(NTag, { size: 'small', bordered: false, type: 'success' }, () =>\n t('filePath.server.passwordSet'),\n )\n : dash(),\n },\n {\n key: 'status',\n width: 100,\n title: () => t('filePath.status.column'),\n render: r => status.render(r.id),\n },\n {\n key: 'enabled',\n title: () => t('common.status'),\n width: 80,\n render: r =>\n h(StatusSwitch, {\n value: r.enabled,\n disabled: !authStore.hasPerm('PUT:/api/v1/sys/file-server/{id}'),\n // 密码留空 = 不改;主机和账号没动,后端不会清密码\n request: (next: boolean) =>\n fileServerApi.update(Number(r.id), {\n name: r.name,\n rootPath: r.rootPath,\n userName: r.userName,\n password: null,\n enabled: next,\n remark: r.remark,\n }),\n 'onUpdate:value': (v: boolean) => {\n r.enabled = v\n },\n }),\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 140,\n align: 'right',\n fixed: 'right',\n hideInSetting: true,\n render: r =>\n h(NSpace, { size: 2, wrapItem: false, justify: 'end' }, () => [\n authStore.hasPerm('PUT:/api/v1/sys/file-server/{id}')\n ? h(\n NButton,\n { size: 'small', quaternary: true, type: 'primary', onClick: () => openEdit(r) },\n () => t('common.edit'),\n )\n : null,\n authStore.hasPerm('DELETE:/api/v1/sys/file-server/{id}')\n ? h(\n NPopconfirm,\n {\n onPositiveClick: () =>\n run(() => fileServerApi.remove(Number(r.id)), t('filePath.deleted')).then(ok => {\n if (ok) tableRef.value?.refresh()\n }),\n },\n {\n trigger: () =>\n h(NButton, { size: 'small', quaternary: true, type: 'error' }, () =>\n t('common.delete'),\n ),\n default: () => t('filePath.server.deleteConfirm', { name: r.name }),\n },\n )\n : null,\n ]),\n },\n]\nderiveHeaderFilters(columns)\n\n// ── 新增/编辑抽屉 ──\nconst formShow = ref(false)\nconst editing = ref<FileServerView | null>(null)\nfunction openAdd() {\n editing.value = null\n formShow.value = true\n}\nfunction openEdit(r: FileServerView) {\n editing.value = r\n formShow.value = true\n}\n</script>\n\n<template>\n <SmartTable\n ref=\"tableRef\"\n :toolbar=\"TABLE_TOOLBAR\"\n :columns=\"columns\"\n :fetcher=\"fileServerApi.page\"\n :search=\"{ container: 'table' }\"\n fill-height\n :min-row-height=\"TABLE_MIN_ROW_HEIGHT\"\n card-on-narrow\n storage-key=\"sys-file-server\"\n @loaded=\"rows => status.load(rows)\"\n @error=\"e => message.error(translateError(e))\"\n >\n <template #pagination-prefix=\"{ itemCount }\">\n <TableTotal :count=\"itemCount\" />\n </template>\n <template #toolbar-right>\n <n-button v-auth=\"'POST:/api/v1/sys/file-server/add'\" type=\"primary\" @click=\"openAdd\">\n <template #icon><AppIcon icon=\"ph:plus\" :size=\"16\" /></template>\n {{ t('common.add') }}\n </n-button>\n </template>\n </SmartTable>\n\n <ServerForm\n v-model:show=\"formShow\"\n :editing=\"editing\"\n :environment=\"environment\"\n @saved=\"tableRef?.refresh()\"\n />\n</template>\n\n<style scoped>\n/* 表格单元格由库渲染,要 :deep */\n:deep(.mono) {\n font-family: var(--font-mono);\n font-size: 13.5px;\n letter-spacing: 0;\n}\n:deep(.muted) {\n color: var(--text-2);\n}\n</style>\n"],"names":["useI18n","message","useMessage","run","useConfirm","authStore","useAuthStore","tableRef","ref","status","useAccessStatus","fileServerApi","dash","h","columns","SEARCH_ACTIONS","r","NTag","StatusSwitch","next","v","NSpace","NButton","openEdit","NPopconfirm","ok","_a","deriveHeaderFilters","formShow","editing","openAdd","_createVNode","_unref","SmartTable","TABLE_TOOLBAR","TABLE_MIN_ROW_HEIGHT","rows","_cache","e","translateError","_withCtx","itemCount","TableTotal","_createBlock","AppIcon","_createTextVNode","ServerForm","$event","__props"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import o from "./index2.vue.js";
2
+ /* empty css */
3
+ import t from "../../../_virtual/_plugin-vue_export-helper.js";
4
+ const p = /* @__PURE__ */ t(o, [["__scopeId", "data-v-73c1a187"]]);
5
+ export {
6
+ p as default
7
+ };
8
+ //# sourceMappingURL=index.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -0,0 +1,61 @@
1
+ import { defineComponent as g, computed as v, ref as f, onMounted as P, openBlock as a, createElementBlock as T, createVNode as r, unref as e, withCtx as n, createBlock as c, createCommentVNode as d } from "vue";
2
+ import { useMessage as x, NTabs as k, NTabPane as h } from "naive-ui";
3
+ import { useMediaQuery as w } from "@vueuse/core";
4
+ import { useI18n as E } from "vue-i18n";
5
+ import { filePathApi as N } from "../../../api/index.js";
6
+ import { useAuthStore as S } from "../../../stores/auth.js";
7
+ import { translateError as B } from "../../../utils/error.js";
8
+ import C from "./components/PathTab.vue.js";
9
+ import G from "./components/ServerTab.vue.js";
10
+ const M = { class: "view fill-page" }, H = /* @__PURE__ */ g({
11
+ __name: "index",
12
+ setup(z) {
13
+ const { t: o } = E(), b = x(), t = S(), s = v(() => t.hasPerm("GET:/api/v1/sys/file-path/page")), i = v(() => t.hasPerm("GET:/api/v1/sys/file-server/page")), m = f(s.value || !i.value ? "path" : "server"), _ = w("(max-width: 604px)"), l = f(null);
14
+ return P(async () => {
15
+ if (t.hasPerm("GET:/api/v1/sys/file-path/environment"))
16
+ try {
17
+ l.value = await N.environment();
18
+ } catch (p) {
19
+ b.error(B(p));
20
+ }
21
+ }), (p, u) => (a(), T("div", M, [
22
+ r(e(k), {
23
+ value: m.value,
24
+ "onUpdate:value": u[0] || (u[0] = (y) => m.value = y),
25
+ type: "segment",
26
+ animated: "",
27
+ class: "fill-tabs file-path-seg",
28
+ size: e(_) ? "large" : "medium",
29
+ "pane-style": { padding: 0 }
30
+ }, {
31
+ default: n(() => [
32
+ s.value ? (a(), c(e(h), {
33
+ key: 0,
34
+ name: "path",
35
+ tab: e(o)("filePath.tabs.path")
36
+ }, {
37
+ default: n(() => [
38
+ r(C)
39
+ ]),
40
+ _: 1
41
+ }, 8, ["tab"])) : d("", !0),
42
+ i.value ? (a(), c(e(h), {
43
+ key: 1,
44
+ name: "server",
45
+ tab: e(o)("filePath.tabs.server")
46
+ }, {
47
+ default: n(() => [
48
+ r(G, { environment: l.value }, null, 8, ["environment"])
49
+ ]),
50
+ _: 1
51
+ }, 8, ["tab"])) : d("", !0)
52
+ ]),
53
+ _: 1
54
+ }, 8, ["value", "size"])
55
+ ]));
56
+ }
57
+ });
58
+ export {
59
+ H as default
60
+ };
61
+ //# sourceMappingURL=index2.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index2.vue.js","sources":["../../../../src/views/system/file-path/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 文件路径配置页:「文件路径」「文件服务器」两个页签,各一张列表加一个编辑抽屉。\n// 页签按各自列表的查询权限显示,默认打开第一个看得见的。\n// 环境信息(白名单根目录、平台能不能用账号)挂载时取一次,白名单为空时顶部提示,服务器页签用它给根路径候选。\nimport { computed, onMounted, ref } from 'vue'\nimport { NTabPane, NTabs, useMessage } from 'naive-ui'\nimport { useMediaQuery } from '@vueuse/core'\nimport { useI18n } from 'vue-i18n'\nimport { filePathApi, type FilePathEnvironment } from '#/api'\nimport { useAuthStore } from '#/stores/auth'\nimport { translateError } from '#/utils/error'\nimport PathTab from './components/PathTab.vue'\nimport ServerTab from './components/ServerTab.vue'\n\nconst { t } = useI18n()\nconst message = useMessage()\nconst authStore = useAuthStore()\n\nconst canPath = computed(() => authStore.hasPerm('GET:/api/v1/sys/file-path/page'))\nconst canServer = computed(() => authStore.hasPerm('GET:/api/v1/sys/file-server/page'))\nconst activeTab = ref<'path' | 'server'>(canPath.value || !canServer.value ? 'path' : 'server')\n// 窄屏页签放大到触控尺寸\nconst narrow = useMediaQuery('(max-width: 604px)')\n\n// 没有查询权限的账号拿不到环境信息:按「没有候选、能用账号」处理,不弹错\nconst environment = ref<FilePathEnvironment | null>(null)\nonMounted(async () => {\n if (!authStore.hasPerm('GET:/api/v1/sys/file-path/environment')) return\n try {\n environment.value = await filePathApi.environment()\n } catch (e) {\n message.error(translateError(e))\n }\n})\n</script>\n\n<template>\n <div class=\"view fill-page\">\n <!-- 形状 4:.fill-tabs 把 n-tabs → 面板容器 → .n-tab-pane 一路拉成 flex 列,\n 面板里的 SmartTable 就接上高度链了(见 styles/layout.css ⑧)。 -->\n <n-tabs\n v-model:value=\"activeTab\"\n type=\"segment\"\n animated\n class=\"fill-tabs file-path-seg\"\n :size=\"narrow ? 'large' : 'medium'\"\n :pane-style=\"{ padding: 0 }\"\n >\n <n-tab-pane v-if=\"canPath\" name=\"path\" :tab=\"t('filePath.tabs.path')\">\n <PathTab />\n </n-tab-pane>\n <n-tab-pane v-if=\"canServer\" name=\"server\" :tab=\"t('filePath.tabs.server')\">\n <ServerTab :environment=\"environment\" />\n </n-tab-pane>\n </n-tabs>\n </div>\n</template>\n\n<style scoped>\n/* display / flex-direction / 整屏高度链都在 styles/layout.css 的 .fill-page,这里只留卡片间距。 */\n.view {\n gap: var(--gap-card);\n}\n\n/* 分段控件:naive 的 segment 轨道默认 width:100% 且各格等分,两格会被撑成一条长带。\n 这里让轨道按内容收窄、靠左。 */\n.file-path-seg :deep(.n-tabs-nav) {\n align-self: flex-start;\n max-width: 100%;\n margin-bottom: var(--gap-card);\n}\n.file-path-seg :deep(.n-tabs-rail) {\n width: auto;\n overflow-x: auto;\n scrollbar-width: none;\n}\n.file-path-seg :deep(.n-tabs-rail::-webkit-scrollbar) {\n display: none;\n}\n.file-path-seg :deep(.n-tabs-tab-wrapper) {\n flex: 0 0 auto;\n}\n.file-path-seg :deep(.n-tabs-tab) {\n padding: 4px 14px;\n white-space: nowrap;\n}\n</style>\n"],"names":["t","useI18n","message","useMessage","authStore","useAuthStore","canPath","computed","canServer","activeTab","ref","narrow","useMediaQuery","environment","onMounted","filePathApi","e","translateError","_openBlock","_createElementBlock","_hoisted_1","_createVNode","_unref","NTabs","$event","_createBlock","NTabPane","PathTab","ServerTab"],"mappings":";;;;;;;;;;;;AAcA,UAAM,EAAE,GAAAA,EAAA,IAAMC,EAAA,GACRC,IAAUC,EAAA,GACVC,IAAYC,EAAA,GAEZC,IAAUC,EAAS,MAAMH,EAAU,QAAQ,gCAAgC,CAAC,GAC5EI,IAAYD,EAAS,MAAMH,EAAU,QAAQ,kCAAkC,CAAC,GAChFK,IAAYC,EAAuBJ,EAAQ,SAAS,CAACE,EAAU,QAAQ,SAAS,QAAQ,GAExFG,IAASC,EAAc,oBAAoB,GAG3CC,IAAcH,EAAgC,IAAI;AACxD,WAAAI,EAAU,YAAY;AACpB,UAAKV,EAAU,QAAQ,uCAAuC;AAC9D,YAAI;AACF,UAAAS,EAAY,QAAQ,MAAME,EAAY,YAAA;AAAA,QACxC,SAASC,GAAG;AACV,UAAAd,EAAQ,MAAMe,EAAeD,CAAC,CAAC;AAAA,QACjC;AAAA,IACF,CAAC,cAICE,EAAA,GAAAC,EAkBM,OAlBNC,GAkBM;AAAA,MAfJC,EAcSC,EAAAC,CAAA,GAAA;AAAA,QAbC,OAAOd,EAAA;AAAA,iDAAAA,EAAS,QAAAe;AAAA,QACxB,MAAK;AAAA,QACL,UAAA;AAAA,QACA,OAAM;AAAA,QACL,MAAMF,EAAAX,CAAA,IAAM,UAAA;AAAA,QACZ,cAAY,EAAA,SAAA,EAAA;AAAA,MAAA;mBAEb,MAEa;AAAA,UAFKL,EAAA,cAAlBmB,EAEaH,EAAAI,CAAA,GAAA;AAAA;YAFc,MAAK;AAAA,YAAQ,KAAKJ,EAAAtB,CAAA,EAAC,oBAAA;AAAA,UAAA;uBAC5C,MAAW;AAAA,cAAXqB,EAAWM,CAAA;AAAA,YAAA;;;UAEKnB,EAAA,cAAlBiB,EAEaH,EAAAI,CAAA,GAAA;AAAA;YAFgB,MAAK;AAAA,YAAU,KAAKJ,EAAAtB,CAAA,EAAC,sBAAA;AAAA,UAAA;uBAChD,MAAwC;AAAA,cAAxCqB,EAAwCO,GAAA,EAA5B,aAAaf,EAAA,MAAA,GAAW,MAAA,GAAA,CAAA,aAAA,CAAA;AAAA,YAAA;;;;;;;;;"}
@@ -0,0 +1,61 @@
1
+ /** 文件落盘的命名规则(与后端 FilePathNamingRule 的值一致)。 */
2
+ export declare const NamingRule: {
3
+ readonly YearMonthOriginal: 0;
4
+ readonly BusinessPath: 1;
5
+ readonly DateGuid: 2;
6
+ };
7
+ /** 命名规则的显示名在语言包里的键。 */
8
+ export declare const NAMING_RULE_LABEL_KEYS: Record<number, string>;
9
+ /** 业务指定路径撞名时的处理(与后端 FilePathConflictMode 的值一致);其余命名规则不会撞名。 */
10
+ export declare const ConflictMode: {
11
+ readonly Reject: 0;
12
+ readonly Overwrite: 1;
13
+ };
14
+ /**
15
+ * 业务指定路径 + 同名覆盖 + 没限制上传角色:任何登录用户都能覆盖这个文件夹里的同名文件,表单要给出警告。
16
+ * 只读的行不收上传,谈不上覆盖。
17
+ */
18
+ export declare function overwriteRisk(form: {
19
+ namingRule: number;
20
+ onConflict: number;
21
+ readOnly: boolean;
22
+ uploadRoleIds: readonly unknown[];
23
+ }): boolean;
24
+ /** 编码:字母、数字、点、下划线、连字符,1–64 位。 */
25
+ export declare const CODE_PATTERN: RegExp;
26
+ /**
27
+ * 后缀白名单规范化:去空白、转小写、去重,每项须是「点 + 1–15 位字母或数字」。
28
+ * 格式不对返回 null;空输入是合法的空白名单,返回空串(是否必填由调用方按只读与否决定)。
29
+ */
30
+ export declare function normalizeExtensions(input: string): string | null;
31
+ /**
32
+ * 共享路径 `\\host\share` 或 `//host/share` 里的主机名。不是共享路径(本地路径、只有主机没有共享名、
33
+ * 设备路径 `\\?\`)一律为空串,按「本机」算。与后端 FilePathRules.TryGetShare 的判定一致。
34
+ */
35
+ export declare function hostOf(rootPath: string): string;
36
+ /**
37
+ * 保存或测试连接时,密码留空会沿用已保存的密码,但主机或账号换了就不会(后端 CanReuseSavedPassword),
38
+ * 修改时后端直接拒绝保存(44157),原来有没有设置密码都一样。
39
+ * 同时满足才返回 true:新账号不为空(清空账号 = 改用后端运行身份,不需要密码);主机或账号变了。
40
+ * 主机、账号都不区分大小写,账号先去首尾空白,null 与空串相同。
41
+ */
42
+ export declare function passwordReentryRequired(original: {
43
+ rootPath: string;
44
+ userName?: string | null;
45
+ }, rootPath: string, userName: string | null | undefined): boolean;
46
+ /**
47
+ * 修改一台文件服务器的账号或密码时,后端会把同一主机的其他文件服务器一起改成相同的账号和密码(Windows 对一台主机只接受一套凭据)。
48
+ * 返回表单要给出的提示:'change' 同主机其他行一起改成这个账号和密码;'clear' 清空账号,整台主机改用后端运行身份;null 不影响别的行。
49
+ * 只在主机没变时级联,换到另一台主机或本机路径时为 null。账号先去首尾空白、按原样比较:只差大小写也算改了,后端会统一写法。
50
+ */
51
+ export declare function credentialCascade(original: {
52
+ rootPath: string;
53
+ userName?: string | null;
54
+ }, rootPath: string, userName: string | null | undefined, password: string): 'change' | 'clear' | null;
55
+ /**
56
+ * 完整文件夹的显示:共享路径和盘符路径用反斜杠,其余用正斜杠;子文件夹两种斜杠都认,
57
+ * 空段去掉。只给人看,不参与任何校验。
58
+ */
59
+ export declare function folderPreview(rootPath: string, folder: string): string;
60
+ /** 三种命名规则各一个示例路径(相对文件夹)。示例名与语言无关,所以用英文。 */
61
+ export declare function exampleFileName(rule: number, now: Date): string;
@@ -0,0 +1,53 @@
1
+ const a = { YearMonthOriginal: 0, BusinessPath: 1, DateGuid: 2 }, h = {
2
+ [a.YearMonthOriginal]: "filePath.namingRule.yearMonthOriginal",
3
+ [a.BusinessPath]: "filePath.namingRule.businessPath",
4
+ [a.DateGuid]: "filePath.namingRule.dateGuid"
5
+ }, d = { Reject: 0, Overwrite: 1 };
6
+ function m(t) {
7
+ return !t.readOnly && t.namingRule === a.BusinessPath && t.onConflict === d.Overwrite && t.uploadRoleIds.length === 0;
8
+ }
9
+ const p = /^[A-Za-z0-9._-]{1,64}$/;
10
+ function g(t) {
11
+ const n = t.split(",").map((e) => e.trim().toLowerCase()).filter(Boolean);
12
+ return n.some((e) => !/^\.[a-z0-9]{1,15}$/.test(e)) ? null : [...new Set(n)].join(",");
13
+ }
14
+ function s(t) {
15
+ const n = t.trim().replaceAll("/", "\\");
16
+ if (!n.startsWith("\\\\")) return "";
17
+ const [e, r] = n.slice(2).split("\\");
18
+ return e && r && e !== "." && e !== "?" ? e : "";
19
+ }
20
+ const u = (t, n) => t.toLowerCase() === n.toLowerCase();
21
+ function P(t, n, e) {
22
+ const r = (e ?? "").trim();
23
+ return r ? !u(s(t.rootPath), s(n)) || !u((t.userName ?? "").trim(), r) : !1;
24
+ }
25
+ function R(t, n, e, r) {
26
+ const i = s(t.rootPath);
27
+ if (!i || !u(i, s(n))) return null;
28
+ const o = (t.userName ?? "").trim(), l = (e ?? "").trim();
29
+ return l ? l !== o || r !== "" ? "change" : null : o ? "clear" : null;
30
+ }
31
+ function w(t, n) {
32
+ const e = t.trim(), r = s(e) !== "" || /^[A-Za-z]:/.test(e), i = r ? "\\" : "/", o = (r ? e.replaceAll("/", "\\") : e).replace(/[\\/]+$/, ""), l = n.split(/[\\/]/).map((f) => f.trim()).filter(Boolean);
33
+ return [o, ...l].join(i) || e;
34
+ }
35
+ const c = (t) => String(t).padStart(2, "0");
36
+ function b(t, n) {
37
+ const e = n.getFullYear();
38
+ return t === a.BusinessPath ? "template/label.btw" : t === a.DateGuid ? `${e}${c(n.getMonth() + 1)}${c(n.getDate())}/3f2a9c1e7b4d4e0a8c5d6f1a2b3c4d5e.pdf` : `${e}/${c(n.getMonth() + 1)}/report_a1b2c3d4.pdf`;
39
+ }
40
+ export {
41
+ p as CODE_PATTERN,
42
+ d as ConflictMode,
43
+ h as NAMING_RULE_LABEL_KEYS,
44
+ a as NamingRule,
45
+ R as credentialCascade,
46
+ b as exampleFileName,
47
+ w as folderPreview,
48
+ s as hostOf,
49
+ g as normalizeExtensions,
50
+ m as overwriteRisk,
51
+ P as passwordReentryRequired
52
+ };
53
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sources":["../../../../src/views/system/file-path/rules.ts"],"sourcesContent":["// 文件路径配置页的纯函数:校验与提示文案的素材。规则与后端保持一致,后端才是最终裁决。\n\n/** 文件落盘的命名规则(与后端 FilePathNamingRule 的值一致)。 */\nexport const NamingRule = { YearMonthOriginal: 0, BusinessPath: 1, DateGuid: 2 } as const\n\n/** 命名规则的显示名在语言包里的键。 */\nexport const NAMING_RULE_LABEL_KEYS: Record<number, string> = {\n [NamingRule.YearMonthOriginal]: 'filePath.namingRule.yearMonthOriginal',\n [NamingRule.BusinessPath]: 'filePath.namingRule.businessPath',\n [NamingRule.DateGuid]: 'filePath.namingRule.dateGuid',\n}\n\n/** 业务指定路径撞名时的处理(与后端 FilePathConflictMode 的值一致);其余命名规则不会撞名。 */\nexport const ConflictMode = { Reject: 0, Overwrite: 1 } as const\n\n/**\n * 业务指定路径 + 同名覆盖 + 没限制上传角色:任何登录用户都能覆盖这个文件夹里的同名文件,表单要给出警告。\n * 只读的行不收上传,谈不上覆盖。\n */\nexport function overwriteRisk(form: {\n namingRule: number\n onConflict: number\n readOnly: boolean\n uploadRoleIds: readonly unknown[]\n}): boolean {\n return (\n !form.readOnly &&\n form.namingRule === NamingRule.BusinessPath &&\n form.onConflict === ConflictMode.Overwrite &&\n form.uploadRoleIds.length === 0\n )\n}\n\n/** 编码:字母、数字、点、下划线、连字符,1–64 位。 */\nexport const CODE_PATTERN = /^[A-Za-z0-9._-]{1,64}$/\n\n/**\n * 后缀白名单规范化:去空白、转小写、去重,每项须是「点 + 1–15 位字母或数字」。\n * 格式不对返回 null;空输入是合法的空白名单,返回空串(是否必填由调用方按只读与否决定)。\n */\nexport function normalizeExtensions(input: string): string | null {\n const items = input\n .split(',')\n .map(s => s.trim().toLowerCase())\n .filter(Boolean)\n if (items.some(e => !/^\\.[a-z0-9]{1,15}$/.test(e))) return null\n return [...new Set(items)].join(',')\n}\n\n/**\n * 共享路径 `\\\\host\\share` 或 `//host/share` 里的主机名。不是共享路径(本地路径、只有主机没有共享名、\n * 设备路径 `\\\\?\\`)一律为空串,按「本机」算。与后端 FilePathRules.TryGetShare 的判定一致。\n */\nexport function hostOf(rootPath: string): string {\n const p = rootPath.trim().replaceAll('/', '\\\\')\n if (!p.startsWith('\\\\\\\\')) return ''\n const [host, share] = p.slice(2).split('\\\\')\n return host && share && host !== '.' && host !== '?' ? host : ''\n}\n\nconst same = (a: string, b: string) => a.toLowerCase() === b.toLowerCase()\n\n/**\n * 保存或测试连接时,密码留空会沿用已保存的密码,但主机或账号换了就不会(后端 CanReuseSavedPassword),\n * 修改时后端直接拒绝保存(44157),原来有没有设置密码都一样。\n * 同时满足才返回 true:新账号不为空(清空账号 = 改用后端运行身份,不需要密码);主机或账号变了。\n * 主机、账号都不区分大小写,账号先去首尾空白,null 与空串相同。\n */\nexport function passwordReentryRequired(\n original: { rootPath: string; userName?: string | null },\n rootPath: string,\n userName: string | null | undefined,\n): boolean {\n const account = (userName ?? '').trim()\n if (!account) return false\n return (\n !same(hostOf(original.rootPath), hostOf(rootPath)) ||\n !same((original.userName ?? '').trim(), account)\n )\n}\n\n/**\n * 修改一台文件服务器的账号或密码时,后端会把同一主机的其他文件服务器一起改成相同的账号和密码(Windows 对一台主机只接受一套凭据)。\n * 返回表单要给出的提示:'change' 同主机其他行一起改成这个账号和密码;'clear' 清空账号,整台主机改用后端运行身份;null 不影响别的行。\n * 只在主机没变时级联,换到另一台主机或本机路径时为 null。账号先去首尾空白、按原样比较:只差大小写也算改了,后端会统一写法。\n */\nexport function credentialCascade(\n original: { rootPath: string; userName?: string | null },\n rootPath: string,\n userName: string | null | undefined,\n password: string,\n): 'change' | 'clear' | null {\n const host = hostOf(original.rootPath)\n if (!host || !same(host, hostOf(rootPath))) return null\n const before = (original.userName ?? '').trim()\n const account = (userName ?? '').trim()\n if (!account) return before ? 'clear' : null\n return account !== before || password !== '' ? 'change' : null\n}\n\n/**\n * 完整文件夹的显示:共享路径和盘符路径用反斜杠,其余用正斜杠;子文件夹两种斜杠都认,\n * 空段去掉。只给人看,不参与任何校验。\n */\nexport function folderPreview(rootPath: string, folder: string): string {\n const root = rootPath.trim()\n const windows = hostOf(root) !== '' || /^[A-Za-z]:/.test(root)\n const sep = windows ? '\\\\' : '/'\n const base = (windows ? root.replaceAll('/', '\\\\') : root).replace(/[\\\\/]+$/, '')\n const segments = folder\n .split(/[\\\\/]/)\n .map(s => s.trim())\n .filter(Boolean)\n return [base, ...segments].join(sep) || root\n}\n\nconst two = (n: number) => String(n).padStart(2, '0')\n\n/** 三种命名规则各一个示例路径(相对文件夹)。示例名与语言无关,所以用英文。 */\nexport function exampleFileName(rule: number, now: Date): string {\n const year = now.getFullYear()\n if (rule === NamingRule.BusinessPath) return 'template/label.btw'\n if (rule === NamingRule.DateGuid) {\n return `${year}${two(now.getMonth() + 1)}${two(now.getDate())}/3f2a9c1e7b4d4e0a8c5d6f1a2b3c4d5e.pdf`\n }\n return `${year}/${two(now.getMonth() + 1)}/report_a1b2c3d4.pdf`\n}\n"],"names":["NamingRule","NAMING_RULE_LABEL_KEYS","ConflictMode","overwriteRisk","form","CODE_PATTERN","normalizeExtensions","input","items","s","hostOf","rootPath","p","host","share","same","a","b","passwordReentryRequired","original","userName","account","credentialCascade","password","before","folderPreview","folder","root","windows","sep","base","segments","two","n","exampleFileName","rule","now","year"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-admin-web",
3
- "version": "10.26.0",
3
+ "version": "10.28.0",
4
4
  "description": "SmartAdmin 前端内核:布局、路由、鉴权、内置系统页与共享组件,配合 SmartAdmin NuGet 包使用",
5
5
  "keywords": [
6
6
  "smartadmin",