diff --git a/package.json b/package.json index 595983853..e2b3c28dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sub-store-front-end", - "version": "2.14.33", + "version": "2.14.34", "private": true, "scripts": { "dev": "vite --host", diff --git a/src/api/artifacts/index.ts b/src/api/artifacts/index.ts index fdecbe038..f1cf624f4 100644 --- a/src/api/artifacts/index.ts +++ b/src/api/artifacts/index.ts @@ -11,13 +11,13 @@ export function useArtifactsApi() { }, getOneArtifact: (name: string): AxiosPromise => { return request({ - url: `/api/artifact/${name}`, + url: `/api/artifact/${encodeURIComponent(name)}`, method: 'get', }); }, syncOneArtifact: (name: string): AxiosPromise => { return request({ - url: `/api/sync/artifact/${name}`, + url: `/api/sync/artifact/${encodeURIComponent(name)}`, method: 'get', }); }, @@ -30,14 +30,14 @@ export function useArtifactsApi() { }, editArtifact: (name: string, data: Artifact): AxiosPromise => { return request({ - url: `/api/artifact/${name}`, + url: `/api/artifact/${encodeURIComponent(name)}`, method: 'patch', data, }); }, deleteArtifact: (name: string): AxiosPromise => { return request({ - url: `/api/artifact/${name}`, + url: `/api/artifact/${encodeURIComponent(name)}`, method: 'delete', }); }, diff --git a/src/api/files/index.ts b/src/api/files/index.ts new file mode 100644 index 000000000..24208b50d --- /dev/null +++ b/src/api/files/index.ts @@ -0,0 +1,51 @@ +import request from '@/api'; +import { AxiosPromise } from 'axios'; + +export function useFilesApi() { + return { + getFiles: (): AxiosPromise => { + return request({ + url: '/api/files', + method: 'get', + }); + }, + getWholeFiles: (): AxiosPromise => { + return request({ + url: '/api/wholeFiles', + method: 'get', + }); + }, + getOneFile: (name: string): AxiosPromise => { + return request({ + url: `/api/file/${encodeURIComponent(name)}`, + method: 'get', + }); + }, + getWholeFile: (name: string): AxiosPromise => { + return request({ + url: `/api/wholeFile/${encodeURIComponent(name)}`, + method: 'get', + }); + }, + createFile: (data: any): AxiosPromise => { + return request({ + url: '/api/files', + method: 'post', + data, + }); + }, + editFile: (name: string, data: any): AxiosPromise => { + return request({ + url: `/api/file/${encodeURIComponent(name)}`, + method: 'patch', + data, + }); + }, + deleteFile: (name: string): AxiosPromise => { + return request({ + url: `/api/file/${encodeURIComponent(name)}`, + method: 'delete', + }); + }, + }; +} diff --git a/src/assets/styles/global.scss b/src/assets/styles/global.scss index b62bc1758..2e70c3a67 100644 --- a/src/assets/styles/global.scss +++ b/src/assets/styles/global.scss @@ -75,6 +75,18 @@ img { font-weight: bold; line-height: 2; } +// .nut-icon-order:before { +// content: "\e697"; +// } +// .nut-icon-edit:before { +// content: "\e667"; +// } +// .nut-icon-find:before { +// content: "\e661"; +// } +.nut-icon-category:before { + content: "\e662"; +} .nut-icon-issue:before { content: '\e6b1'; } diff --git a/src/components/FileListItem.vue b/src/components/FileListItem.vue new file mode 100644 index 000000000..2e1ad6279 --- /dev/null +++ b/src/components/FileListItem.vue @@ -0,0 +1,548 @@ + + + + + diff --git a/src/components/TabBar.vue b/src/components/TabBar.vue index d8642dc0d..ccf9a1add 100644 --- a/src/components/TabBar.vue +++ b/src/components/TabBar.vue @@ -8,6 +8,7 @@ size="22px" > + { diff --git a/src/locales/en.ts b/src/locales/en.ts index a4a97adc8..7184ad0e4 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -21,9 +21,11 @@ export default { }, pagesTitle: { sub: 'Management', + file: 'File', sync: 'Sync Subscription', my: 'My Profile', subEditor: 'Subscription Editor', + fileEditor: 'File Editor', themeSetting: 'Theme Setting', moreSetting: 'More Setting', apiSetting: 'Backend Setting', @@ -58,6 +60,14 @@ export default { desc: 'Back to Home Page', backendDesc: 'If you are seeing this, it is probably due to a routing interception issue on the front end of your browser. You can force a refresh to see it or use the link directly without affecting the use of this link.', }, + filePage: { + deleteFile: { + succeedNotify: 'Successfully deleted!', + }, + content: { + placeholder: 'The content of the file' + } + }, // subscription management page subPage: { addSubTitle: 'Which type you want to create?', @@ -91,8 +101,8 @@ export default { noExpiresInfo: 'No expires info', }, deleteSub: { - title: 'Delete Subscription', - desc: 'Are you sure to delete subscription {displayName}? \nDeleted cannot be restored!', + title: 'Delete', + desc: 'Are you sure to delete {displayName}? \nDeleted cannot be restored!', succeedNotify: 'Successfully deleted!', btn: { confirm: 'Delete', @@ -160,7 +170,7 @@ export default { }, displayName: { label: 'Display Name', - placeholder: 'The display name for the subscription', + placeholder: 'The display name', }, source: { label: 'Source', diff --git a/src/locales/zh.ts b/src/locales/zh.ts index 074536297..f41715bb0 100644 --- a/src/locales/zh.ts +++ b/src/locales/zh.ts @@ -21,9 +21,11 @@ export default { }, pagesTitle: { sub: '订阅管理', + file: '文件管理', sync: '同步订阅', my: '我的', subEditor: '订阅编辑', + fileEditor: '文件编辑', themeSetting: '主题设置', moreSetting: '更多设置', apiSetting: '后端设置', @@ -58,6 +60,18 @@ export default { desc: '回首页', backendDesc: '如果你看到这个 可能是因为浏览器前端路由拦截的问题 可以强制刷新查看或直接使用该链接 不影响此链接的使用', }, + filePage: { + deleteFile: { + succeedNotify: '删除文件成功', + }, + content: { + placeholder: '填入文件内容' + }, + copyNotify: { + succeed: '复制文件链接成功', + failed: '复制文件链接失败\n{e}', + } + }, // 订阅管理页 subPage: { addSubTitle: '选择要创建的订阅类型', @@ -90,9 +104,9 @@ export default { noExpiresInfo: '无有效期信息', }, deleteSub: { - title: '删除订阅', - desc: '是否确认删除订阅 {displayName}?删除后不可恢复!', - succeedNotify: '删除订阅成功!', + title: '删除', + desc: '是否确认删除 {displayName}?删除后不可恢复!', + succeedNotify: '删除成功!', btn: { confirm: '确认删除', cancel: '取消', @@ -155,12 +169,12 @@ export default { name: { label: '名称', placeholder: '唯一的标识名称(请勿包含 / )', - isEmpty: '订阅名称不能为空', - isInvalid: '订阅名称已存在或不合法' + isEmpty: '名称不能为空', + isInvalid: '名称已存在或不合法' }, displayName: { label: '显示名称', - placeholder: '输入展示的订阅名称', + placeholder: '输入展示的名称', }, source: { label: '来源', diff --git a/src/router/index.ts b/src/router/index.ts index 045728204..a6ab4547e 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -7,6 +7,9 @@ import { initStores } from '@/utils/initApp'; import My from '@/views/My.vue'; import NotFound from '@/views/NotFound.vue'; +import File from '@/views/File.vue'; +import FileEditor from '@/views/FileEditor.vue'; + import Sub from '@/views/Sub.vue'; import SubEditor from '@/views/SubEditor.vue'; @@ -68,6 +71,24 @@ const router = createRouter({ needNavBack: false, }, }, + { + path: '/files', + component: File, + meta: { + title: 'file', + needTabBar: true, + needNavBack: false, + }, + }, + { + path: '/edit/:editType(files)/:id', + component: FileEditor, + meta: { + title: 'fileEditor', + needTabBar: false, + needNavBack: true, + }, + }, { path: '/edit/:editType(subs|collections)/:id', component: SubEditor, diff --git a/src/store/subs.ts b/src/store/subs.ts index b668f05f9..575f46fee 100644 --- a/src/store/subs.ts +++ b/src/store/subs.ts @@ -1,4 +1,5 @@ import { useSubsApi } from '@/api/subs'; +import { useFilesApi } from '@/api/files'; import i18n from '@/locales'; import { useAppNotifyStore } from '@/store/appNotify'; import { getFlowsUrlList } from '@/utils/getFlowsUrlList'; @@ -6,6 +7,7 @@ import { defineStore } from 'pinia'; const { t } = i18n.global; const subsApi = useSubsApi(); +const filesApi = useFilesApi(); export const useSubsStore = defineStore('subsStore', { state: (): SubsStoreState => { @@ -13,6 +15,7 @@ export const useSubsStore = defineStore('subsStore', { subs: [], collections: [], flows: {}, + files: [], }; }, getters: { @@ -26,16 +29,24 @@ export const useSubsStore = defineStore('subsStore', { ({ collections }): GetOne => (name: string): Collection => collections.find(collection => collection.name === name), + hasFiles: ({ files }): boolean => files.length > 0, + getOneFile: + ({ files }): GetOne => + (name: string) => + files.find(file => file.name === name), }, actions: { async fetchSubsData() { - Promise.all([subsApi.getSubs(), subsApi.getCollections()]).then(res => { + Promise.all([subsApi.getSubs(), subsApi.getCollections(), filesApi.getWholeFiles()]).then(res => { if ('data' in res[0].data) { this.subs = res[0].data.data; } if ('data' in res[1].data) { this.collections = res[1].data.data; } + if ('data' in res[2].data) { + this.files = res[2].data.data; + } }); }, async updateOneData(type: string, name: string) { @@ -44,6 +55,8 @@ export const useSubsStore = defineStore('subsStore', { res = await subsApi.getOne('sub', name); } else if (type === 'collections') { res = await subsApi.getOne('collection', name); + } else if (type === 'files') { + res = await filesApi.getWholeFile(name); } if (res?.data?.status === 'success') { const index = this[type].findIndex(item => item.name === name); @@ -84,5 +97,25 @@ export const useSubsStore = defineStore('subsStore', { }); } }, + async fetchFiles() { + Promise.all([filesApi.getWholeFiles()]).then(res => { + if ('data' in res[0].data) { + this.files = res[0].data.data; + } + }); + }, + + async deleteFile(name: string) { + const { showNotify } = useAppNotifyStore(); + + const { data } = await filesApi.deleteFile(name); + if (data.status === 'success') { + await this.fetchFiles(); + showNotify({ + type: 'danger', + title: t('filePage.deleteFile.succeedNotify'), + }); + } + }, }, }); diff --git a/src/types/store/subsStore.d.ts b/src/types/store/subsStore.d.ts index 9244e7b0d..d42ca0512 100644 --- a/src/types/store/subsStore.d.ts +++ b/src/types/store/subsStore.d.ts @@ -2,6 +2,7 @@ interface SubsStoreState { subs: Sub[]; collections: Collection[]; flows: FlowsDict; + files: any[]; } interface FlowsDict { diff --git a/src/views/File.vue b/src/views/File.vue new file mode 100644 index 000000000..863b49b43 --- /dev/null +++ b/src/views/File.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/src/views/FileEditor.vue b/src/views/FileEditor.vue new file mode 100644 index 000000000..9f5b27c5e --- /dev/null +++ b/src/views/FileEditor.vue @@ -0,0 +1,376 @@ + + + + + diff --git a/src/views/Sub.vue b/src/views/Sub.vue index e30cd85bc..9133c3592 100644 --- a/src/views/Sub.vue +++ b/src/views/Sub.vue @@ -250,7 +250,7 @@ const changeSort = async ( if (env.value.version > "2.14.48") { console.log(`new sort > v2.14.48`); const nameSortArray = dataValue.map((k: { name: string }) => k.name); - console.log(nameSortArray); + // console.log(nameSortArray); sortDataRes = await subsApi.newSortSub( subColl, JSON.parse(JSON.stringify(toRaw(nameSortArray))) diff --git a/src/views/Sync.vue b/src/views/Sync.vue index c43e076af..0e302bd13 100644 --- a/src/views/Sync.vue +++ b/src/views/Sync.vue @@ -240,12 +240,12 @@ const changeArtifacts = async () => { if (env.value.version > "2.14.48") { console.log("new sort > v2.14.48"); const nameSortArray = artifacts.value.map((k) => k.name); - console.log(nameSortArray); + // console.log(nameSortArray); sortArtifacts = await subsApi.newSortSub( "artifacts", JSON.parse(JSON.stringify(toRaw(nameSortArray))) ); - console.log(JSON.stringify(sortArtifacts)); + // console.log(JSON.stringify(sortArtifacts)); } else { console.log("old sort < v2.14.48"); sortArtifacts = await subsApi.sortSub(