diff --git a/README.md b/README.md index 610695642..c98e2ed87 100644 --- a/README.md +++ b/README.md @@ -192,14 +192,14 @@ ps:核心功能已经实现,正在对接微信小程序中... | [JUnit](https://junit.org/junit5/) | Java 单元测试框架 | 5.8.2 | - | | [Mockito](https://github.com/mockito/mockito) | Java Mock 框架 | 4.0.0 | - | -### Vue2 前端 +### [Vue2 前端](./yudao-ui-admin) | 框架 | 说明 | 版本 | |------------------------------------------------------------------------------|---------------|--------| | [Vue](https://cn.vuejs.org/index.html) | JavaScript 框架 | 2.6.12 | | [Vue Element Admin](https://panjiachen.github.io/vue-element-admin-site/zh/) | 后台前端解决方案 | - | -### Vue3 前端 +### [Vue3 前端](./yudao-ui-admin-vue3) | 框架 | 说明 | 版本 | |----------------------------------------------------------------------|------------------|--------| diff --git a/yudao-ui-admin-vue3/README.md b/yudao-ui-admin-vue3/README.md index f898a6d9e..c477d2e75 100644 --- a/yudao-ui-admin-vue3/README.md +++ b/yudao-ui-admin-vue3/README.md @@ -22,6 +22,8 @@ - node >=14.18.0(建议使用 16 版本) ,pnpm >=7 - 开发建议使用 [谷歌浏览器-开发者版](https://www.google.cn/intl/zh-CN/chrome/dev/) 不支持 IE\QQ 等浏览器 +### 点击查看[使用说明](./use.md) + ### 前端依赖 | 框架 | 说明 | 版本 | diff --git a/yudao-ui-admin-vue3/package.json b/yudao-ui-admin-vue3/package.json index 4e7ebb03e..c221f0d68 100644 --- a/yudao-ui-admin-vue3/package.json +++ b/yudao-ui-admin-vue3/package.json @@ -65,8 +65,8 @@ "@types/nprogress": "^0.2.0", "@types/qrcode": "^1.4.2", "@types/qs": "^6.9.7", - "@typescript-eslint/eslint-plugin": "^5.31.0", - "@typescript-eslint/parser": "^5.31.0", + "@typescript-eslint/eslint-plugin": "^5.32.0", + "@typescript-eslint/parser": "^5.32.0", "@vitejs/plugin-vue": "^3.0.1", "@vitejs/plugin-vue-jsx": "^2.0.0", "autoprefixer": "^10.4.8", @@ -91,7 +91,7 @@ "stylelint-config-standard": "^26.0.0", "stylelint-order": "^5.0.0", "typescript": "4.7.4", - "unplugin-vue-define-options": "^0.6.2", + "unplugin-vue-define-options": "^0.7.1", "vite": "3.0.4", "vite-plugin-compression": "^0.5.1", "vite-plugin-eslint": "^1.7.0", diff --git a/yudao-ui-admin-vue3/src/api/system/dept/types.ts b/yudao-ui-admin-vue3/src/api/system/dept/types.ts index 3151c610f..470fcd3d8 100644 --- a/yudao-ui-admin-vue3/src/api/system/dept/types.ts +++ b/yudao-ui-admin-vue3/src/api/system/dept/types.ts @@ -1,9 +1,12 @@ export type DeptVO = { id: number name: string - status: number parentId: number - createTime: string + status: number + sort: number + leaderUserId: number + phone: string + email: string } export type DeptListReqVO = { diff --git a/yudao-ui-admin-vue3/src/config/axios/index.ts b/yudao-ui-admin-vue3/src/config/axios/index.ts index 95023c4e4..14bd90bad 100644 --- a/yudao-ui-admin-vue3/src/config/axios/index.ts +++ b/yudao-ui-admin-vue3/src/config/axios/index.ts @@ -1,8 +1,8 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios' -import { ElMessage, ElMessageBox, ElNotification } from 'element-plus' +import { ElMessage, ElNotification } from 'element-plus' import qs from 'qs' import { config } from '@/config/axios/config' -import { getAccessToken, getRefreshToken, getTenantId } from '@/utils/auth' +import { getAccessToken, getTenantId, removeToken } from '@/utils/auth' import errorCode from './errorCode' import { useI18n } from '@/hooks/web/useI18n' @@ -22,7 +22,7 @@ export const isRelogin = { show: false } // 请求队列 // const requestList = [] // 是否正在刷新中 -let isRefreshToken = false +// const isRefreshToken = false export const PATH_URL = base_url[import.meta.env.VITE_API_BASEPATH] @@ -55,18 +55,26 @@ service.interceptors.request.use( config.data = qs.stringify(data) } // get参数编码 - if (config.method?.toUpperCase() === 'GET' && config.params) { - let url = config.url as string + if (config.method?.toUpperCase() === 'GET' && params) { + let url = config.url + '?' + for (const propName of Object.keys(params)) { + const value = params[propName] + if (value !== void 0 && value !== null && typeof value !== 'undefined') { + if (typeof value === 'object') { + for (const val of Object.keys(value)) { + const params = propName + '[' + val + ']' + const subPart = encodeURIComponent(params) + '=' + url += subPart + encodeURIComponent(value[val]) + '&' + } + } else { + url += `${propName}=${encodeURIComponent(value)}&` + } + } + } // 给 get 请求加上时间戳参数,避免从缓存中拿数据 // const now = new Date().getTime() // params = params.substring(0, url.length - 1) + `?_t=${now}` - url += '?' - const keys = Object.keys(params) - for (const key of keys) { - if (params[key] !== void 0 && params[key] !== null) { - url += `${key}=${encodeURIComponent(params[key])}&` - } - } + url = url.slice(0, -1) config.params = {} config.url = url } @@ -90,6 +98,13 @@ service.interceptors.response.use( const { t } = useI18n() // 未设置状态码则默认成功状态 const code = data.code || result_code + // 二进制数据则直接返回 + if ( + response.request.responseType === 'blob' || + response.request.responseType === 'arraybuffer' + ) { + return response.data + } // 获取错误信息 const msg = data.msg || errorCode[code] || errorCode['default'] if (ignoreMsgs.indexOf(msg) !== -1) { @@ -97,15 +112,16 @@ service.interceptors.response.use( return Promise.reject(msg) } else if (code === 401) { // 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了 - if (!isRefreshToken) { - isRefreshToken = true - // 1. 如果获取不到刷新令牌,则只能执行登出操作 - if (!getRefreshToken()) { - return handleAuthorized() - } - // 2. 进行刷新访问令牌 - // TODO: 引入refreshToken会循环依赖报错 - } + return handleAuthorized() + // if (!isRefreshToken) { + // isRefreshToken = true + // // 1. 如果获取不到刷新令牌,则只能执行登出操作 + // if (!getRefreshToken()) { + // return handleAuthorized() + // } + // // 2. 进行刷新访问令牌 + // // TODO: 引入refreshToken会循环依赖报错 + // } } else if (code === 500) { ElMessage.error(t('sys.api.errMsg500')) return Promise.reject(new Error(msg)) @@ -149,21 +165,12 @@ service.interceptors.response.use( return Promise.reject(error) } ) -function handleAuthorized() { +const handleAuthorized = () => { const { t } = useI18n() if (!isRelogin.show) { + removeToken() isRelogin.show = true - ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), { - confirmButtonText: t('login.relogin'), - cancelButtonText: t('common.cancel'), - type: 'warning' - }) - .then(() => { - isRelogin.show = false - }) - .catch(() => { - isRelogin.show = false - }) + ElNotification.error(t('sys.api.timeoutMessage')) } return Promise.reject(t('sys.api.timeoutMessage')) } diff --git a/yudao-ui-admin-vue3/src/utils/tree.ts b/yudao-ui-admin-vue3/src/utils/tree.ts index a82fb1c27..76ec0a2e1 100644 --- a/yudao-ui-admin-vue3/src/utils/tree.ts +++ b/yudao-ui-admin-vue3/src/utils/tree.ts @@ -213,7 +213,7 @@ export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => { * @param {*} parentId 父节点字段 默认 'parentId' * @param {*} children 孩子节点字段 默认 'children' */ -export const handleTree = (data, id?: string, parentId?: string, children?: string) => { +export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => { const config = { id: id || 'id', parentId: parentId || 'parentId', @@ -222,7 +222,7 @@ export const handleTree = (data, id?: string, parentId?: string, children?: stri const childrenListMap = {} const nodeIds = {} - const tree = [] + const tree: any[] = [] for (const d of data) { const parentId = d[config.parentId] diff --git a/yudao-ui-admin-vue3/src/views/infra/apiAccessLog/apiAccessLog.data.ts b/yudao-ui-admin-vue3/src/views/infra/apiAccessLog/apiAccessLog.data.ts index 97fae4357..69423dd9d 100644 --- a/yudao-ui-admin-vue3/src/views/infra/apiAccessLog/apiAccessLog.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/apiAccessLog/apiAccessLog.data.ts @@ -50,7 +50,16 @@ const crudSchemas = reactive<CrudSchema[]>([ }, { label: '请求时间', - field: 'beginTime' + field: 'beginTime', + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } + } }, { label: '执行时长', diff --git a/yudao-ui-admin-vue3/src/views/infra/apiErrorLog/apiErrorLog.data.ts b/yudao-ui-admin-vue3/src/views/infra/apiErrorLog/apiErrorLog.data.ts index 8ded13e8e..404262be5 100644 --- a/yudao-ui-admin-vue3/src/views/infra/apiErrorLog/apiErrorLog.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/apiErrorLog/apiErrorLog.data.ts @@ -50,7 +50,16 @@ const crudSchemas = reactive<CrudSchema[]>([ }, { label: '异常发生时间', - field: 'exceptionTime' + field: 'exceptionTime', + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } + } }, { label: '异常名', diff --git a/yudao-ui-admin-vue3/src/views/infra/codegen/codegen.data.ts b/yudao-ui-admin-vue3/src/views/infra/codegen/codegen.data.ts index 5253c9636..27e49ff31 100644 --- a/yudao-ui-admin-vue3/src/views/infra/codegen/codegen.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/codegen/codegen.data.ts @@ -50,6 +50,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/infra/config/config.data.ts b/yudao-ui-admin-vue3/src/views/infra/config/config.data.ts index c040d4fe3..425918d15 100644 --- a/yudao-ui-admin-vue3/src/views/infra/config/config.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/config/config.data.ts @@ -91,6 +91,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/dataSourceConfig.data.ts b/yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/dataSourceConfig.data.ts index 2d5869f2a..4431c0c45 100644 --- a/yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/dataSourceConfig.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/dataSourceConfig/dataSourceConfig.data.ts @@ -58,6 +58,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/infra/fileConfig/fileConfig.data.ts b/yudao-ui-admin-vue3/src/views/infra/fileConfig/fileConfig.data.ts index 6dd5e5e4a..b2383346f 100644 --- a/yudao-ui-admin-vue3/src/views/infra/fileConfig/fileConfig.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/fileConfig/fileConfig.data.ts @@ -76,6 +76,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/infra/fileList/fileList.data.ts b/yudao-ui-admin-vue3/src/views/infra/fileList/fileList.data.ts index 6984e693e..e203fd4cf 100644 --- a/yudao-ui-admin-vue3/src/views/infra/fileList/fileList.data.ts +++ b/yudao-ui-admin-vue3/src/views/infra/fileList/fileList.data.ts @@ -36,6 +36,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/pay/app/app.data.ts b/yudao-ui-admin-vue3/src/views/pay/app/app.data.ts index 652da6359..544428cba 100644 --- a/yudao-ui-admin-vue3/src/views/pay/app/app.data.ts +++ b/yudao-ui-admin-vue3/src/views/pay/app/app.data.ts @@ -8,9 +8,10 @@ const { t } = useI18n() // 国际化 // 表单校验 export const rules = reactive({ name: [required], - code: [required], - sort: [required], - status: [required] + status: [required], + payNotifyUrl: [required], + refundNotifyUrl: [required], + merchantId: [required] }) // CrudSchema @@ -53,6 +54,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/pay/merchant/merchant.data.ts b/yudao-ui-admin-vue3/src/views/pay/merchant/merchant.data.ts index 7db448ea9..53a2dc581 100644 --- a/yudao-ui-admin-vue3/src/views/pay/merchant/merchant.data.ts +++ b/yudao-ui-admin-vue3/src/views/pay/merchant/merchant.data.ts @@ -7,9 +7,9 @@ const { t } = useI18n() // 国际化 // 表单校验 export const rules = reactive({ + no: [required], name: [required], - code: [required], - sort: [required], + shortName: [required], status: [required] }) @@ -77,6 +77,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/pay/order/order.data.ts b/yudao-ui-admin-vue3/src/views/pay/order/order.data.ts index e16b9979f..8cdf1c9b0 100644 --- a/yudao-ui-admin-vue3/src/views/pay/order/order.data.ts +++ b/yudao-ui-admin-vue3/src/views/pay/order/order.data.ts @@ -157,6 +157,22 @@ const crudSchemas = reactive<CrudSchema[]>([ label: '渠道订单号', field: 'channelOrderNo' }, + { + label: t('common.createTime'), + field: 'createTime', + form: { + show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } + } + }, { label: t('table.action'), field: 'action', diff --git a/yudao-ui-admin-vue3/src/views/pay/refund/refund.data.ts b/yudao-ui-admin-vue3/src/views/pay/refund/refund.data.ts index 19c8e8ec9..6d1fef177 100644 --- a/yudao-ui-admin-vue3/src/views/pay/refund/refund.data.ts +++ b/yudao-ui-admin-vue3/src/views/pay/refund/refund.data.ts @@ -84,6 +84,15 @@ const crudSchemas = reactive<CrudSchema[]>([ field: 'createTime', form: { show: false + }, + search: { + show: true, + component: 'DatePicker', + componentProps: { + type: 'datetimerange', + valueFormat: 'YYYY-MM-DD HH:mm:ss', + defaultTime: [new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)] + } } }, { diff --git a/yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts b/yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts index 1a66624d3..ad6458699 100644 --- a/yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/dept/dept.data.ts @@ -1,5 +1,19 @@ import { required } from '@/utils/formRules' import { reactive } from 'vue' +// 表单校验 +export const rules = reactive({ + name: [required], + sort: [required], + email: [required], + phone: [ + { + pattern: + /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/, + trigger: 'blur', + message: '请输入正确的手机号码' + } + ] +}) export const modelSchema = reactive<FormSchema[]>([ { @@ -17,7 +31,7 @@ export const modelSchema = reactive<FormSchema[]>([ }, { label: '负责人', - field: 'email', + field: 'leaderUserId', component: 'Input' }, { @@ -33,7 +47,7 @@ export const modelSchema = reactive<FormSchema[]>([ { label: '显示排序', field: 'sort', - component: 'Input' + component: 'InputNumber' }, { label: '状态', diff --git a/yudao-ui-admin-vue3/src/views/system/dept/index.vue b/yudao-ui-admin-vue3/src/views/system/dept/index.vue index b956eb6a1..ea3c5f6dc 100644 --- a/yudao-ui-admin-vue3/src/views/system/dept/index.vue +++ b/yudao-ui-admin-vue3/src/views/system/dept/index.vue @@ -1,13 +1,14 @@ <script setup lang="ts"> import { useI18n } from '@/hooks/web/useI18n' -import { ElInput, ElCard, ElTree, ElTreeSelect } from 'element-plus' +import { ElInput, ElCard, ElTree, ElTreeSelect, ElSelect, ElOption } from 'element-plus' import { handleTree } from '@/utils/tree' import { onMounted, ref, unref, watch } from 'vue' import * as DeptApi from '@/api/system/dept' import { Form, FormExpose } from '@/components/Form' -import { modelSchema } from './dept.data' +import { modelSchema, rules } from './dept.data' import { DeptVO } from '@/api/system/dept/types' import { useMessage } from '@/hooks/web/useMessage' +import { getListSimpleUsersApi } from '@/api/system/user' const message = useMessage() interface Tree { id: number @@ -34,7 +35,7 @@ const filterText = ref('') const deptOptions = ref() // 树形结构 const treeRef = ref<InstanceType<typeof ElTree>>() const getTree = async () => { - const res = await DeptApi.getDeptPageApi(null) + const res = await DeptApi.listSimpleDeptApi() deptOptions.value = handleTree(res) } const filterNode = (value: string, data: Tree) => { @@ -44,6 +45,13 @@ const filterNode = (value: string, data: Tree) => { watch(filterText, (val) => { treeRef.value!.filter(val) }) +// 用户列表 +const userOption = ref() +const leaderUserId = ref() +const getUserList = async () => { + const res = await getListSimpleUsersApi() + userOption.value = res +} // 新增 const handleAdd = (data: { id: number }) => { // 重置表单 @@ -54,11 +62,12 @@ const handleAdd = (data: { id: number }) => { } // 编辑 const handleUpdate = async (data: { id: number }) => { - showForm.value = true const res = await DeptApi.getDeptApi(data.id) formTitle.value = '修改- ' + res?.name deptParentId.value = res.parentId + leaderUserId.value = res.leaderUserId unref(formRef)?.setValues(res) + showForm.value = true } // 删除 const handleDelete = async (data: { id: number }) => { @@ -78,7 +87,7 @@ const submitForm = async () => { try { const data = unref(formRef)?.formModel as DeptVO data.parentId = deptParentId.value - // TODO: 表单提交待完善 + data.leaderUserId = leaderUserId.value if (formTitle.value.startsWith('新增')) { await DeptApi.createDeptApi(data) } else if (formTitle.value.startsWith('修改')) { @@ -92,6 +101,7 @@ const submitForm = async () => { } onMounted(async () => { await getTree() + await getUserList() }) </script> <template> @@ -123,14 +133,29 @@ onMounted(async () => { <span class="custom-tree-node"> <span>{{ node.label }}</span> <span> - <el-button link v-hasPermi="['system:dept:create']" @click="handleAdd(data)"> - <Icon icon="ep:plus" class="mr-1px" /> + <el-button + link + type="primary" + v-hasPermi="['system:dept:create']" + @click="handleAdd(data)" + > + <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }} </el-button> - <el-button link v-hasPermi="['system:dept:update']" @click="handleUpdate(data)"> - <Icon icon="ep:edit" class="mr-1px" /> + <el-button + link + type="primary" + v-hasPermi="['system:dept:update']" + @click="handleUpdate(data)" + > + <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }} </el-button> - <el-button link v-hasPermi="['system:dept:delete']" @click="handleDelete(data)"> - <Icon icon="ep:delete" class="mr-1px" /> + <el-button + link + type="primary" + v-hasPermi="['system:dept:delete']" + @click="handleDelete(data)" + > + <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }} </el-button> </span> </span> @@ -149,7 +174,7 @@ onMounted(async () => { </div> <div v-if="showForm"> <!-- 操作工具栏 --> - <Form :schema="modelSchema" ref="formRef"> + <Form ref="formRef" :schema="modelSchema" :rules="rules"> <template #parentId> <el-tree-select node-key="id" @@ -159,6 +184,16 @@ onMounted(async () => { check-strictly /> </template> + <template #leaderUserId> + <el-select v-model="leaderUserId"> + <el-option + v-for="item in userOption" + :key="parseInt(item.id)" + :label="item.nickname" + :value="parseInt(item.id)" + /> + </el-select> + </template> </Form> <!-- 操作按钮 --> <el-button diff --git a/yudao-ui-admin-vue3/src/views/system/dict/dict.data.ts b/yudao-ui-admin-vue3/src/views/system/dict/dict.data.ts index 1e5670edc..6c869dbd8 100644 --- a/yudao-ui-admin-vue3/src/views/system/dict/dict.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/dict/dict.data.ts @@ -7,9 +7,9 @@ import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' const { t } = useI18n() // 表单校验 export const dictDataRules = reactive({ - dictType: [required], label: [required], - value: [required] + value: [required], + sort: [required] }) // crudSchemas export const crudSchemas = reactive<CrudSchema[]>([ @@ -29,6 +29,9 @@ export const crudSchemas = reactive<CrudSchema[]>([ field: 'dictType', table: { show: false + }, + form: { + show: false } }, { diff --git a/yudao-ui-admin-vue3/src/views/system/menu/index.vue b/yudao-ui-admin-vue3/src/views/system/menu/index.vue index 6fc6cda40..6286a9440 100644 --- a/yudao-ui-admin-vue3/src/views/system/menu/index.vue +++ b/yudao-ui-admin-vue3/src/views/system/menu/index.vue @@ -25,11 +25,12 @@ import { MenuVO } from '@/api/system/menu/types' import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { useMessage } from '@/hooks/web/useMessage' +import { required } from '@/utils/formRules.js' const message = useMessage() const { t } = useI18n() // 国际化 // ========== 创建菜单树结构 ========== const loading = ref(true) -const menuData = ref([]) // 树形结构 +const menuData = ref<any[]>([]) // 树形结构 const getList = async () => { const res = await MenuApi.getMenuListApi(queryParams) menuData.value = handleTree(res) @@ -44,7 +45,7 @@ const menuProps = { const menuOptions = ref() // 树形结构 const getTree = async () => { const res = await MenuApi.listSimpleMenusApi() - const menu = { id: 0, name: '主类目', children: [] } + const menu = { id: 0, name: '主类目', children: [] as any[] } menu.children = handleTree(res) console.info(menu) menuOptions.value = menu @@ -85,12 +86,12 @@ const menuForm = ref<MenuVO>({ createTime: '' }) // 表单校验 -const rules = { - name: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }], - sort: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }], - path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }], - status: [{ required: true, message: '状态不能为空', trigger: 'blur' }] -} +const rules = reactive({ + name: [required], + sort: [required], + path: [required], + status: [required] +}) // 设置标题 const setDialogTile = (type: string) => { dialogTitle.value = t('action.' + type) diff --git a/yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts b/yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts index 6c68a692d..bdf2f3ecb 100644 --- a/yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/notice/notice.data.ts @@ -8,8 +8,7 @@ const { t } = useI18n() // 国际化 // 表单校验 export const rules = reactive({ title: [required], - type: [required], - status: [required] + type: [required] }) // CrudSchema diff --git a/yudao-ui-admin-vue3/src/views/system/post/post.data.ts b/yudao-ui-admin-vue3/src/views/system/post/post.data.ts index 0e96fd745..a3383241f 100644 --- a/yudao-ui-admin-vue3/src/views/system/post/post.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/post/post.data.ts @@ -9,8 +9,7 @@ const { t } = useI18n() // 国际化 export const rules = reactive({ name: [required], code: [required], - sort: [required], - status: [required] + sort: [required] }) // CrudSchema diff --git a/yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/sms.template.data.ts b/yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/sms.template.data.ts index b491db583..55a1c8d67 100644 --- a/yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/sms.template.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/sms/smsTemplate/sms.template.data.ts @@ -8,13 +8,12 @@ const { t } = useI18n() // 国际化 // 表单校验 export const rules = reactive({ type: [required], + status: [required], + code: [required], name: [required], content: [required], apiTemplateId: [required], - channelId: [required], - code: [required], - sort: [required], - status: [required] + channelId: [required] }) // CrudSchema diff --git a/yudao-ui-admin-vue3/src/views/system/user/index.vue b/yudao-ui-admin-vue3/src/views/system/user/index.vue index 2f8d8a1ad..d6b4101c0 100644 --- a/yudao-ui-admin-vue3/src/views/system/user/index.vue +++ b/yudao-ui-admin-vue3/src/views/system/user/index.vue @@ -9,6 +9,7 @@ import { ElTreeSelect, ElSelect, ElOption, + ElTransfer, ElForm, ElFormItem, ElUpload, @@ -62,7 +63,7 @@ const { getList, setSearchParams, delList, exportList } = methods // ========== 创建部门树结构 ========== const filterText = ref('') -const deptOptions = ref([]) // 树形结构 +const deptOptions = ref<any[]>([]) // 树形结构 const searchForm = ref<FormExpose>() const treeRef = ref<InstanceType<typeof ElTree>>() const getTree = async () => { @@ -268,6 +269,7 @@ const handleFileSuccess = (response: any): void => { text += '< ' + username + ': ' + data.failureUsernames[username] + ' >' } message.alert(text) + getList() } // 文件数超出提示 const handleExceed = (): void => { @@ -281,8 +283,8 @@ const excelUploadError = (): void => { onMounted(async () => { await getTree() await getPostOptions() + await getList() }) -getList() </script> <template> @@ -482,7 +484,7 @@ getList() </template> </Dialog> <!-- 分配用户角色 --> - <Dialog v-model="roleDialogVisible" title="分配角色"> + <Dialog v-model="roleDialogVisible" title="分配角色" maxHeight="450px"> <el-form :model="userRole" label-width="80px"> <el-form-item label="用户名称"> <el-input v-model="userRole.username" :disabled="true" /> @@ -491,14 +493,15 @@ getList() <el-input v-model="userRole.nickname" :disabled="true" /> </el-form-item> <el-form-item label="角色"> - <el-select v-model="userRole.roleIds" multiple> - <el-option - v-for="item in roleOptions" - :key="parseInt(item.id)" - :label="item.name" - :value="parseInt(item.id)" - /> - </el-select> + <el-transfer + v-model="userRole.roleIds" + :titles="['角色列表', '已选择']" + :props="{ + key: 'id', + label: 'name' + }" + :data="roleOptions" + /> </el-form-item> </el-form> <!-- 操作按钮 --> diff --git a/yudao-ui-admin-vue3/src/views/system/user/user.data.ts b/yudao-ui-admin-vue3/src/views/system/user/user.data.ts index f4995edc3..ec7d6a502 100644 --- a/yudao-ui-admin-vue3/src/views/system/user/user.data.ts +++ b/yudao-ui-admin-vue3/src/views/system/user/user.data.ts @@ -7,8 +7,18 @@ import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' const { t } = useI18n() // 表单校验 export const rules = reactive({ + username: [required], nickname: [required], - status: [required] + email: [required], + status: [required], + mobile: [ + { + pattern: + /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/, + trigger: 'blur', + message: '请输入正确的手机号码' + } + ] }) // crudSchemas const crudSchemas = reactive<CrudSchema[]>([ diff --git a/yudao-ui-admin-vue3/use.md b/yudao-ui-admin-vue3/use.md new file mode 100644 index 000000000..bc100685a --- /dev/null +++ b/yudao-ui-admin-vue3/use.md @@ -0,0 +1,33 @@ +# 注意事项 + +- 项目路径请不要使用中文命名!!!会造成解析乱码!!!请使用全英文路径!!!全英文路径!!!全英文路径!!! +- node >=16 , pnpm >=7,非node16+ pnpm 7+ 安装问题不予解决、不适配 +- 开发建议使用 [谷歌浏览器-开发者版](https://www.google.cn/intl/zh-CN/chrome/dev/) 不支持 IE\QQ 等浏览器 +- 本框架使用 TypeScript ,简称ts,和java的类型差不多,为了简化没过多使用 type +- 本框架使用 Vue3.2 + setup语法糖,请自行学习相关内容 +- [点击查看:为什么Vue3.2,什么是setup,Vite为什么第一次加载速度慢](https://www.baidu.com) +- idea 怎么开发? 不知道。 +- 启动方式详见[README.md](./README.md) + +## 简单使用 + +- 目录结构与 vue2 版本基本保持一致 +- 一个页面(以post为例)由4部分组成 + +```bash +/src/api/system/post/ [index.ts | types.ts] +/src/views/system/post/ [index.vue | post.data.ts] +``` + +- 其中api内index.ts 与 vue2 基本一致,只不过axios封装了get post put delete upload download 等方法,不用写method: 'get' 了 +- api内types.ts,是接口中的类型声明,与java中vo等保持一致, java中long int => ts 中 number +- views中,index.vue 与 vue2 基本一致,本框架封装了Search Table Form Descriptions等组件,也可以按照vue2方式去写,参考menu +- post.data.ts 中主要是表单校验 rules 和表单 crudSchemas ,通过修改crudSchemas 就可以控制增删改查的字段、输入框还是下拉框等等 +- 本框架集成了国际化,不需要可以自己想办法移除,后期不会提供删减版 使用方式 + +```bash +import { useI18n } from '@/hooks/web/useI18n' +const { t } = useI18n() +t('common.createTime') +对应翻译文档在 src/locales +``` diff --git a/yudao-ui-admin-vue3/vite.config.ts b/yudao-ui-admin-vue3/vite.config.ts index 835c7e9f3..ef8ffe395 100644 --- a/yudao-ui-admin-vue3/vite.config.ts +++ b/yudao-ui-admin-vue3/vite.config.ts @@ -138,6 +138,7 @@ export default ({ command, mode }: ConfigEnv): UserConfig => { 'vue-router', 'vue-types', 'vue-i18n', + 'element-plus/es', 'element-plus/es/locale/lang/zh-cn', 'element-plus/es/locale/lang/en', '@iconify/iconify', diff --git a/yudao-ui-admin/src/views/system/dept/index.vue b/yudao-ui-admin/src/views/system/dept/index.vue index 02f7fe436..c8de00daf 100644 --- a/yudao-ui-admin/src/views/system/dept/index.vue +++ b/yudao-ui-admin/src/views/system/dept/index.vue @@ -167,7 +167,7 @@ export default { ], phone: [ { - pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, + pattern: /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" } diff --git a/yudao-ui-admin/src/views/system/tenant/index.vue b/yudao-ui-admin/src/views/system/tenant/index.vue index 3098fb4e1..c7a57b868 100755 --- a/yudao-ui-admin/src/views/system/tenant/index.vue +++ b/yudao-ui-admin/src/views/system/tenant/index.vue @@ -183,8 +183,6 @@ export default { accountCount: [{ required: true, message: "账号额度不能为空", trigger: "blur" }], expireTime: [{ required: true, message: "过期时间不能为空", trigger: "blur" }], domain: [{ required: true, message: "绑定域名不能为空", trigger: "blur" }], - username: [{ required: true, message: "用户名称不能为空", trigger: "blur" }], - password: [{ required: true, message: "用户密码不能为空", trigger: "blur" }], } }; },