commit 7acef4c56952a29b15cd82e583f3bd8b4adbab60 Author: zhangjianjun Date: Mon Mar 16 10:35:51 2026 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a020562 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# Logs +logs +.vscode +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* +package-lock.json +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local +/cypress/videos/ +/cypress/screenshots/ +/service/dev +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +yarn.lock +*.tsbuildinfo +*.env +src +sub +rbBuildAll.bat \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..456cf61 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM registry.cn-shanghai.aliyuncs.com/devcon/node:18 +RUN git clone https://wujiefeng:sange666@git.u8t.cn/batiao/cy-admin.git +RUN mv cy-admin /app +ADD . /app/src +WORKDIR /app +RUN mkdir /app/log +RUN cd /app && \ + chmod +x start.sh && \ + npm config set registry https://registry.npmmirror.com/ && \ + npm run installModels && \ + npm run build +EXPOSE 9290 +CMD [ "/app/start.sh" ] + + diff --git a/api/admin/list.ts b/api/admin/list.ts new file mode 100644 index 0000000..172a9e0 --- /dev/null +++ b/api/admin/list.ts @@ -0,0 +1,36 @@ +import Request from "lib/utils/requests"; +import roleApi from './role'; +export default { + getDataList(params: any) { + return Request({ + url: 'yt/user', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/user', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/user', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/user', + method: 'post', + data: params + }) + }, + getRoleList() { + return roleApi.getDataList() + } +} + diff --git a/api/admin/role.ts b/api/admin/role.ts new file mode 100644 index 0000000..7db3a02 --- /dev/null +++ b/api/admin/role.ts @@ -0,0 +1,35 @@ +import Request from "lib/utils/requests"; +import sourceApi from '../config/source'; + +export default { + getDataList() { + return Request({ + url: 'yt/role', + method: 'get', + params: {} + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/role', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/role', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/role', + method: 'post', + data: params + }) + }, + getResources: sourceApi.getDataList, +} + diff --git a/api/app.ts b/api/app.ts new file mode 100644 index 0000000..b7938e4 --- /dev/null +++ b/api/app.ts @@ -0,0 +1,17 @@ +import Request from "lib/utils/requests"; + +export default { + upload(data: any) { + return Request({ + url: "/admin/cmp_upload", + method: "post", + data, + params: { + expire: 24 * 30 * 12 * 10, + }, + headers: { + "Content-Type": "multipart/form-data", + }, + }).then(res => ({ data: {url: res.data} })) + }, +}; diff --git a/api/common.ts b/api/common.ts new file mode 100644 index 0000000..d4137a1 --- /dev/null +++ b/api/common.ts @@ -0,0 +1,63 @@ +import Request from "lib/utils/requests"; + +// 翻译 +export const translateApi = { + translate(params: { text: string, from?: string, to?: string }) { + return Request({ + url: "yt/translate", + method: "get", + params, + }) + }, +} + +// 分类 +export const categoryApi = { + getDataList(params: any) { + return Request({ + url: 'yt/category', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/category', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/category', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/category', + method: 'post', + data: params + }) + }, +} + + +// 上传 +export const uploadApi = { + upload(params: any) { + return Request({ + url: 'yt/upload', + method: 'post', + data: params, + params: { + expire: 24 * 30 * 12 * 10, + }, + headers: { + "Content-Type": "multipart/form-data", + }, + }) + }, +} + diff --git a/api/config/list.ts b/api/config/list.ts new file mode 100644 index 0000000..bbff9f1 --- /dev/null +++ b/api/config/list.ts @@ -0,0 +1,32 @@ +import Request from "lib/utils/requests"; +export default { + getDataList(params: any) { + return Request({ + url: 'yt/page', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/page', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/page', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/page', + method: 'post', + data: params + }) + }, +} + diff --git a/api/config/source.ts b/api/config/source.ts new file mode 100644 index 0000000..a399828 --- /dev/null +++ b/api/config/source.ts @@ -0,0 +1,32 @@ +import Request from "lib/utils/requests"; +export default { + getDataList(params: any) { + return Request({ + url: 'yt/resource', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/resource', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/resource', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/resource', + method: 'post', + data: params + }) + }, +} + diff --git a/api/document/list.ts b/api/document/list.ts new file mode 100644 index 0000000..580ef6a --- /dev/null +++ b/api/document/list.ts @@ -0,0 +1,42 @@ +import Request from "lib/utils/requests"; +import { categoryApi, translateApi, uploadApi } from '../common'; +export default { + getDataList(params: any) { + return Request({ + url: 'yt/doc', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/doc', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/doc', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/doc', + method: 'post', + data: params + }) + }, + getDetail(id: number | string) { + return Request({ + url: `yt/doc/${id}`, + method: 'get', + }) + }, + getCategoryList: categoryApi.getDataList, + ...translateApi, + ...uploadApi, +} + diff --git a/api/document/typesManage.ts b/api/document/typesManage.ts new file mode 100644 index 0000000..ac1d63e --- /dev/null +++ b/api/document/typesManage.ts @@ -0,0 +1,2 @@ +import { categoryApi } from "../common"; +export default categoryApi \ No newline at end of file diff --git a/api/history/list.ts b/api/history/list.ts new file mode 100644 index 0000000..6792d49 --- /dev/null +++ b/api/history/list.ts @@ -0,0 +1,42 @@ +import Request from "lib/utils/requests"; +import { categoryApi, translateApi } from '../common'; + +export default { + getDataList(params: any) { + return Request({ + url: 'yt/process', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/process', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/process', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/process', + method: 'post', + data: params + }) + }, + getDetail(id: number | string) { + return Request({ + url: `yt/process/${id}`, + method: 'get', + }) + }, + getCategoryList: categoryApi.getDataList, + ...translateApi +} + diff --git a/api/history/typesManage.ts b/api/history/typesManage.ts new file mode 100644 index 0000000..ac1d63e --- /dev/null +++ b/api/history/typesManage.ts @@ -0,0 +1,2 @@ +import { categoryApi } from "../common"; +export default categoryApi \ No newline at end of file diff --git a/api/jobs/list.ts b/api/jobs/list.ts new file mode 100644 index 0000000..7634871 --- /dev/null +++ b/api/jobs/list.ts @@ -0,0 +1,41 @@ +import Request from "lib/utils/requests"; +import { translateApi, categoryApi } from '../common'; +export default { + getDataList(params: any) { + return Request({ + url: 'yt/job', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/job', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/job', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/job', + method: 'post', + data: params + }) + }, + getDetail(id: number | string) { + return Request({ + url: `yt/job/${id}`, + method: 'get', + }) + }, + getCategoryList: categoryApi.getDataList, + ...translateApi +} + diff --git a/api/jobs/typesManage.ts b/api/jobs/typesManage.ts new file mode 100644 index 0000000..ac1d63e --- /dev/null +++ b/api/jobs/typesManage.ts @@ -0,0 +1,2 @@ +import { categoryApi } from "../common"; +export default categoryApi \ No newline at end of file diff --git a/api/login.ts b/api/login.ts new file mode 100644 index 0000000..4caf7dc --- /dev/null +++ b/api/login.ts @@ -0,0 +1,41 @@ +import Request from "lib/utils/requests"; + +export default { + login(data: any) { + return Request({ + url: 'yt/user/login', + method: 'post', + data: { + account: data.username, + password: data.password + }, + }) + }, + resetPassWord(data: any) { + return Request({ + url: "/admin/v2", + method: "put", + data + }) + }, + editorConfig(data: any) { + return Request({ + url: "/corp/config", + method: "put", + data + }) + }, + getConfig() { + return Request({ + url: "/corp/config", + method: "get" + }) + }, + flashRole(params: any) { + return Request({ + url: "/corp/flash/role", + method: "get", + params + }) + }, +} \ No newline at end of file diff --git a/api/news/list.ts b/api/news/list.ts new file mode 100644 index 0000000..5c0fa18 --- /dev/null +++ b/api/news/list.ts @@ -0,0 +1,43 @@ +import Request from "lib/utils/requests"; +import { translateApi, categoryApi, uploadApi } from '../common'; + +export default { + getDataList(params: any) { + return Request({ + url: 'yt/news', + method: 'get', + params + }) + }, + updateData(params: any) { + return Request({ + url: 'yt/news', + method: 'put', + data: params + }) + }, + deleteData(params: any) { + return Request({ + url: 'yt/news', + method: 'delete', + params: params + }) + }, + addData(params: any) { + return Request({ + url: 'yt/news', + method: 'post', + data: params + }) + }, + getDetail(id: number | string) { + return Request({ + url: `yt/news/${id}`, + method: 'get', + }) + }, + getCategoryList: categoryApi.getDataList, + ...translateApi, + ...uploadApi, +} + diff --git a/api/news/typesManage.ts b/api/news/typesManage.ts new file mode 100644 index 0000000..ac1d63e --- /dev/null +++ b/api/news/typesManage.ts @@ -0,0 +1,2 @@ +import { categoryApi } from "../common"; +export default categoryApi \ No newline at end of file diff --git a/beforeMount.ts b/beforeMount.ts new file mode 100644 index 0000000..e00a9b8 --- /dev/null +++ b/beforeMount.ts @@ -0,0 +1,5 @@ +import type { App } from 'vue' + +export default function BeforeMount(app:App){ + +} \ No newline at end of file diff --git a/components/In18FormDialog.vue b/components/In18FormDialog.vue new file mode 100644 index 0000000..d066b18 --- /dev/null +++ b/components/In18FormDialog.vue @@ -0,0 +1,544 @@ + + + + + diff --git a/components/JsonFormDialog.vue b/components/JsonFormDialog.vue new file mode 100644 index 0000000..0158b9d --- /dev/null +++ b/components/JsonFormDialog.vue @@ -0,0 +1,364 @@ + + + + + diff --git a/config.json b/config.json new file mode 100644 index 0000000..c266f7f --- /dev/null +++ b/config.json @@ -0,0 +1,25 @@ +{ + "title": "工商年报", + "baseUrl": "/companyHome", + "tokenKey": "token", + "messageDuration": 3000, + "requestTimeout": 60000, + "successCode": [ + 200, + 0 + ], + "invalidCode": [ + 1001106, + 1001003, + 11009 + ], + "menus":false, + "noLogin": false, + "mainColor": "#1677ff", + "port": 9290 , + "noPermissionCode": 401, + "rbBuldInfo": { + "api": "http://rb2.batiao8.com/console/custom/deploy/f5b5219cce4a7d47a60416ef4d3fa891", + "key": "bNJXlzwc" + } +} \ No newline at end of file diff --git a/data/const.ts b/data/const.ts new file mode 100644 index 0000000..d75a7ac --- /dev/null +++ b/data/const.ts @@ -0,0 +1,23 @@ +// 语言 +export const LOCALES = [ + { + name: '中文', + key: 'ZH', + isPrimary: true, + }, + { + name: 'English', + key: 'EN', + }, +]; + +// 分类 +export const categoryTypes = [ + { key: 'process', name: '历程', path: '/history' }, + { key: 'news', name: '新闻', path: '/news' }, + { key: 'file', name: '文件', path: '/document' }, + { key: 'job', name: '招聘', path: '/jobs' }, + { key: 'job_type', name: '职业类型', path: '/jobs' }, + { key: 'job_area', name: '业务领域', path: '/jobs' }, + { key: 'job_unit', name: '所属板块', path: '/jobs' }, +] \ No newline at end of file diff --git a/layout/TopLayout.scss b/layout/TopLayout.scss new file mode 100644 index 0000000..7ddd311 --- /dev/null +++ b/layout/TopLayout.scss @@ -0,0 +1,28 @@ +.upload-flie { + .el-upload { + border: 1px dashed var(--el-border-color); + border-radius: 6px; + cursor: pointer; + position: relative; + overflow: hidden; + transition: var(--el-transition-duration-fast); + } + + .el-upload:hover { + border-color: var(--el-color-primary); + } + + .el-icon.avatar-uploader-icon { + font-size: 28px; + color: #8c939d; + width: 64px; + height: 64px; + text-align: center; + } + + .uploaded-img { + width: 64px; + height: 64px; + display: block; + } +} diff --git a/layout/TopLayout.tsx b/layout/TopLayout.tsx new file mode 100644 index 0000000..cef2711 --- /dev/null +++ b/layout/TopLayout.tsx @@ -0,0 +1,232 @@ +import type { TopLayoutType } from 'lib/type/TopLayout' +import { ElMessage } from 'element-plus' +import { indexStore } from 'lib/stores' +import login from 'src/api/login' +import clipboard from 'clipboard' +import 'src/layout/TopLayout.scss' +import TableLayout from 'lib/layout/TableLayout.vue' +import message from 'lib/utils/message' +import type { Form, FormData } from 'lib/type/TableData' +import { formatConfig } from 'src/tools' + +// const TableLayout: any = utils.deepClone(tl) +const store = indexStore() +const data: TopLayoutType = { + userButtons: [ + // { + // name: '修改配置', + // type: 'success', + // icon: 'EditPen', + // onClick(self) { + // self.methods?.getConfig(self) + // ;(self.bean as any).configForm.show = 'form' + // } + // // getHide() { + // // return store.$state.kwargs.role != 1 + // // } + // }, + // { + // name: '用户信息', + // type: 'success', + // icon: 'User', + // onClick(self) { + // ;(self.bean as any).userInfoDialogShow = true + // } + // }, + // { + // name: '修改密码', + // type: 'warning', + // icon: 'Key', + // onClick(self) { + // ;(self.bean as any).resetPasswordDialogShow = true + // } + // } + ], + bean: { + userInfoDialogShow: false, + resetPasswordDialogShow: false, + resetPasswordInput: '', + resetPasswordInputOld: '', + resetPasswordInputTwo: '', + configForm: { + hideButton: true, + show: false, + data: [], + async subFun(self, data) { + // console.log(data) + for (const key in data){ + if (typeof data[key] === "object" && Array.isArray(data[key])){ + data[key] = data[key].join(",") + } + } + return login.editorConfig(data) + } + } as Form + }, + methods: { + handleEditorConfigSubmit(self: TopLayoutType) { + login.editorConfig((self.bean as any).editorConfigInfo).then((res: any) => { + if (res.code == 0) { + ElMessage.success('配置修改成功') + } else { + ElMessage.success('配置修改失败') + } + self.methods?.updateConfig(self) + }) + }, + handleResetPasswordSubmit(self: TopLayoutType) { + if ((self.bean as any).resetPasswordInputOld === '') { + ElMessage.error('旧密码不能为空') + return + } + if ((self.bean as any).resetPasswordInput === '') { + ElMessage.error('密码不能为空') + return + } + if ((self.bean as any).resetPasswordInput !== (self.bean as any).resetPasswordInputTwo) { + ElMessage.error('两次输入的密码不一致') + return + } + login + .resetPassWord({ + old_password: (self.bean as any).resetPasswordInputOld, + password: (self.bean as any).resetPasswordInput + }) + .then((res: any) => { + if (res.code === 0) { + ElMessage.success('密码修改成功') + setTimeout(() => { + store.logout() + }, 1000) + } else { + ElMessage.error(res.message) + } + }) + }, + copy(text: string) { + clipboard.copy(text) + message.success('复制成功') + }, + async getConfig(self: TopLayoutType) { + const res = await login.getConfig() + let formData: FormData[] = res.data + formData = formatConfig(formData) + ;(self.bean as any).configForm.data = formData + } + }, + launchTask: [ + // async (self) => { + // const res = await login.getHomeData({}) + // ;(self.bean as any).homeData = res.data + // } + ], + addNods: [ + (self) => { + return ( + + + +
{store.$state.kwargs.realname}
+
+ +
{store.$state.kwargs.role_name}
+
+ +
{store.$state.kwargs.level_name}
+
+ +
{store.$state.kwargs.parent_info.realname}
+
+ {/* +
{store.$state.kwargs.parent_info.role_name}
+
+ +
{store.$state.kwargs.parent_info.level_name}
+
*/} + {/**/} + {/* */} + {/**/} + {/**/} + {/*
*/} + {/* {self.bean?.homeData.url}*/} + {/* {*/} + {/* self.methods?.copy(self.bean?.homeData.url)*/} + {/* }}*/} + {/* >*/} + {/* 复制*/} + {/* */} + {/*
*/} + {/*
*/} +
+
+ ) + }, + (self) => { + return ( + + + + + + + + + + + + + { + ;(self.bean as any).resetPasswordDialogShow = false + }} + > + 取消 + + { + ;(self.methods as any).handleResetPasswordSubmit(self) + }} + > + 确定 + + + + + ) + }, + (self) => { + let element: any = <> + if (self.bean && TableLayout.methods) { + element = TableLayout.methods.createForm.call( + { + ...TableLayout.methods, + ...self.this_, + fetchData: () => {} + }, + self.bean.configForm, + { + id: 'form' + } + ) + } + return element + } + ] +} +export default data diff --git a/package.json b/package.json new file mode 100644 index 0000000..bf593c5 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "yintai-company-home-am", + "version": "1.0.0", + "main": "index.js", + "repository": "https://git.u8t.cn/batiao/corp-bm.git", + "author": "YSASM <1613921123@qq.com>", + "license": "MIT", + "dependencies": { + "@amap/amap-jsapi-loader": "^1.0.1" + }, + "lib": "cy-admin" +} diff --git a/proxy.mjs b/proxy.mjs new file mode 100644 index 0000000..38d1690 --- /dev/null +++ b/proxy.mjs @@ -0,0 +1,12 @@ +import dotenv from "dotenv" +dotenv.config() +// eslint-disable-next-line no-undef +const isDev = process.env.DEV +console.log("isDev:" + isDev) +export default { + '/companyHome': { + target: isDev ? "http://10.3.0.7:9999/":'https://companyapi.batiao8.com/', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/companyHome/, '') + } +} diff --git a/pub/favicon.ico b/pub/favicon.ico new file mode 100644 index 0000000..d7c1d40 Binary files /dev/null and b/pub/favicon.ico differ diff --git a/pub/login.jpg b/pub/login.jpg new file mode 100644 index 0000000..8e20d79 Binary files /dev/null and b/pub/login.jpg differ diff --git a/pub/oderDetailCallBack.png b/pub/oderDetailCallBack.png new file mode 100644 index 0000000..b1e904f Binary files /dev/null and b/pub/oderDetailCallBack.png differ diff --git a/pub/oderDetailCallBackSuccess.png b/pub/oderDetailCallBackSuccess.png new file mode 100644 index 0000000..1ae6856 Binary files /dev/null and b/pub/oderDetailCallBackSuccess.png differ diff --git a/pub/svg/交易管理.svg b/pub/svg/交易管理.svg new file mode 100644 index 0000000..c20e41d --- /dev/null +++ b/pub/svg/交易管理.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/人员管理.svg b/pub/svg/人员管理.svg new file mode 100644 index 0000000..778fb41 --- /dev/null +++ b/pub/svg/人员管理.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/卡号列表.svg b/pub/svg/卡号列表.svg new file mode 100644 index 0000000..9de2b26 --- /dev/null +++ b/pub/svg/卡号列表.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/商品管理.svg b/pub/svg/商品管理.svg new file mode 100644 index 0000000..9fc64bd --- /dev/null +++ b/pub/svg/商品管理.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/用户列表.svg b/pub/svg/用户列表.svg new file mode 100644 index 0000000..9e5beee --- /dev/null +++ b/pub/svg/用户列表.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/订单管理.svg b/pub/svg/订单管理.svg new file mode 100644 index 0000000..fc493fc --- /dev/null +++ b/pub/svg/订单管理.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/订单统计.svg b/pub/svg/订单统计.svg new file mode 100644 index 0000000..c1ea20f --- /dev/null +++ b/pub/svg/订单统计.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/配置.svg b/pub/svg/配置.svg new file mode 100644 index 0000000..0aaecd9 --- /dev/null +++ b/pub/svg/配置.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/预填信息.svg b/pub/svg/预填信息.svg new file mode 100644 index 0000000..10caa39 --- /dev/null +++ b/pub/svg/预填信息.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pub/svg/首页.svg b/pub/svg/首页.svg new file mode 100644 index 0000000..c921a30 --- /dev/null +++ b/pub/svg/首页.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/routes.ts b/routes.ts new file mode 100644 index 0000000..d305387 --- /dev/null +++ b/routes.ts @@ -0,0 +1,191 @@ +import type { RouteRecordRaw } from "vue-router"; +import TableLayout from "lib/layout/TableLayout.vue"; +import MainLayout from "lib/layout/MainLayout.vue"; +const routes: Array = [ + { + meta: { + hidden: true, + }, + path: "/login", + component: () => import("src/views/LoginPage.vue"), + children: [], + }, + { + path: "/", + redirect: "/home", + component: MainLayout, + children: [ + { + path: "home", + component: () => import("src/views/HomeView.vue"), + meta: { + title: "首页", + icon: "首页", + myico: true, + }, + }, + ], + }, + { + path: "/admin", + component: MainLayout, + meta: { + title: "账号管理", + icon: "用户列表", + myico: true, + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "账号列表", + icon: "用户列表", + myico: true, + }, + }, + { + path: "role", + component: TableLayout, + meta: { + title: "角色管理", + icon: "用户列表", + myico: true, + }, + }, + ], + }, + { + path: "/history", + component: MainLayout, + meta: { + title: "银泰历程", + icon: "TrendCharts", + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "银泰历程", + icon: "TrendCharts", + }, + }, + { + path: "typesManage", + component: TableLayout, + meta: { + title: "类型管理", + icon: "Setting", + }, + }, + ], + }, + { + path: "/news", + component: MainLayout, + meta: { + title: "新闻管理", + icon: "VideoCamera", + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "新闻列表", + icon: "VideoCamera", + }, + }, + { + path: "typesManage", + component: TableLayout, + meta: { + title: "类型管理", + icon: "Setting", + }, + }, + ], + }, + { + path: "/jobs", + component: MainLayout, + meta: { + title: "招聘管理", + icon: "House", + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "招聘列表", + icon: "Memo", + }, + }, + { + path: "typesManage", + component: TableLayout, + meta: { + title: "类型管理", + icon: "Setting", + }, + }, + ], + }, + + { + path: "/document", + component: MainLayout, + meta: { + title: "文档管理", + icon: "Files", + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "文档列表", + icon: "Files", + }, + }, + { + path: "typesManage", + component: TableLayout, + meta: { + title: "类型管理", + icon: "Setting", + }, + }, + ], + }, + { + path: "/config", + component: MainLayout, + meta: { + title: "配置管理", + icon: "Setting", + }, + children: [ + { + path: "list", + component: TableLayout, + meta: { + title: "页面配置", + icon: "Setting", + }, + }, + { + path: "source", + component: TableLayout, + meta: { + title: "资源管理", + icon: "Refresh", + }, + }, + ], + }, +]; + +export default routes; diff --git a/tools.ts b/tools.ts new file mode 100644 index 0000000..03534d0 --- /dev/null +++ b/tools.ts @@ -0,0 +1,60 @@ +import type { Form } from 'lib/type/TableData' + +export function formatConfig(config: Array) { + if (typeof config === 'object') { + config = JSON.parse(JSON.stringify(config)) + } + config?.forEach((item: any) => { + let defaultValue: any = '' + if (item.type === 'text') { + item.type = 'input' + item.rows = 5 + defaultValue = item.value || '' + } else if (item.type === 'radio') { + item.type = 'select' + item.items = item.option.map((item: any) => { + return { + key: item.value, + name: item.name + } + }) + delete item.option + defaultValue = item.value || '' + } else if (item.type === 'checkbox') { + item.multiple = true + item.type = 'select' + item.items = item.option.map((item: any) => { + return { + key: item.value, + name: item.name + } + }) + delete item.option + defaultValue = item.value.split(',') + if (defaultValue.length === 1 && defaultValue[0] === '') { + defaultValue = [] + } + } else if (item.type === 'switch') { + item.openValue = true + item.closeValue = false + defaultValue = !!item.value + } else if (item.type === 'json') { + item.type = 'jsonInput' + defaultValue = item.value || '' + } else { + defaultValue = item.value || '' + } + item.getValue = () => defaultValue + delete item.value + }) + return config +} + +export function updateFormData(form: Form, data: Array) { + while (form.data.length > 0) { + form.data.pop() + } + for (const d of data) { + form.data.push(d) + } +} diff --git a/views/ConfigView.scss b/views/ConfigView.scss new file mode 100644 index 0000000..4f5784c --- /dev/null +++ b/views/ConfigView.scss @@ -0,0 +1,37 @@ +.upload-flie { + .el-upload { + border: 1px dashed var(--el-border-color); + border-radius: 6px; + cursor: pointer; + position: relative; + overflow: hidden; + transition: var(--el-transition-duration-fast); + } + + .el-upload:hover { + border-color: var(--el-color-primary); + } + + .el-icon.avatar-uploader-icon { + font-size: 28px; + color: #8c939d; + width: 64px; + height: 64px; + text-align: center; + } + + .uploaded-img{ + width: 64px; + height: 64px; + display: block; + } +} + +.tabs { + width: calc(100% - 60px); + margin: 10px auto 0 30px; + + :deep(.el-tabs__header) { + margin: 0; + } +} \ No newline at end of file diff --git a/views/ConfigView.tsx b/views/ConfigView.tsx new file mode 100644 index 0000000..589d777 --- /dev/null +++ b/views/ConfigView.tsx @@ -0,0 +1,201 @@ +import { reactive } from 'vue' +import './ConfigView.scss' +import { ElMessage } from 'element-plus' +import login from 'src/api/login' +import { indexStore } from 'lib/stores' +export default { + setup() { + const store = indexStore() + const bean = reactive({ + resetPasswordDialogShow: false, + resetPasswordInput: '', + resetPasswordInputOld: '', + resetPasswordInputTwo: '', + + editorConfigDialogShow: false, + editorConfigInfo: { + oa_appid: '', + oa_secret: '', + link_prev:'', + show_conn:"false", + show_seal:"false", + // service_phone: '', + // service_qrcode: { + // url: '' + // }, + service_weixin:"", + robot_key:'', + // service_type: '1', + front_host: '', + back_host: '', + privacy: '', + user: '' + } + }) + const methods = reactive({ + handleEditorConfigSubmit() { + login.editorConfig(bean.editorConfigInfo).then((res: any) => { + if (res.code == 0) { + ElMessage.success('配置修改成功') + } else { + ElMessage.success('配置修改失败') + } + methods.updateConfig() + bean.editorConfigDialogShow = false + }) + }, + handleResetPasswordSubmit() { + if (bean.resetPasswordInputOld === '') { + ElMessage.error('旧密码不能为空') + return + } + if (bean.resetPasswordInput === '') { + ElMessage.error('密码不能为空') + return + } + if (bean.resetPasswordInput !== bean.resetPasswordInputTwo) { + ElMessage.error('两次输入的密码不一致') + return + } + login + .resetPassWord({ + old_password: bean.resetPasswordInputOld, + password: bean.resetPasswordInput + }) + .then((res: any) => { + if (res.code === 0) { + ElMessage.success('密码修改成功') + setTimeout(() => { + store.logout() + }, 1000) + } else { + ElMessage.error(res.message) + } + }) + }, + updateConfig() { + login.getConfig().then((res) => { + bean.editorConfigInfo = res.data + }) + } + }) + methods.updateConfig() + return () => { + return ( +
+ {/* + + + + + + + + + + + + + { + methods.handleResetPasswordSubmit() + }} + > + 确定 + + + + + */} + + + + + + + + + + + {/* + + + + + + {bean.editorConfigInfo.service_type == '1' ? ( + + + + ) : ( + + { + bean.editorConfigInfo.service_qrcode = response.data + }} + > + {bean.editorConfigInfo.service_qrcode ? ( + + ) : ( + + + + )} + + + )} */} + {/* front_host:"", + back_host:"", + privacy:"", + user:"" */} + + + + + + + + + + + + + + + + + + + + + + + + + + { + methods.handleEditorConfigSubmit() + }} + > + 确定 + + + + {/* + */} +
+ ) + } + } +} diff --git a/views/HomeView.vue b/views/HomeView.vue new file mode 100644 index 0000000..4c5e55d --- /dev/null +++ b/views/HomeView.vue @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/views/LoginPage.vue b/views/LoginPage.vue new file mode 100644 index 0000000..0749b67 --- /dev/null +++ b/views/LoginPage.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/views/admin/list.tsx b/views/admin/list.tsx new file mode 100644 index 0000000..bf89b03 --- /dev/null +++ b/views/admin/list.tsx @@ -0,0 +1,167 @@ +import type { TableData } from 'lib/type/TableData' + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + + ], + launchTask: [ + async (self) => { + if (self.bean) { + const res = await self.api?.getRoleList() + self.bean.roleList = res.data.items.map((item:any) => ({key: item.id, name: item.name})) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'username', + name: '用户名', + type: 'input' + }, + { + type: 'dialogForm', + key: 'create', + form: { + title: '新建', + data: [ + { + key: 'username', + name: '用户名', + type: 'input', + must: true + }, + { + key: 'account', + name: '账号', + type: 'input', + must: true + }, + { + key: 'password', + name: '密码', + type: 'input', + must: true + }, + { + key: 'role', + name: '角色', + type: 'select', + getItems: (self) => { + return self.bean ? self.bean.roleList : [] + }, + must: true + }, + ], + subFun(self, data) { + return self.api?.addData(data) + } + } + } + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'username', + name: '用户名', + width: '200px' + }, + { + key: 'account', + name: '账号', + width: '200px' + }, + { + key: 'role_name', + name: '角色', + width: '200px' + }, + { + key: 'status', + name: '状态', + width: '100px', + editor: { + type: 'switch', + openValue: 1, + closeValue: 2, + subFun(self, data) { + return self.api?.updateData({id: String(data.id), status: String(data.status)}) + }, + } + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'dialogForm', + key: 'update', + form: { + title: '编辑', + type: 'warning', + primary: 'id', + data: [ + { + key: 'username', + name: '用户名', + type: 'input', + must: true + }, + { + key: 'role_id', + name: '角色', + type: 'select', + getItems: (self) => { + return self.bean ? self.bean.roleList : [] + }, + must: true + }, + { + key: 'status', + name: '状态', + type: 'switch', + openValue: 1, + closeValue: 2, + tips: '启用/禁用', + must: true + }, + ], + subFun(self, data) { + return self.api?.updateData({...data, id: String(data.id), role_id: String(data.role_id), status: String(data.status)}) + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/admin/role.tsx b/views/admin/role.tsx new file mode 100644 index 0000000..eb7d06a --- /dev/null +++ b/views/admin/role.tsx @@ -0,0 +1,139 @@ +import type { TableData } from 'lib/type/TableData' + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + + ], + launchTask: [ + async (self: any) => { + if (self.bean) { + const res = await self.api?.getResources() + self.bean.resources = res.data.items.map((item:any) => { + const type = item.type === 'page' ? '页面' : '接口' + return { + key: item.id, + name: `【${type}】${item.name}` + } + }) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'username', + name: '用户名', + type: 'input' + }, + { + type: 'dialogForm', + key: 'create', + form: { + title: '新建', + data: [ + { + key: 'name', + name: '角色', + type: 'input', + must: true + }, + { + key: 'resource', + name: '权限', + type: 'select', + getItems: (self: any) => { + return self.bean ? self.bean.resources : [] + }, + multiple: true, + must: true + }, + ], + subFun(self, data) { + const params = { + ...data, + resource: data.resource.map((i:number) => String(i)) + } + return self.api?.addData(params) + } + } + } + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'name', + name: '角色', + width: '200px' + }, + { + key: 'desc', + name: '描述', + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'dialogForm', + key: 'update', + form: { + title: '编辑', + type: 'warning', + primary: 'id', + data: [ + { + key: 'name', + name: '角色', + type: 'input', + must: true + }, + { + key: 'resource', + name: '权限', + type: 'select', + getItems: (self: any) => { + return self.bean ? self.bean.resources : [] + }, + multiple: true, + must: true + }, + ], + subFun(self, data) { + return self.api?.updateData({...data, id: String(data.id)}) + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/config/index.less b/views/config/index.less new file mode 100644 index 0000000..bf66019 --- /dev/null +++ b/views/config/index.less @@ -0,0 +1,20 @@ +.category-row, +.active-category-row { + .cell { + display: flex; + align-items: center; + } + + &.el-table__row--level-0 .el-tooltip__trigger>span { + margin: 0 !important; + text-align: left; + } + + &.el-table__row--level-0 { + font-weight: 600; + } +} + +.active-category-row { + background: greenyellow !important; +} \ No newline at end of file diff --git a/views/config/list.tsx b/views/config/list.tsx new file mode 100644 index 0000000..66ad115 --- /dev/null +++ b/views/config/list.tsx @@ -0,0 +1,273 @@ +import type { TableData } from 'lib/type/TableData' +import './index.less' +import JsonFormDialog from 'src/components/JsonFormDialog.vue' +const data: TableData = { + rowKey: 'id', + defaultExpandAll: true, + sizeOption: [1000, 100, 500, 2000], + fetchFun(self, data) { + return self.api?.getDataList(data).then((res: any) => { + const items = res.data.items || [] + const backendItem = items.find((item:any) => item.tags.includes('backend')) + if(backendItem) { + try { + (self.bean as any).fieldMap = JSON.parse(backendItem.content || '{}') + } catch(err) { + console.log(err) + } + } + const flatData = items.map((item: any) => ({ + ...item, + key: item.id, + id: item.id, + pid: String(item.pid ?? 0), + color: 'category' + })) + res.data.items = self.methods?.getTree(flatData) ?? flatData + return res + }) + }, + methods: { + getTree(arr: any[]) { + const map: any = {} + const roots: any[] = [] + + arr.forEach((item: any) => { + map[item.key] = { ...item, children: [] } + }) + + arr.forEach((item: any) => { + const node = map[item.key] + if (item.pid === 0 || item.pid === '0') { + roots.push(node) + } else { + if (map[item.pid]) { + map[item.pid].children.push(node) + } else { + roots.push(node) + } + } + }) + return roots + } + }, + addNods: [ + (self: any) => { + return self.bean && { + self.bean.showJsonFormDialog = false + }} + onSubmit={async (data: any) => { + await self.api?.updateData({ + id: String(self.bean.currentRow.id), + content: JSON.stringify(data), + }) + self.bean.showJsonFormDialog = false + self.methods.fetchData() + }} + /> + } + ], + launchTask: [ + async (self: any) => { + if (self.bean) { + self.bean.showJsonFormDialog = false + self.bean.currentRow = null + self.bean.jsonFormData = {} + // self.bean.fieldMap = {} + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'name', + name: '配置名', + type: 'input' + }, + { + type: 'dialogForm', + key: 'create', + form: { + title: '新建', + data: [ + { + key: 'pid', + name: '父级', + type: 'input', + }, + { + key: 'name', + name: '配置名', + type: 'input', + must: true + }, + { + key: 'page', + name: '页面路径', + type: 'input', + must: true + }, + { + key: 'extra', + hide: true, + name: '配置内容', + type: 'input', + rows: 4 + }, + ], + subFun(self, data) { + return self.api?.addData(data) + } + } + } + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'pid', + name: 'PID', + width: '80px', + showJson: '*' + }, + { + key: 'name', + name: '配置名', + width: '150px' + }, + { + key: 'page', + name: '页面路径', + width: '150px' + }, + { + key: 'content', + name: 'JSON配置', + width: '200px', + editor: { + type: 'json', + subFun(self, data) { + return self.api?.updateData({...data, id: String(data.id)}) + } + } + }, + { + key: 'content', + name: '配置', + width: '100px', + renderBodyCell({self, row}:any) { + if(row.tags.includes('backend')) { + return + } + return ( + { + try { + self.bean.jsonFormData = JSON.parse(row.content || '{}') + } catch { + self.bean.jsonFormData = {} + } + self.bean.currentRow = row + self.bean.showJsonFormDialog = true + }} + >配置 + ) + }, + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'weight', + name: '权重', + width: '100px', + editor: { + type: 'input', + subFun(self, data, row) { + return self.api?.updateData({...data, id: String(data.id), pid: String(row.pid)}) + } + } + }, + { + key: 'tags', + name: '标签', + editor: { + type: 'input', + subFun(self, data, row) { + return self.api?.updateData({...data, id: String(data.id), pid: String(row.pid)}) + } + } + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'dialogForm', + key: 'update', + form: { + title: '编辑', + type: 'warning', + primary: 'id', + data: [ + { + key: 'pid', + name: '父级', + type: 'input', + }, + { + key: 'name', + name: '配置名', + type: 'input', + must: true + }, + { + key: 'page', + name: '页面路径', + type: 'input', + must: true + }, + { + key: 'content', + hide: true, + name: '配置内容', + type: 'input', + rows: 4 + }, + ], + subFun(self, data) { + return self.api?.updateData({...data, id: String(data.id)}) + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/config/source.tsx b/views/config/source.tsx new file mode 100644 index 0000000..24ca70a --- /dev/null +++ b/views/config/source.tsx @@ -0,0 +1,158 @@ +import type { TableData } from 'lib/type/TableData' + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + + ], + launchTask: [ + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'name', + name: '名称', + type: 'input' + }, + { + key: 'type', + name: '类型', + type: 'select', + items: [ + { key: 'page',name: '页面' }, + { key: 'api',name: 'API' }, + ], + value: 'page' + }, + { + key: 'path', + name: '路径', + type: 'input', + }, + { + type: 'dialogForm', + key: 'create', + form: { + title: '新建', + data: [ + { + key: 'name', + name: '名称', + type: 'input', + must: true + }, + { + key: 'type', + name: '类型', + type: 'select', + items: [ + { key: 'page',name: '页面' }, + { key: 'api',name: 'API' }, + ], + value: 'page' + }, + { + key: 'path', + name: '路径', + type: 'input', + must: true + }, + ], + subFun(self, data) { + return self.api?.addData(data) + } + } + } + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'name', + name: '名称', + width: '200px' + }, + { + key: 'type', + name: '类型', + }, + { + key: 'path', + name: '路径', + }, + { + key: 'method', + name: '方法', + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'dialogForm', + key: 'update', + form: { + title: '编辑', + type: 'warning', + primary: 'id', + data: [ + { + key: 'name', + name: '名称', + type: 'input', + must: true + }, + { + key: 'type', + name: '类型', + type: 'select', + items: [ + { key: 'page',name: '页面' }, + { key: 'api',name: 'API' }, + ], + value: 'page' + }, + { + key: 'path', + name: '路径', + type: 'input', + must: true + }, + ], + subFun(self, data) { + return self.api?.updateData({...data, id: String(data.id)}) + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/default.tsx b/views/default.tsx new file mode 100644 index 0000000..ed65ae4 --- /dev/null +++ b/views/default.tsx @@ -0,0 +1,6 @@ +import type { TableData } from "lib/type/TableData" +const data:TableData = { + +} + +export default data \ No newline at end of file diff --git a/views/document/list.tsx b/views/document/list.tsx new file mode 100644 index 0000000..635c8ab --- /dev/null +++ b/views/document/list.tsx @@ -0,0 +1,212 @@ +import type { TableData } from 'lib/type/TableData' +import In18FormDialog from '../../components/In18FormDialog.vue' +import { LOCALES } from '../../data/const' +import { categoryTypes } from '../../data/const' +import utils from 'lib/utils' +let types: any[] = [] +const pathname = utils.getPathName() +types = categoryTypes.filter(item => pathname.includes(item.path)) + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + (self: any) => { + return ( + self.bean && + { + self.bean.showEditorDialog = false; + self.bean.id = null; + }} + onSubmit={async (data) => { + const params = { + ...data, + id: data.id ? String(data.id) : '', + category_id: data.category_id ? String(data.category_id) : '', + } + if(data.id) { + await self.api?.updateData(params) + } else { + await self.api?.addData(params) + } + self.bean.showEditorDialog = false; + self.bean.id = null; + self.methods.fetchData() + }} + translateApi={self.api?.translate} + detailApi={async (id: number) => { + const res = await self.api?.getDetail(id); + const data = res.data; + Object.keys(data).forEach((langKey) => { + const langData = data[langKey]; + Object.keys(langData).forEach((fieldKey) => { + const field = self.bean.form.find((f:any) => f.key === fieldKey); + if(fieldKey === 'name') { + data[langKey]['file_name'] = langData[fieldKey] + } + if (!field) return; + data[langKey][fieldKey] = langData[fieldKey]; + }) + }) + return data + }} + uploadFun={self.api?.upload} + /> + ) + } + ], + launchTask: [ + async (self: any) => { + if (self.bean) { + self.bean.id = null; + self.bean.form = [ + { + name: '分类', + key: 'category_id', + type: 'select', + getItems: () => self.bean.docTypes, + must: true, + shouldTranslate: false, + }, + { + name: '文件路径', + key: 'path', + type: 'upload:file', + accept: '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx', + must: true, + shouldTranslate: false, + }, + { + name: '文件名', + key: 'file_name', + type: 'input', + value: '', + must: true, + shouldTranslate: true, + }, + ]; + self.bean.locales = LOCALES + } + }, + async (self: any) => { + if (self.bean) { + const types = ['file'] as const + const results = await Promise.all( + types.map((type) => + self.api?.getCategoryList({ page: 1, size: 1000, type }) + ) + ) + const toOptions = (items: any[]) => items.map((item: any) => ({ key: item.id, name: item.name })); + + [self.bean.docTypes] = results.map( + (res) => toOptions(res?.data?.items ?? []) + ) + console.log('docTypes', self.bean.docTypes) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'lang', + name: '语言', + type: 'select', + value: 'ZH', + getItems: (self) => { + return self.bean ? self.bean.locales : [] + } + }, + { + key: 'category_id', + name: '分类', + type: 'select', + value: '', + getItems: (self: any) => { + return self.bean ? self.bean.docTypes : [] + }, + }, + { + key: 'file_name', + name: '文件名', + type: 'input' + }, + { + type: 'onlyFun', + onlyFun: { + title: '新建', + type: ' ' as any, + fun(self) { + if(self.bean) { + self.bean.id = null; + self.bean.showEditorDialog = true; + } + } + } + }, + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'name', + name: '文件名', + width: '200px' + }, + { + key: 'path', + name: '文件路径', + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'onlyFun', + key: 'update', + onlyFun: { + title: '编辑', + type: ' ' as any, + fun(self, row) { + if(self.bean) { + self.bean.id = row.id; + self.bean.showEditorDialog = true; + } + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/document/typesManage.tsx b/views/document/typesManage.tsx new file mode 100644 index 0000000..ced0dc5 --- /dev/null +++ b/views/document/typesManage.tsx @@ -0,0 +1,3 @@ +import data from '../history/typesManage' + +export default data \ No newline at end of file diff --git a/views/history/list.tsx b/views/history/list.tsx new file mode 100644 index 0000000..ea053df --- /dev/null +++ b/views/history/list.tsx @@ -0,0 +1,212 @@ +import type { TableData } from 'lib/type/TableData' +import In18FormDialog from '../../components/In18FormDialog.vue' +import { LOCALES } from '../../data/const' +import { categoryTypes } from '../../data/const' +import utils from 'lib/utils' +let types: any[] = [] +const pathname = utils.getPathName() +types = categoryTypes.filter(item => pathname.includes(item.path)) + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + (self: any) => { + return ( + self.bean && + { + self.bean.showEditorDialog = false; + self.bean.id = null; + }} + onSubmit={async (data) => { + await self.api?.addData(data) + self.bean.showEditorDialog = false; + self.bean.id = null; + self.methods.fetchData() + }} + translateApi={self.api?.translate} + detailApi={async (id: number) => { + const res = await self.api?.getDetail(id); + const data = res.data; + Object.keys(data).forEach((langKey) => { + const langData = data[langKey]; + Object.keys(langData).forEach((fieldKey) => { + const field = self.bean.form.find((f:any) => f.key === fieldKey); + if (!field) return; + data[langKey][fieldKey] = langData[fieldKey]; + }) + }) + return data + }} + /> + ) + } + ], + launchTask: [ + async (self: any) => { + if (self.bean) { + self.bean.id = null; + self.bean.form = [ + { + name: '分类', + key: 'category_id', + type: 'select', + must: true, + getItems: () => { + return self.bean ? self.bean.processTypes : [] + }, + shouldTranslate: false, + }, + { + name: '标题', + key: 'title', + type: 'input', + value: '', + must: true, + shouldTranslate: true, + }, + { + name: '内容', + key: 'content', + type: 'textarea', + value: '', + must: true, + shouldTranslate: true, + }, + ]; + self.bean.locales = LOCALES + } + }, + async (self: any) => { + if (self.bean) { + const types = ['process'] as const + const results = await Promise.all( + types.map((type) => + self.api?.getCategoryList({ page: 1, size: 1000, type }) + ) + ) + const toOptions = (items: any[]) => items.map((item: any) => ({ key: item.id, name: item.name })); + + [self.bean.processTypes] = results.map( + (res) => toOptions(res?.data?.items ?? []) + ) + console.log('processTypes', self.bean.processTypes) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'lang', + name: '语言', + type: 'select', + value: 'ZH', + getItems: (self) => { + return self.bean ? self.bean.locales : [] + } + }, + { + key: 'category_id', + name: '分类', + type: 'select', + value: '', + getItems: (self: any) => { + return self.bean ? self.bean.processTypes : [] + }, + }, + { + key: 'title', + name: '标题', + type: 'input' + }, + { + type: 'onlyFun', + onlyFun: { + title: '新建', + type: ' ' as any, + fun(self) { + if(self.bean) { + self.bean.id = null; + self.bean.showEditorDialog = true; + } + } + } + }, + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'lang', + name: '语言', + width: '80px', + }, + { + key: 'category_name', + name: '分类', + width: '200px', + }, + { + key: 'title', + name: '标题', + width: '200px', + }, + { + key: 'content', + name: '内容', + }, + { + key: 'create_time', + name: '创建时间', + width: '150px' + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'onlyFun', + key: 'update', + onlyFun: { + title: '编辑', + type: ' ' as any, + fun(self, row) { + if(self.bean) { + self.bean.id = row.id; + self.bean.showEditorDialog = true; + } + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/history/typesManage.tsx b/views/history/typesManage.tsx new file mode 100644 index 0000000..c771558 --- /dev/null +++ b/views/history/typesManage.tsx @@ -0,0 +1,140 @@ +import type { TableData } from 'lib/type/TableData' +import { categoryTypes } from '../../data/const' +import utils from 'lib/utils' +let types: any[] = [] +const pathname = utils.getPathName() +types = categoryTypes.filter(item => pathname.includes(item.path)) + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + + ], + launchTask: [ + async (self) => { + const pathname = utils.getPathName() + types = categoryTypes.filter(item => pathname.includes(item.path)) + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'type', + name: '类型', + type: 'select', + getValue: () => types[0] ? types[0].key : '', + getItems: () => types, + }, + { + key: 'name', + name: '分类名', + type: 'input' + }, + { + type: 'dialogForm', + key: 'create', + form: { + title: '新建', + data: [ + { + key: 'pid', + name: '父ID', + type: 'input', + }, + { + key: 'name', + name: '分类名', + type: 'input', + must: true + }, + { + key: 'type', + name: '类型', + type: 'select', + getItems: () => types, + must: true + }, + ], + subFun(self, data) { + return self.api?.addData(data) + } + } + } + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'pid', + name: 'PID', + width: '80px', + showJson: '*' + }, + { + key: 'name', + name: '分类名', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'dialogForm', + key: 'update', + form: { + title: '编辑', + type: 'warning', + primary: 'id', + data: [ + { + key: 'pid', + name: '父ID', + type: 'input', + }, + { + key: 'name', + name: '分类名', + type: 'input', + must: true + }, + // { + // key: 'type', + // name: '类型', + // type: 'select', + // getItems: () => types, + // must: true + // }, + ], + subFun(self, data) { + return self.api?.updateData({ ...data, id: String(data.id), pid: String(data.pid) }) + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/jobs/list.tsx b/views/jobs/list.tsx new file mode 100644 index 0000000..d909f82 --- /dev/null +++ b/views/jobs/list.tsx @@ -0,0 +1,317 @@ +import type { TableData } from 'lib/type/TableData' +import In18FormDialog from '../../components/In18FormDialog.vue' +import { LOCALES } from '../../data/const' + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + (self: any) => { + return ( + self.bean && + { + self.bean.showEditorDialog = false; + self.bean.id = null; + }} + onSubmit={async (data) => { + const params = { + ...data, + id: data.id ? String(data.id) : undefined, + job_area: data.job_area ? String(data.job_area) : undefined, + job_unit: data.job_unit ? String(data.job_unit) : undefined, + job_type: data.job_type ? String(data.job_type) : undefined, + recruit_count: data.recruit_count ? String(data.recruit_count) : undefined, + } + if(data.id) { + await self.api?.updateData(params) + } else { + await self.api?.addData(params) + } + self.bean.showEditorDialog = false; + self.bean.id = null; + self.methods.fetchData() + }} + translateApi={self.api?.translate} + detailApi={async (id: number) => { + const res = await self.api?.getDetail(id); + const data = res.data; + Object.keys(data).forEach((langKey) => { + const langData = data[langKey]; + Object.keys(langData).forEach((fieldKey) => { + const field = self.bean.form.find((f:any) => f.key === fieldKey); + if (fieldKey === 'title') { + data[langKey]['name'] = langData[fieldKey]; + } + if(fieldKey === 'category') { + data[langKey]['job_type'] = langData[fieldKey].job_type; + data[langKey]['job_area'] = langData[fieldKey].job_area; + data[langKey]['job_unit'] = langData[fieldKey].job_unit; + } + if (!field) return; + data[langKey][fieldKey] = langData[fieldKey]; + }) + }) + console.log('data', data) + return data + }} + /> + ) + } + ], + launchTask: [ + async (self: any) => { + if (self.bean) { + self.bean.id = null; + console.log('self.bean.jobTypes', self.bean.jobTypes) + self.bean.form = [ + { + name: '职业类别', + key: 'job_type', + type: 'select', + value: '', + getItems: () => self.bean.jobTypes, + must: true, + shouldTranslate: false, + }, + { + name: '业务领域', + key: 'job_area', + type: 'select', + getItems: () => self.bean.jobAreas, + value: '', + must: true, + shouldTranslate: false, + }, + { + name: '所属板块', + key: 'job_unit', + type: 'select', + getItems: () => self.bean.jobUnits, + value: '', + must: true, + shouldTranslate: false, + }, + { + name: '招聘人数', + key: 'recruit_count', + type: 'input', + value: '', + must: true, + shouldTranslate: false, + }, + { + name: '城市', + key: 'city', + type: 'input', + value: '', + must: true, + shouldTranslate: false, + }, + { + name: '岗位名称', + key: 'name', + type: 'input', + value: '', + must: true, + shouldTranslate: true, + }, + { + name: '岗位描述', + key: 'description', + type: 'textarea', + value: '', + must: true, + shouldTranslate: true, + }, + { + name: '任职需求', + key: 'requirement', + type: 'textarea', + value: '', + must: true, + shouldTranslate: true, + }, + { + name: '联系方式', + key: 'contract_info', + type: 'input', + value: '', + must: true, + shouldTranslate: true, + }, + ]; + self.bean.locales = LOCALES + } + }, + async (self: any) => { + if (self.bean) { + const types = ['job_type', 'job_area', 'job_unit'] as const + const results = await Promise.all( + types.map((type) => + self.api?.getCategoryList({ page: 1, size: 1000, type }) + ) + ) + const toOptions = (items: any[]) => items.map((item: any) => ({ key: item.id, name: item.name })); + + [self.bean.jobTypes, self.bean.jobAreas, self.bean.jobUnits] = results.map( + (res) => toOptions(res?.data?.items ?? []) + ) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'lang', + name: '语言', + type: 'select', + value: 'ZH', + getItems: (self) => { + return self.bean ? self.bean.locales : [] + } + }, + { + key: 'title', + name: '职位名称', + type: 'input', + }, + { + key: 'job_type', + name: '职业类别', + type: 'select', + getItems: (self) => { + return self.bean ? self.bean.jobTypes : [] + } + }, + { + key: 'job_area', + name: '业务领域', + type: 'select', + getItems: (self) => { + return self.bean ? self.bean.jobAreas : [] + } + }, + { + key: 'job_unit', + name: '所属板块', + type: 'select', + getItems: (self) => { + return self.bean ? self.bean.jobUnits : [] + } + }, + { + type: 'onlyFun', + onlyFun: { + title: '新建', + type: ' ' as any, + fun(self) { + if (self.bean) { + self.bean.id = null; + self.bean.showEditorDialog = true; + } + } + } + }, + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'lang', + name: '语言', + width: '80px' + }, + { + key: 'title', + name: '职位名称', + width: '200px' + }, + { + key: 'category', + name: '职业类型 | 业务领域 | 所属板块', + renderBodyCell(data) { + let item: any = {} + try { + item = JSON.parse(data.row.category) + } catch (error) { + item = data.row.category + } + return
+ {item.job_type_name} + {item.job_area_name} + {item.job_unit_name} +
+ }, + }, + { + key: 'description', + name: '岗位描述', + }, + { + key: 'requirement', + name: '任职需求', + }, + { + key: 'recruit_count', + name: '招聘人数', + width: '80px' + }, + { + key: 'contract_info', + name: '联系方式', + width: '200px' + }, + { + key: 'create_time', + name: '创建时间', + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'onlyFun', + key: 'update', + onlyFun: { + title: '编辑', + type: ' ' as any, + fun(self, row) { + if (self.bean) { + self.bean.id = row.id; + self.bean.showEditorDialog = true; + } + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/jobs/typesManage.tsx b/views/jobs/typesManage.tsx new file mode 100644 index 0000000..ced0dc5 --- /dev/null +++ b/views/jobs/typesManage.tsx @@ -0,0 +1,3 @@ +import data from '../history/typesManage' + +export default data \ No newline at end of file diff --git a/views/news/list.tsx b/views/news/list.tsx new file mode 100644 index 0000000..7cd36ec --- /dev/null +++ b/views/news/list.tsx @@ -0,0 +1,278 @@ +import type { TableData } from 'lib/type/TableData' +import { LOCALES } from '../../data/const' +import In18FormDialog from '../../components/In18FormDialog.vue' + +const data: TableData = { + async fetchFun(self, data) { + const res = await self.api?.getDataList(data) + return res + }, + addNods: [ + (self: any) => { + return ( + self.bean && + { + self.bean.showEditorDialog = false; + self.bean.id = null; + }} + onSubmit={async (data) => { + const params = { + ...data, + id: data.id ? String(data.id) : undefined, + category_id: data.category_id ? String(data.category_id) : undefined, + } + if(data.id) { + await self.api?.updateData(params) + } else { + await self.api?.addData(params) + } + self.bean.showEditorDialog = false; + self.bean.id = null; + self.methods.fetchData() + }} + translateApi={self.api?.translate} + detailApi={async (id: number) => { + const res = await self.api?.getDetail(id); + const data = res.data; + Object.keys(data).forEach((langKey) => { + const langData = data[langKey]; + Object.keys(langData).forEach((fieldKey) => { + const field = self.bean.form.find((f:any) => f.key === fieldKey); + if (fieldKey === 'covers') { + data[langKey]['cover_resource'] = langData[fieldKey]; + } + if (!field) return; + data[langKey][fieldKey] = langData[fieldKey]; + }) + }) + return data + }} + uploadFun={self.api?.upload} + /> + ) + } + ], + launchTask: [ + async (self) => { + if (self.bean) { + self.bean.locales = LOCALES; + self.bean.id = null; + self.bean.form = [ + { + name: '分类', + key: 'category_id', + type: 'select', + value: '', + getItems: () => { + return self.bean ? self.bean.newsTypes : [] + }, + must: true, + shouldTranslate: false, + }, + { + name: '封面类型', + key: 'cover_show', + type: 'select', + items: [ + {key: 'image', name: '图片'}, + {key: 'video', name: '视频'}, + ], + value: 'image', + must: true, + shouldTranslate: false, + }, + { + name: '封面', + key: 'cover_resource', + type: 'upload:image,video', + relateKey: 'cover_show', + uploadFun: self.api?.upload, + value: '', + must: true, + shouldTranslate: false, + }, + { + name: '标题', + key: 'title', + type: 'input', + value: '', + must: true, + shouldTranslate: true, + }, + { + name: '内容', + key: 'content', + type: 'textarea', + value: '', + must: true, + shouldTranslate: true, + }, + ]; + } + }, + async (self: any) => { + if (self.bean) { + const types = ['news'] as const + const results = await Promise.all( + types.map((type) => + self.api?.getCategoryList({ page: 1, size: 1000, type }) + ) + ) + const toOptions = (items: any[]) => items.map((item: any) => ({ key: item.id, name: item.name })); + + [self.bean.newsTypes] = results.map( + (res) => toOptions(res?.data?.items ?? []) + ) + console.log('newsTypes', self.bean.newsTypes) + } + } + ], + fliter: [ + { + key: 'id', + name: 'ID', + type: 'input' + }, + { + key: 'lang', + name: '语言', + type: 'select', + value: 'ZH', + getItems: (self) => { + return self.bean ? self.bean.locales : [] + } + }, + { + key: 'category_id', + name: '分类', + type: 'select', + value: '', + getItems: (self: any) => { + return self.bean ? self.bean.newsTypes : [] + }, + }, + { + key: 'title', + name: '标题', + type: 'input' + }, + { + key: 'content', + name: '内容', + type: 'input' + }, + + { + key: 'publish_time', + name: '发布时间', + type: 'input' + }, + { + type: 'onlyFun', + onlyFun: { + title: '新建', + type: ' ' as any, + fun(self) { + if (self.bean) { + self.bean.id = null; + self.bean.showEditorDialog = true; + } + } + } + }, + ], + tableColumns: [ + { + key: 'id', + name: 'ID', + width: '80px', + showJson: '*' + }, + { + key: 'lang', + name: '语言', + width: '80px', + }, + { + key: 'category_name', + name: '分类', + width: '150px', + }, + { + key: 'covers', + name: '封面', + width: '200px', + renderBodyCell(data) { + let covers = data.row.covers + try { + covers = JSON.parse(data.row.covers) + } catch (error) { + covers = data.row.covers + } + return + }, + }, + { + key: 'covers_show', + name: '封面类型', + width: '100px', + }, + { + key: 'title', + name: '标题', + width: '200px' + }, + { + key: 'content', + name: '内容', + }, + { + key: 'create_time', + name: '发布时间', + width: '150px' + }, + { + key: 'count', + name: '阅读次数', + width: '150px' + }, + { + key: 'table_tools', + name: '操作', + buttons: [ + { + type: 'onlyFun', + key: 'update', + onlyFun: { + title: '编辑', + type: ' ' as any, + fun(self, row) { + if (self.bean) { + self.bean.id = row.id; + self.bean.showEditorDialog = true; + } + } + } + }, + { + type: 'popoverConfirm', + key: 'delete', + confirm: { + title: '删除', + primary: 'id', + subFun(self, data) { + return self.api?.deleteData(data) + } + } + } + ] + } + ] +} + +export default data diff --git a/views/news/typesManage.tsx b/views/news/typesManage.tsx new file mode 100644 index 0000000..ced0dc5 --- /dev/null +++ b/views/news/typesManage.tsx @@ -0,0 +1,3 @@ +import data from '../history/typesManage' + +export default data \ No newline at end of file