dsh-long-plugins 1.3.9 → 1.3.10
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.
- package/README.md +14 -1
- package/THIRD_PARTY_NOTICES.md +7 -0
- package/client/client.js +29 -9
- package/client/vendor/xlsx.full.min.js +22 -0
- package/lib/index.js +331 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ upload manager, workspace **输出文件** section, top-bar **文件** browser w
|
|
|
5
5
|
**技能文档** (skill docs) browser, DeepSeek account balance, and **turn ruler (session navigation)** — all in one installable plugin.
|
|
6
6
|
Also ships an auto-repair install that relinks DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink).
|
|
7
7
|
|
|
8
|
-
一个插件整合 DSH Web 的常用增强:上传管理、顶栏「📂文件」工作区浏览 + 文件预览(Word、PPT 格式渲染)、工作区「输出文件」面板、技能文档浏览、账户余额显示。并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。会话记录导航。
|
|
8
|
+
一个插件整合 DSH Web 的常用增强:上传管理、顶栏「📂文件」工作区浏览 + 文件预览(Word、PPT、Excel 格式渲染)、工作区「输出文件」面板、技能文档浏览、账户余额显示。并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。会话记录导航。
|
|
9
9
|
|
|
10
10
|
## Features / 功能
|
|
11
11
|
|
|
@@ -95,6 +95,8 @@ Agent 可直接调用 `md2docx` 工具,把 Markdown 转成带页码页脚的 W
|
|
|
95
95
|
/api/dsh-uploads/workspace-file/save save edited content (POST)
|
|
96
96
|
/api/dsh-uploads/docx-preview Word (.docx) real render page (browser-side docx-preview)
|
|
97
97
|
/api/dsh-uploads/docx-preview-asset serve docx-preview / jszip vendor libs
|
|
98
|
+
/api/dsh-uploads/xlsx-preview Excel (.xlsx) static render page (browser-side SheetJS → table)
|
|
99
|
+
/api/dsh-uploads/xlsx-preview-asset serve SheetJS (xlsx) vendor lib
|
|
98
100
|
/dsh-skill-docs/skill-docs skill docs list (grouped by skill)
|
|
99
101
|
/dsh-skill-docs/skill-doc preview / download
|
|
100
102
|
/dsh-skill-docs/skill-doc/save save (POST)
|
|
@@ -115,7 +117,18 @@ MIT
|
|
|
115
117
|
- `JSZip` — 解压 Office 包 — **MIT**(或 GPLv3,本项目按 MIT 使用)
|
|
116
118
|
- `Chart.js` — PPT 内图表 — **MIT**
|
|
117
119
|
- `PptxViewJS` — PowerPoint 真实预览 — **MIT**
|
|
120
|
+
- `SheetJS`(xlsx.full.min.js) — Excel 真实预览 — **Apache-2.0**
|
|
118
121
|
- npm 依赖:`mammoth`(BSD-2-Clause)、`exceljs`(MIT)
|
|
119
122
|
|
|
120
123
|
完整的版权声明与来源见 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。
|
|
121
124
|
|
|
125
|
+
## Changelog / 更新记录
|
|
126
|
+
|
|
127
|
+
### v1.3.10
|
|
128
|
+
- 新增 `.xlsx` 浏览器端预览:用 SheetJS 解析并显示为表格(行列标头、合并单元格、多工作表切换),预览支持 − / + / 适合宽度缩放,默认整表适配;浏览器端处理,不占用 NAS 本地资源。
|
|
129
|
+
- 工作区浏览、工作区文件、上传文件列表中的 `.xlsx` 均接入该预览页。
|
|
130
|
+
- `.csv` / `.tsv` 保留表格预览(首行作表头)。
|
|
131
|
+
- 文件列表按钮顺序调整:工作区浏览页为 复制路径、重命名、下载、预览;上传/输出文件面板为 复制路径、删除、下载、预览。
|
|
132
|
+
- 「上传文件」「输出文件」新增「开启删除」开关:关闭时删除按钮置灰禁用,开启后可删除;上传文件的「复制路径」不再使用删除红色。
|
|
133
|
+
- 手机端(≤640px)文件列表顶部操作行保持单行:搜索/日期等宽、刷新/开关靠右。
|
|
134
|
+
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -34,6 +34,13 @@ copyright notices and sources are listed here.
|
|
|
34
34
|
- npm: <https://www.npmjs.com/package/pptxviewjs>
|
|
35
35
|
- CDN / source build: <https://cdn.jsdelivr.net/npm/pptxviewjs@1.1.9>
|
|
36
36
|
|
|
37
|
+
### SheetJS (`xlsx.full.min.js`)
|
|
38
|
+
- Used for: real browser-side Excel (`.xlsx`) preview
|
|
39
|
+
- License: **Apache-2.0**
|
|
40
|
+
- Copyright: SheetJS Community Edition
|
|
41
|
+
- npm: <https://www.npmjs.com/package/xlsx>
|
|
42
|
+
- CDN / source build: <https://cdn.jsdelivr.net/npm/xlsx@0.18.5>
|
|
43
|
+
|
|
37
44
|
## Runtime npm dependencies (not vendored into the package)
|
|
38
45
|
|
|
39
46
|
These are declared as `dependencies` and resolved on the host at install time;
|
package/client/client.js
CHANGED
|
@@ -718,6 +718,7 @@ window.__ModuleLoader__.load({
|
|
|
718
718
|
const [previewMaximized, setPreviewMaximized] = React.useState(false)
|
|
719
719
|
const [dayFilter, setDayFilter] = React.useState('')
|
|
720
720
|
const [search, setSearch] = React.useState('')
|
|
721
|
+
const [deleteEnabled, setDeleteEnabled] = React.useState(false)
|
|
721
722
|
|
|
722
723
|
async function refresh() {
|
|
723
724
|
setState((current) => ({ ...current, loading: true, error: '' }))
|
|
@@ -852,6 +853,12 @@ window.__ModuleLoader__.load({
|
|
|
852
853
|
{ type: 'button', className: 'dsh-upload-refresh', disabled: state.loading, onClick: refresh },
|
|
853
854
|
state.loading ? '刷新中…' : '刷新',
|
|
854
855
|
),
|
|
856
|
+
React.createElement(
|
|
857
|
+
'label',
|
|
858
|
+
{ className: 'dsh-upload-del-toggle' },
|
|
859
|
+
React.createElement('input', { type: 'checkbox', checked: deleteEnabled, onChange: (e) => setDeleteEnabled(e.target.checked) }),
|
|
860
|
+
'开启删除',
|
|
861
|
+
),
|
|
855
862
|
),
|
|
856
863
|
),
|
|
857
864
|
React.createElement(
|
|
@@ -941,11 +948,9 @@ window.__ModuleLoader__.load({
|
|
|
941
948
|
React.createElement(
|
|
942
949
|
'div',
|
|
943
950
|
{ className: 'dsh-upload-actions' },
|
|
944
|
-
React.createElement('button', { type: 'button', className: 'dsh-upload-preview', onClick: () => previewFile(file.name) }, '预览'),
|
|
945
|
-
React.createElement('a', { href: downloadUrl(file.name), download: file.name }, '下载'),
|
|
946
951
|
React.createElement(
|
|
947
952
|
'button',
|
|
948
|
-
{ type: 'button', onClick: () => {
|
|
953
|
+
{ type: 'button', className: 'dsh-upload-copy', onClick: () => {
|
|
949
954
|
const s = String(file.path || file.name)
|
|
950
955
|
const base = state.root ? String(state.root).replace(/\/[^/]*$/, '') : ''
|
|
951
956
|
copyText(base && s.indexOf(base) === 0 ? s.slice(base.length).replace(/^\/+/, '') : s)
|
|
@@ -954,9 +959,11 @@ window.__ModuleLoader__.load({
|
|
|
954
959
|
),
|
|
955
960
|
React.createElement(
|
|
956
961
|
'button',
|
|
957
|
-
{ type: 'button', disabled: deleting === file.name, onClick: () => remove(file.name) },
|
|
962
|
+
{ type: 'button', disabled: !deleteEnabled || deleting === file.name, onClick: () => remove(file.name) },
|
|
958
963
|
deleting === file.name ? '删除中…' : '删除',
|
|
959
964
|
),
|
|
965
|
+
React.createElement('a', { href: downloadUrl(file.name), download: file.name }, '下载'),
|
|
966
|
+
React.createElement('button', { type: 'button', className: 'dsh-upload-preview', onClick: () => previewFile(file.name) }, '预览'),
|
|
960
967
|
),
|
|
961
968
|
)),
|
|
962
969
|
)),
|
|
@@ -1024,8 +1031,13 @@ window.__ModuleLoader__.load({
|
|
|
1024
1031
|
.dsh-upload-file-meta{flex:none;color:var(--dsw-alias-label-tertiary);font-size:12px}
|
|
1025
1032
|
.dsh-upload-actions{display:flex;flex:none;gap:7px}
|
|
1026
1033
|
.dsh-upload-actions button{color:var(--dsw-alias-state-error-primary)}
|
|
1034
|
+
.dsh-upload-actions button.dsh-upload-copy{color:var(--dsw-alias-label-primary)}
|
|
1035
|
+
.dsh-upload-actions button:disabled{opacity:.5;cursor:not-allowed;color:var(--dsw-alias-label-tertiary)}
|
|
1036
|
+
.dsh-upload-del-toggle{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;user-select:none}
|
|
1037
|
+
.dsh-upload-del-toggle input{accent-color:var(--dsw-alias-state-business-primary);cursor:pointer}
|
|
1038
|
+
.dsh-ws-del:disabled{opacity:.5;cursor:not-allowed;color:var(--dsw-alias-label-tertiary)!important}
|
|
1027
1039
|
.dsh-upload-actions a,.dsh-upload-actions button{white-space:nowrap}
|
|
1028
|
-
@media (max-width:640px){.dsh-upload-row{align-items:stretch;flex-direction:column;gap:4px}.dsh-upload-file-name{white-space:normal;word-break:break-all}.dsh-upload-actions{width:100%;display:flex;gap:6px}.dsh-upload-actions a,.dsh-upload-actions button{flex:1;text-align:center;white-space:nowrap;padding:6px 4px}.dsh-upload-chip{min-width:160px}.dsh-upload-settings-head{flex-direction:column;align-items:stretch;gap:10px}.dsh-upload-head-actions{width:100%;justify-content:flex-
|
|
1040
|
+
@media (max-width:640px){.dsh-upload-row{align-items:stretch;flex-direction:column;gap:4px}.dsh-upload-file-name{white-space:normal;word-break:break-all}.dsh-upload-actions{width:100%;display:flex;gap:6px}.dsh-upload-actions a,.dsh-upload-actions button{flex:1;text-align:center;white-space:nowrap;padding:6px 4px}.dsh-upload-chip{min-width:160px}.dsh-upload-settings-head{flex-direction:column;align-items:stretch;gap:10px}.dsh-upload-head-actions{width:100%;flex-wrap:nowrap;justify-content:flex-start}.dsh-upload-head-actions .dsh-searchpop,.dsh-upload-head-actions .dsh-datefilter{flex:1 1 0;min-width:0}.dsh-upload-head-actions .dsh-upload-refresh{flex:none;text-align:center;padding:7px 8px;max-width:none}.dsh-upload-head-actions .dsh-upload-del-toggle{flex:none;white-space:nowrap;padding:0 4px}}
|
|
1029
1041
|
.dsh-ws-folder:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
1030
1042
|
.dsh-ws-file-type{flex:none;font-size:10px;line-height:14px;padding:1px 6px;border-radius:5px;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);white-space:nowrap}
|
|
1031
1043
|
.dsh-upload-preview-del{color:var(--dsw-alias-state-error-primary)!important}
|
|
@@ -1068,6 +1080,7 @@ window.__ModuleLoader__.load({
|
|
|
1068
1080
|
const [collapsed, setCollapsed] = React.useState({})
|
|
1069
1081
|
const [dayFilter, setDayFilter] = React.useState('')
|
|
1070
1082
|
const [search, setSearch] = React.useState('')
|
|
1083
|
+
const [deleteEnabled, setDeleteEnabled] = React.useState(false)
|
|
1071
1084
|
const [copied, setCopied] = React.useState(false)
|
|
1072
1085
|
const [editing, setEditing] = React.useState(false)
|
|
1073
1086
|
const [edited, setEdited] = React.useState('')
|
|
@@ -1129,6 +1142,9 @@ window.__ModuleLoader__.load({
|
|
|
1129
1142
|
} else if (/\.pptx$/i.test(path)) {
|
|
1130
1143
|
// pptx:走 PptxViewJS 真实渲染页(浏览器端 Canvas 渲染,所见即所得)。
|
|
1131
1144
|
setPreview({ path, name: data.name, url: '/api/dsh-uploads/pptx-preview?path=' + encodeURIComponent(path) })
|
|
1145
|
+
} else if (/\.xlsx$/i.test(path)) {
|
|
1146
|
+
// xlsx:走 x-spreadsheet 真实渲染页(浏览器端解析 xlsx,所见即所得)。
|
|
1147
|
+
setPreview({ path, name: data.name, url: '/api/dsh-uploads/xlsx-preview?path=' + encodeURIComponent(path) })
|
|
1132
1148
|
} else {
|
|
1133
1149
|
setPreview(data)
|
|
1134
1150
|
}
|
|
@@ -1267,6 +1283,10 @@ window.__ModuleLoader__.load({
|
|
|
1267
1283
|
React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', minWidth: 0 } },
|
|
1268
1284
|
React.createElement(SearchPopup, { value: search, onChange: setSearch, placeholder: '搜索文件名…' }),
|
|
1269
1285
|
React.createElement(DateFilter, { value: dayFilter, onChange: setDayFilter, placeholder: '选择日期' }),
|
|
1286
|
+
React.createElement('label', { className: 'dsh-upload-del-toggle' },
|
|
1287
|
+
React.createElement('input', { type: 'checkbox', checked: deleteEnabled, onChange: (e) => setDeleteEnabled(e.target.checked) }),
|
|
1288
|
+
'开启删除',
|
|
1289
|
+
),
|
|
1270
1290
|
),
|
|
1271
1291
|
error !== null && React.createElement('div', { style: { fontSize: 12, color: 'var(--dsw-alias-state-error-primary)' } }, error),
|
|
1272
1292
|
groups === null && error === null && React.createElement('div', { style: metaStyle }, '加载中…'),
|
|
@@ -1299,10 +1319,10 @@ window.__ModuleLoader__.load({
|
|
|
1299
1319
|
React.createElement(
|
|
1300
1320
|
'div',
|
|
1301
1321
|
{ className: 'dsh-ws-actions', style: { display: 'flex', gap: 6, flex: 'none' } },
|
|
1302
|
-
React.createElement('button', { type: 'button', style: btnStyle, disabled: busy, onClick: () => openPreview(f.path) }, '预览'),
|
|
1303
|
-
React.createElement('a', { href: '/api/dsh-uploads/workspace-file?path=' + encodeURIComponent(f.path) + '&download=1', download: f.name, style: btnStyle }, '下载'),
|
|
1304
1322
|
React.createElement('button', { type: 'button', style: btnStyle, disabled: busy, onClick: () => copyText(f.path) }, '复制路径'),
|
|
1305
|
-
React.createElement('button', { type: 'button', style: delStyle, disabled: busy, onClick: () => doDelete(f.path) }, '删除'),
|
|
1323
|
+
React.createElement('button', { type: 'button', className: 'dsh-ws-del', style: delStyle, disabled: !deleteEnabled || busy, onClick: () => doDelete(f.path) }, '删除'),
|
|
1324
|
+
React.createElement('a', { href: '/api/dsh-uploads/workspace-file?path=' + encodeURIComponent(f.path) + '&download=1', download: f.name, style: btnStyle }, '下载'),
|
|
1325
|
+
React.createElement('button', { type: 'button', style: btnStyle, disabled: busy, onClick: () => openPreview(f.path) }, '预览'),
|
|
1306
1326
|
),
|
|
1307
1327
|
)),
|
|
1308
1328
|
)),
|
|
@@ -1320,7 +1340,7 @@ window.__ModuleLoader__.load({
|
|
|
1320
1340
|
editing && React.createElement('button', { type: 'button', style: btnStyle, disabled: busy, onClick: doSave }, savedFlash ? '已保存' : '保存'),
|
|
1321
1341
|
React.createElement('button', { type: 'button', style: btnStyle, onClick: copyContent }, copied ? '已复制' : '复制全部'),
|
|
1322
1342
|
(preview.url !== void 0 || preview.officeHtml !== void 0 || preview.mdHtml !== void 0) && preview.loading !== true && React.createElement('a', { href: '/api/dsh-uploads/workspace-file?path=' + encodeURIComponent(preview.path) + '&download=1', download: preview.name, style: { ...btnStyle, color: 'var(--dsw-alias-state-business-primary)' } }, '下载'),
|
|
1323
|
-
(preview.url !== void 0 || preview.officeHtml !== void 0 || preview.mdHtml !== void 0) && preview.loading !== true && React.createElement('a', { href: '/api/dsh-uploads/workspace-preview?path=' + encodeURIComponent(preview.path), target: '_blank', rel: 'noopener noreferrer', style: { ...btnStyle, color: 'var(--dsw-alias-state-business-primary)' } }, '打开'),
|
|
1343
|
+
(preview.url !== void 0 || preview.officeHtml !== void 0 || preview.mdHtml !== void 0) && preview.loading !== true && React.createElement('a', { href: preview.url !== void 0 ? preview.url : '/api/dsh-uploads/workspace-preview?path=' + encodeURIComponent(preview.path), target: '_blank', rel: 'noopener noreferrer', style: { ...btnStyle, color: 'var(--dsw-alias-state-business-primary)' } }, '打开'),
|
|
1324
1344
|
React.createElement('button', { type: 'button', style: delStyle, disabled: busy, onClick: () => doDelete(preview.path) }, '删除'),
|
|
1325
1345
|
React.createElement('button', { type: 'button', style: btnStyle, onClick: () => setMaximized((m) => !m) }, maximized ? '还原' : '放大'),
|
|
1326
1346
|
React.createElement('button', { type: 'button', style: btnStyle, onClick: () => setPreview(null) }, '关闭'),
|