diff --git a/apps/web-antd/.env b/apps/web-antd/.env index 975ea83cb4930585fc04e6c008b56883f7c3a0ae..affa214833742ef89e4b8469a16dea674165fa9b 100644 --- a/apps/web-antd/.env +++ b/apps/web-antd/.env @@ -3,14 +3,11 @@ VITE_APP_TITLE=芋道管理系统 # 应用命名空间,用于缓存、store等功能的前缀,确保隔离 VITE_APP_NAMESPACE=yudao-vben-antd +# 是否开启模拟数据 +VITE_NITRO_MOCK=false # 租户开关 VITE_APP_TENANT_ENABLE=true # 验证码的开关 -VITE_APP_CAPTCHA_ENABLE=false - -# 默认账户密码 -VITE_APP_DEFAULT_LOGIN_TENANT=芋道源码 -VITE_APP_DEFAULT_LOGIN_USERNAME=admin -VITE_APP_DEFAULT_LOGIN_PASSWORD=admin123 +VITE_APP_CAPTCHA_ENABLE=true diff --git a/apps/web-antd/.env.development b/apps/web-antd/.env.development index 3c441c7f45b10fe2ccccc42ffeaa45b1ebec5e68..fa8b5b0c83ee1d737aaac60a68759c63fe8631b6 100644 --- a/apps/web-antd/.env.development +++ b/apps/web-antd/.env.development @@ -5,12 +5,15 @@ VITE_BASE=/ # 接口地址 VITE_GLOB_API_URL=/admin-api - -# 是否开启 Nitro Mock服务,true 为开启,false 为关闭 -VITE_NITRO_MOCK=false - # 是否打开 devtools,true 为打开,false 为关闭 VITE_DEVTOOLS=false # 是否注入全局loading VITE_INJECT_APP_LOADING=true + +# 默认租户名称 +VITE_APP_DEFAULT_TENANT_NAME=芋道源码 +# 默认登录用户名 +VITE_APP_DEFAULT_USERNAME=admin +# 默认登录密码 +VITE_APP_DEFAULT_PASSWORD=admin123 diff --git a/apps/web-antd/package.json b/apps/web-antd/package.json index 8906b9c8c5b6636543b4310a8625b220b06643b6..42afa3c696d2df2539f2224c3a7c3470220effa1 100644 --- a/apps/web-antd/package.json +++ b/apps/web-antd/package.json @@ -42,13 +42,9 @@ "@vben/utils": "workspace:*", "@vueuse/core": "catalog:", "ant-design-vue": "catalog:", - "crypto-js": "^4.2.0", "dayjs": "catalog:", "pinia": "catalog:", "vue": "catalog:", "vue-router": "catalog:" - }, - "devDependencies": { - "@types/crypto-js": "^4.2.2" } } diff --git a/apps/web-antd/src/adapter/component/index.ts b/apps/web-antd/src/adapter/component/index.ts index 1afa62174637a977bf5f2d28e5a1ce0225fa45ad..9e1028960c4d7ba89f78a33f3de8b06597ed5279 100644 --- a/apps/web-antd/src/adapter/component/index.ts +++ b/apps/web-antd/src/adapter/component/index.ts @@ -5,6 +5,8 @@ import type { BaseFormComponentType } from '@vben/common-ui'; +import type { CustomComponentType } from '#/components/form/types'; + import type { Component, SetupContext } from 'vue'; import { h } from 'vue'; @@ -36,6 +38,8 @@ import { Upload, } from 'ant-design-vue'; +import { registerComponent as registerCustomFormComponent } from '#/components/form/component-map'; + const withDefaultPlaceholder = ( component: T, type: 'input' | 'select', @@ -70,7 +74,8 @@ export type ComponentType = | 'TimePicker' | 'TreeSelect' | 'Upload' - | BaseFormComponentType; + | BaseFormComponentType + | CustomComponentType; async function initComponentAdapter() { const components: Partial> = { @@ -108,6 +113,9 @@ async function initComponentAdapter() { Upload, }; + // 注册自定义组件 + registerCustomFormComponent(components); + // 将组件注册到全局共享状态中 globalShareState.setComponents(components); diff --git a/apps/web-antd/src/adapter/vxe-table.ts b/apps/web-antd/src/adapter/vxe-table.ts index 6afe838b596048a57939e17e555f186faf5703cc..0a346d3ae0668b7777d47b6aa0c27ffed26fe30f 100644 --- a/apps/web-antd/src/adapter/vxe-table.ts +++ b/apps/web-antd/src/adapter/vxe-table.ts @@ -20,6 +20,17 @@ setupVbenVxeTable({ // 全局禁用vxe-table的表单配置,使用formOptions enabled: false, }, + toolbarConfig: { + import: true, + export: true, + refresh: true, + print: true, + zoom: true, + custom: true, + }, + customConfig: { + mode: 'modal', + }, proxyConfig: { autoLoad: true, response: { @@ -29,6 +40,12 @@ setupVbenVxeTable({ showActiveMsg: true, showResponseMsg: false, }, + pagerConfig: { + enabled: true, + }, + sortConfig: { + multiple: true, + }, round: true, showOverflow: true, size: 'small', diff --git a/apps/web-antd/src/api/core/auth.ts b/apps/web-antd/src/api/core/auth.ts index 4efd5029f1f5eec3226d9331f84309ed3d4a4411..802094c157985a1915f4891f5660d5566b8a4c85 100644 --- a/apps/web-antd/src/api/core/auth.ts +++ b/apps/web-antd/src/api/core/auth.ts @@ -1,7 +1,6 @@ -import type { YudaoUserInfo } from '#/types'; +import type { AuthPermissionInfo } from '@vben/types'; import { baseRequestClient, requestClient } from '#/api/request'; -import { getRefreshToken } from '#/utils'; export namespace AuthApi { /** 登录接口参数 */ @@ -13,121 +12,78 @@ export namespace AuthApi { /** 登录接口返回值 */ export interface LoginResult { - userId: number | string; accessToken: string; refreshToken: string; + userId: number; expiresTime: number; } - export interface RefreshTokenResult { - data: string; - status: number; - } - export interface SmsCodeVO { - mobile: string; - scene: number; - } - - export interface SmsLoginVO { - mobile: string; - code: string; + export interface TenantSimple { + id: number; + name: string; } } /** * 登录 */ -export function loginApi(data: AuthApi.LoginParams) { +export async function loginApi(data: AuthApi.LoginParams) { return requestClient.post('/system/auth/login', data); } /** * 刷新accessToken */ -export function refreshTokenApi() { +export async function refreshTokenApi(refreshToken: string) { return requestClient.post( - `/system/auth/refresh-token?refreshToken=${getRefreshToken()}`, + `/system/auth/refresh-token?refreshToken=${refreshToken}`, ); } -/** - * 使用租户名,获得租户编号 - * @param name 租户名 - * @returns 租户编号 - */ -export function getTenantIdByName(name: string) { - return requestClient.get( - `/system/tenant/get-id-by-name?name=${name}`, - ); -} - -/** - * 使用租户域名,获得租户信息 - * @param website 域名 - * @returns 租户信息 - */ -export function getTenantByWebsite(website: string) { - return requestClient.get(`/system/tenant/get-by-website?website=${website}`); -} - /** * 退出登录 */ -export function logoutApi() { +export async function logoutApi() { return requestClient.post('/system/auth/logout'); } /** * 获取用户权限信息 */ -export function getUserInfo() { - return requestClient.get('/system/auth/get-permission-info'); -} - -/** - * 获取登录验证码 - */ -export function sendSmsCode(data: AuthApi.SmsCodeVO) { - return requestClient.post('/system/auth/send-sms-code', data); -} - -/** - * 短信验证码登录 - */ -export function smsLogin(data: AuthApi.SmsLoginVO) { - return requestClient.post('/system/auth/sms-login', data); +export function getAuthPermissionInfoApi() { + return requestClient.get( + '/system/auth/get-permission-info', + ); } /** - * 社交快捷登录,使用 code 授权码 + * 使用租户名,获得租户编号 + * @param name 租户名 + * @returns 租户编号 */ -export function socialLogin(type: string, code: string, state: string) { - return requestClient.post('/system/auth/social-login', { - type, - code, - state, - }); +export async function getTenantIdByName(name: string) { + return requestClient.get( + `/system/tenant/get-id-by-name?name=${name}`, + ); } /** - * 社交授权的跳转 + * 使用租户域名,获得租户信息 + * @param website 域名 + * @returns 租户信息 */ -export function socialAuthRedirect(type: number, redirectUri: string) { - return requestClient.get( - `/system/auth/social-auth-redirect?type=${type}&redirectUri=${redirectUri}`, +export async function getTenantByWebsite(website: string) { + return requestClient.get( + `/system/tenant/get-by-website?website=${website}`, ); } -/** - * 获取验证图片 以及token - */ -export function getCaptcha(data: any) { +// 获取验证图片 以及token +export async function getCaptcha(data: any) { return baseRequestClient.post('/system/captcha/get', data); } -/** - * 滑动或者点选验证 - */ -export function checkCaptcha(data: any) { +// 滑动或者点选验证 +export async function checkCaptcha(data: any) { return baseRequestClient.post('/system/captcha/check', data); } diff --git a/apps/web-antd/src/api/infra/codegen/index.ts b/apps/web-antd/src/api/infra/codegen/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..0276b19835ee7f4ee13af0f52333a8eb3fe2518f --- /dev/null +++ b/apps/web-antd/src/api/infra/codegen/index.ts @@ -0,0 +1,312 @@ +import { type PageParam, requestClient } from '#/api/request'; + +export namespace CodegenApi { + /** + * 代码生成字段定义 Response VO + */ + export interface CodegenColumnRespVO { + /** 编号 */ + id: number; + /** 表编号 */ + tableId: number; + /** 字段名 */ + columnName: string; + /** 字段类型 */ + dataType: string; + /** 字段描述 */ + columnComment: string; + /** 是否允许为空 */ + nullable: boolean; + /** 是否主键 */ + primaryKey: boolean; + /** 排序 */ + ordinalPosition: number; + /** Java 属性类型 */ + javaType: string; + /** Java 属性名 */ + javaField: string; + /** 字典类型 */ + dictType?: string; + /** 数据示例 */ + example?: string; + /** 是否为 Create 创建操作的字段 */ + createOperation: boolean; + /** 是否为 Update 更新操作的字段 */ + updateOperation: boolean; + /** 是否为 List 查询操作的字段 */ + listOperation: boolean; + /** List 查询操作的条件类型 */ + listOperationCondition: string; + /** 是否为 List 查询操作的返回字段 */ + listOperationResult: boolean; + /** 显示类型 */ + htmlType: string; + /** 创建时间 */ + createTime: string; // 假设为 ISO 字符串格式的 LocalDateTime + } + + /** + * 代码生成字段定义创建/修改 Request VO + */ + export interface CodegenColumnSaveReqVO { + /** 编号 */ + id: number; + /** 表编号 */ + tableId: number; + /** 字段名 */ + columnName: string; + /** 字段类型 */ + dataType: string; + /** 字段描述 */ + columnComment: string; + /** 是否允许为空 */ + nullable: boolean; + /** 是否主键 */ + primaryKey: boolean; + /** 排序 */ + ordinalPosition: number; + /** Java 属性类型 */ + javaType: string; + /** Java 属性名 */ + javaField: string; + /** 字典类型 */ + dictType?: string; + /** 数据示例 */ + example?: string; + /** 是否为 Create 创建操作的字段 */ + createOperation: boolean; + /** 是否为 Update 更新操作的字段 */ + updateOperation: boolean; + /** 是否为 List 查询操作的字段 */ + listOperation: boolean; + /** List 查询操作的条件类型 */ + listOperationCondition: string; + /** 是否为 List 查询操作的返回字段 */ + listOperationResult: boolean; + /** 显示类型 */ + htmlType: string; + } + + /** + * 表定义分页 Request VO + */ + export interface CodegenTablePageReqVO { + /** 表名称,模糊匹配 */ + tableName?: string; + /** 表描述,模糊匹配 */ + tableComment?: string; + /** 实体,模糊匹配 */ + className?: string; + /** 创建时间 */ + createTime?: [string, string]; // 假设为 ISO 字符串格式的 LocalDateTime + } + + /** + * 代码生成表定义 Response VO + */ + export interface CodegenTableRespVO { + /** 编号 */ + id: number; + /** 生成场景 */ + scene: number; + /** 表名称 */ + tableName: string; + /** 表描述 */ + tableComment: string; + /** 备注 */ + remark?: string; + /** 模块名 */ + moduleName: string; + /** 业务名 */ + businessName: string; + /** 类名称 */ + className: string; + /** 类描述 */ + classComment: string; + /** 作者 */ + author: string; + /** 模板类型 */ + templateType: number; + /** 前端类型 */ + frontType: number; + /** 父菜单编号 */ + parentMenuId?: number; + /** 主表的编号 */ + masterTableId?: number; + /** 子表关联主表的字段编号 */ + subJoinColumnId?: number; + /** 主表与子表是否一对多 */ + subJoinMany?: boolean; + /** 树表的父字段编号 */ + treeParentColumnId?: number; + /** 树表的名字字段编号 */ + treeNameColumnId?: number; + /** 主键编号 */ + dataSourceConfigId: number; + /** 创建时间 */ + createTime: string; // 假设为 ISO 字符串格式的 LocalDateTime + /** 更新时间 */ + updateTime: string; // 假设为 ISO 字符串格式的 LocalDateTime + } + + /** + * 代码生成表定义创建/修改 Response VO + */ + export interface CodegenTableSaveReqVO { + /** 编号 */ + id: number; + /** 生成场景 */ + scene: number; + /** 表名称 */ + tableName: string; + /** 表描述 */ + tableComment: string; + /** 备注 */ + remark?: string; + /** 模块名 */ + moduleName: string; + /** 业务名 */ + businessName: string; + /** 类名称 */ + className: string; + /** 类描述 */ + classComment: string; + /** 作者 */ + author: string; + /** 模板类型 */ + templateType: number; + /** 前端类型 */ + frontType: number; + /** 父菜单编号 */ + parentMenuId?: number; + /** 主表的编号 */ + masterTableId?: number; + /** 子表关联主表的字段编号 */ + subJoinColumnId?: number; + /** 主表与子表是否一对多 */ + subJoinMany?: boolean; + /** 树表的父字段编号 */ + treeParentColumnId?: number; + /** 树表的名字字段编号 */ + treeNameColumnId?: number; + } + + /** + * 数据库的表定义 Response VO + */ + export interface DatabaseTableRespVO { + /** 表名称 */ + name: string; + /** 表描述 */ + comment: string; + } + + /** + * 基于数据库的表结构,创建代码生成器的表和字段定义 Request VO + */ + export interface CodegenCreateListReqVO { + /** 数据源配置的编号 */ + dataSourceConfigId: number; + /** 表名数组 */ + tableNames: string[]; + } + + /** + * 代码生成表和字段的明细 Response VO + */ + export interface CodegenDetailRespVO { + /** 表定义 */ + table: CodegenTableRespVO; + /** 字段定义 */ + columns: CodegenColumnRespVO[]; + } + + /** + * 代码生成预览 Response VO + */ + export interface CodegenPreviewRespVO { + /** 文件路径 */ + filePath: string; + /** 代码 */ + code: string; + } + + /** + * 代码生成表和字段的修改 Request VO + */ + export interface CodegenUpdateReqVO { + /** 表定义 */ + table: CodegenTableSaveReqVO; + /** 字段定义 */ + columns: CodegenColumnSaveReqVO[]; + } +} + +// 查询列表代码生成表定义 +export const getCodegenTableList = (dataSourceConfigId: number) => { + return requestClient.get( + `/infra/codegen/table/list?dataSourceConfigId=${dataSourceConfigId}`, + ); +}; + +// 查询列表代码生成表定义 +export const getCodegenTablePage = (params: PageParam) => { + return requestClient.get( + '/infra/codegen/table/page', + { params }, + ); +}; + +// 查询详情代码生成表定义 +export const getCodegenTable = (id: number) => { + return requestClient.get( + `/infra/codegen/detail?tableId=${id}`, + ); +}; + +// 新增代码生成表定义 +export const createCodegenTable = (data: CodegenApi.CodegenCreateListReqVO) => { + return requestClient.post('/infra/codegen/create', data); +}; + +// 修改代码生成表定义 +export const updateCodegenTable = (data: CodegenApi.CodegenUpdateReqVO) => { + return requestClient.put('/infra/codegen/update', data); +}; + +// 基于数据库的表结构,同步数据库的表和字段定义 +export const syncCodegenFromDB = (id: number) => { + return requestClient.put(`/infra/codegen/sync-from-db?tableId=${id}`); +}; + +// 预览生成代码 +export const previewCodegen = (id: number) => { + return requestClient.get(`/infra/codegen/preview?tableId=${id}`); +}; + +// 下载生成代码 +export const downloadCodegen = (id: number) => { + return requestClient.download(`/infra/codegen/download?tableId=${id}`); +}; + +// 获得表定义 +export const getSchemaTableList = (params: { + comment?: string; + dataSourceConfigId: number; + name?: string; +}) => { + return requestClient.get( + '/infra/codegen/db/table/list', + { params }, + ); +}; + +// 基于数据库的表结构,创建代码生成器的表定义 +export const createCodegenList = (data: CodegenApi.CodegenCreateListReqVO) => { + return requestClient.post('/infra/codegen/create-list', data); +}; + +// 删除代码生成表定义 +export const deleteCodegenTable = (id: number) => { + return requestClient.delete(`/infra/codegen/delete?tableId=${id}`); +}; diff --git a/apps/web-antd/src/api/infra/data-source-config/index.ts b/apps/web-antd/src/api/infra/data-source-config/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..33559c9c11b6bb16d63565a14d2dcccea5d06047 --- /dev/null +++ b/apps/web-antd/src/api/infra/data-source-config/index.ts @@ -0,0 +1,51 @@ +import { requestClient } from '#/api/request'; + +export namespace DataSourceConfigApi { + export interface DataSourceConfigRespVO { + id: number; + name: string; + url: string; + username: string; + createTime?: Date; + } + + export interface DataSourceConfigSaveReqVO { + id?: number; + name: string; + url: string; + username: string; + password: string; + } +} +// 新增数据源配置 +export const createDataSourceConfig = ( + data: DataSourceConfigApi.DataSourceConfigSaveReqVO, +) => { + return requestClient.post('/infra/data-source-config/create', data); +}; + +// 修改数据源配置 +export const updateDataSourceConfig = ( + data: DataSourceConfigApi.DataSourceConfigSaveReqVO, +) => { + return requestClient.put('/infra/data-source-config/update', data); +}; + +// 删除数据源配置 +export const deleteDataSourceConfig = (id: number) => { + return requestClient.delete(`/infra/data-source-config/delete?id=${id}`); +}; + +// 查询数据源配置详情 +export const getDataSourceConfig = (id: number) => { + return requestClient.get( + `/infra/data-source-config/get?id=${id}`, + ); +}; + +// 查询数据源配置列表 +export const getDataSourceConfigList = () => { + return requestClient.get( + '/infra/data-source-config/list', + ); +}; diff --git a/apps/web-antd/src/api/request.ts b/apps/web-antd/src/api/request.ts index 819b9c223504e1de11d7ed2b80055f3c362bfdde..f5a81a2627263485e26cb70a1717e3e18acd9c69 100644 --- a/apps/web-antd/src/api/request.ts +++ b/apps/web-antd/src/api/request.ts @@ -10,19 +10,15 @@ import { errorMessageResponseInterceptor, RequestClient, } from '@vben/request'; -import { useAccessStore } from '@vben/stores'; +import { useAccessStore, useTenantStore } from '@vben/stores'; import { message } from 'ant-design-vue'; import { useAuthStore } from '#/store'; -import { getTenantId } from '#/utils'; import { refreshTokenApi } from './core'; -const { apiURL, tenantEnable } = useAppConfig( - import.meta.env, - import.meta.env.PROD, -); +const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); function createRequestClient(baseURL: string) { const client = new RequestClient({ @@ -52,9 +48,12 @@ function createRequestClient(baseURL: string) { */ async function doRefreshToken() { const accessStore = useAccessStore(); - const resp = await refreshTokenApi(); - const newToken = resp.refreshToken; + const resp = await refreshTokenApi(accessStore.refreshToken ?? ''); + const newToken = resp.accessToken; + const newRefreshToken = resp.refreshToken; + accessStore.setAccessToken(newToken); + accessStore.setRefreshToken(newRefreshToken); return newToken; } @@ -66,11 +65,11 @@ function createRequestClient(baseURL: string) { client.addRequestInterceptor({ fulfilled: async (config) => { const accessStore = useAccessStore(); - const tenantId = getTenantId(); + const tenantStore = useTenantStore(); + config.headers.Authorization = formatToken(accessStore.accessToken); config.headers['Accept-Language'] = preferences.app.locale; - config.headers['tenant-id'] = - tenantEnable && tenantId ? tenantId : undefined; + config.headers['tenant-id'] = tenantStore.tenantId ?? undefined; return config; }, }); @@ -78,32 +77,13 @@ function createRequestClient(baseURL: string) { // response数据解构 client.addResponseInterceptor({ fulfilled: (response) => { - // const { config, data: responseData, status, request } = response; - const { data: responseData, request } = response; - // 这个判断的目的是:excel 导出等情况下,系统执行异常,此时返回的是 json,而不是二进制数据 - if ( - (request.responseType === 'blob' || - request.responseType === 'arraybuffer') && - responseData?.code === undefined - ) { - return responseData; - } + const { data: responseData, status } = response; - const { code, data: result } = responseData; - if (responseData && Reflect.has(responseData, 'code') && code === 0) { - return result; - } - - switch (code) { - case 401: { - response.status = 401; - throw Object.assign({}, response, { response }); - } - default: { - response.status = code; - throw Object.assign({}, response, { response }); - } + const { code, data } = responseData; + if (status >= 200 && status < 400 && code === 0) { + return data; } + throw Object.assign({}, response, { response }); }, }); @@ -124,7 +104,8 @@ function createRequestClient(baseURL: string) { // 这里可以根据业务进行定制,你可以拿到 error 内的信息进行定制化处理,根据不同的 code 做不同的提示,而不是直接使用 message.error 提示 msg // 当前mock接口返回的错误字段是 error 或者 message const responseData = error?.response?.data ?? {}; - const errorMessage = responseData?.error ?? responseData?.message ?? ''; + const errorMessage = + responseData?.error ?? responseData?.message ?? responseData.msg ?? ''; // 如果没有错误信息,则会根据状态码进行提示 message.error(errorMessage || msg); }), @@ -133,11 +114,8 @@ function createRequestClient(baseURL: string) { return client; } -export type PageParam = { - pageNo?: number; - pageSize?: number; -}; - export const requestClient = createRequestClient(apiURL); export const baseRequestClient = new RequestClient({ baseURL: apiURL }); + +export type * from '@vben/request'; diff --git a/apps/web-antd/src/api/system/dict-data/index.ts b/apps/web-antd/src/api/system/dict-data/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b89e1ac44c862b7fb525a3ea33fb052065a8a14 --- /dev/null +++ b/apps/web-antd/src/api/system/dict-data/index.ts @@ -0,0 +1,89 @@ +import { type PageParam, requestClient } from '#/api/request'; + +export namespace DictDataApi { + /** + * 字典数据信息 Response VO + */ + export type DictDataRespVO = { + colorType?: string; + createTime?: Date; + cssClass?: string; + dictType: string; + id?: number; + label: string; + remark?: string; + sort?: number; + status?: number; + value: string; + }; + + /** + * 字典类型分页列表 Request VO + */ + export interface DictDataPageReqVO extends PageParam { + dictType?: string; + label?: string; + status?: number; + } + + /** + * 字典数据创建/修改 Request VO + */ + export interface DictDataSaveReqVO { + colorType?: string; + cssClass?: string; + dictType: string; + id?: number; + label: string; + remark?: string; + sort?: number; + status?: number; + value: string; + } + + /** + * 字典数据(精简) Response VO + */ + export interface DictDataSimpleRespVO { + colorType?: string; + cssClass?: string; + dictType: string; + label: string; + value: string; + } +} + +// 查询字典数据(精简)列表 +export const getSimpleDictDataList = () => { + return requestClient.get('/system/dict-data/simple-list'); +}; + +// 查询字典数据列表 +export const getDictDataPage = (params: PageParam) => { + return requestClient.get('/system/dict-data/page', { params }); +}; + +// 查询字典数据详情 +export const getDictData = (id: number) => { + return requestClient.get(`/system/dict-data/get?id=${id}`); +}; + +// 新增字典数据 +export const createDictData = (data: DictDataApi.DictDataSaveReqVO) => { + return requestClient.post('/system/dict-data/create', data); +}; + +// 修改字典数据 +export const updateDictData = (data: DictDataApi.DictDataSaveReqVO) => { + return requestClient.put('/system/dict-data/update', data); +}; + +// 删除字典数据 +export const deleteDictData = (id: number) => { + return requestClient.delete(`/system/dict-data/delete?id=${id}`); +}; + +// 导出字典类型数据 +export const exportDictData = (params: DictDataApi.DictDataPageReqVO) => { + return requestClient.download('/system/dict-data/export', { params }); +}; diff --git a/apps/web-antd/src/api/system/dict-type/index.ts b/apps/web-antd/src/api/system/dict-type/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e8f0f04ceacd61dd4d31657f3c47d50670006159 --- /dev/null +++ b/apps/web-antd/src/api/system/dict-type/index.ts @@ -0,0 +1 @@ +export namespace DictTypeApi {} diff --git a/apps/web-antd/src/api/system/dict/dict.data.ts b/apps/web-antd/src/api/system/dict/dict.data.ts deleted file mode 100644 index c5f9f49894e7e428cf7c2dbf4f097614c9022777..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/api/system/dict/dict.data.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { requestClient } from '#/api/request'; - -export type DictDataVO = { - colorType: string; - createTime: Date; - cssClass: string; - dictType: string; - id: number | undefined; - label: string; - remark: string; - sort: number | undefined; - status: number; - value: string; -}; - -// 查询字典数据(精简)列表 -export function getSimpleDictDataList() { - return requestClient.get('/system/dict-data/simple-list'); -} - -// 查询字典数据列表 -export function getDictDataPage(params: any) { - return requestClient.get('/system/dict-data/page', params); -} - -// 查询字典数据详情 -export function getDictData(id: number) { - return requestClient.get(`/system/dict-data/get?id=${id}`); -} - -// 新增字典数据 -export function createDictData(data: DictDataVO) { - return requestClient.post('/system/dict-data/create', data); -} - -// 修改字典数据 -export function updateDictData(data: DictDataVO) { - return requestClient.put('/system/dict-data/update', data); -} - -// 删除字典数据 -export function deleteDictData(id: number) { - return requestClient.delete(`/system/dict-data/delete?id=${id}`); -} - -// 导出字典类型数据 -export function exportDictData(params: any) { - return requestClient.download('/system/dict-data/export', params); -} diff --git a/apps/web-antd/src/api/system/dict/dict.type.ts b/apps/web-antd/src/api/system/dict/dict.type.ts deleted file mode 100644 index 59af57114c02f46b31ffa3c50c39a01344216c20..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/api/system/dict/dict.type.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { requestClient } from '#/api/request'; - -export type DictTypeVO = { - createTime: Date; - id: number | undefined; - name: string; - remark: string; - status: number; - type: string; -}; - -// 查询字典(精简)列表 -export function getSimpleDictTypeList() { - return requestClient.get('/system/dict-type/list-all-simple'); -} - -// 查询字典列表 -export function getDictTypePage(params: any) { - return requestClient.get('/system/dict-type/page', params); -} - -// 查询字典详情 -export function getDictType(id: number) { - return requestClient.get(`/system/dict-type/get?id=${id}`); -} - -// 新增字典 -export function createDictType(data: DictTypeVO) { - return requestClient.post('/system/dict-type/create', data); -} - -// 修改字典 -export function updateDictType(data: DictTypeVO) { - return requestClient.put('/system/dict-type/update', data); -} - -// 删除字典 -export function deleteDictType(id: number) { - return requestClient.delete(`/system/dict-type/delete?id=${id}`); -} -// 导出字典类型 -export function exportDictType(params: any) { - return requestClient.download('/system/dict-type/export', params); -} diff --git a/apps/web-antd/src/components/Verification/index.ts b/apps/web-antd/src/components/Verification/index.ts deleted file mode 100644 index 0d53aa67016f77d44747694354e479ca35aaa4a7..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/components/Verification/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Verify } from './src/Verify.vue'; diff --git a/apps/web-antd/src/components/Verification/src/Verify.vue b/apps/web-antd/src/components/Verification/src/Verify.vue deleted file mode 100644 index 53199c6e8c58f37c11c2e23dd41636d571d671e6..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/components/Verification/src/Verify.vue +++ /dev/null @@ -1,162 +0,0 @@ - - - diff --git a/apps/web-antd/src/components/description/description.vue b/apps/web-antd/src/components/description/description.vue new file mode 100644 index 0000000000000000000000000000000000000000..ec5e220edcacb290e992a08b03dc8a134b38b6f9 --- /dev/null +++ b/apps/web-antd/src/components/description/description.vue @@ -0,0 +1,77 @@ + + diff --git a/apps/web-antd/src/components/description/index.ts b/apps/web-antd/src/components/description/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..745e7550a39ab6726d52c5e926496f96455fd82a --- /dev/null +++ b/apps/web-antd/src/components/description/index.ts @@ -0,0 +1,2 @@ +export { default as Description } from './description.vue'; +export type * from './types'; diff --git a/apps/web-antd/src/components/description/types.d.ts b/apps/web-antd/src/components/description/types.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5120b8e849e40c242a6e3ecb5fc62d468b4e09f --- /dev/null +++ b/apps/web-antd/src/components/description/types.d.ts @@ -0,0 +1,54 @@ +import type { CollapseContainerOptions } from '@/components/Container'; +import type { DescriptionsProps } from 'ant-design-vue/es/descriptions'; + +import type { CSSProperties, VNode } from 'vue'; + +export interface DescItem { + labelMinWidth?: number; + contentMinWidth?: number; + labelStyle?: CSSProperties; + field: string; + label: JSX.Element | string | VNode; + // Merge column + span?: number; + show?: (...arg: any) => boolean; + // render + render?: ( + val: any, + data: Recordable, + ) => Element | JSX.Element | number | string | undefined | VNode; + component: string; + componentProps?: any; + children?: DescItem[]; +} + +export interface DescriptionProps extends DescriptionsProps { + // Whether to include the collapse component + useCollapse?: boolean; + /** + * item configuration + * @type DescItem + */ + schema: DescItem[]; + /** + * 数据 + * @type object + */ + data: Recordable; + /** + * Built-in CollapseContainer component configuration + * @type CollapseContainerOptions + */ + collapseOptions?: CollapseContainerOptions; +} + +export interface DescInstance { + setDescProps(descProps: Partial): void; +} + +export type Register = (descInstance: DescInstance) => void; + +/** + * @description: + */ +export type UseDescReturnType = [Register, DescInstance]; diff --git a/apps/web-antd/src/components/form/component-map.ts b/apps/web-antd/src/components/form/component-map.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4f664454399cc1c87c18f37635f9433d17d6949 --- /dev/null +++ b/apps/web-antd/src/components/form/component-map.ts @@ -0,0 +1,37 @@ +import type { CustomComponentType } from './types'; + +import type { Component } from 'vue'; + +import { kebabToCamelCase } from '@vben/utils'; + +const componentMap = new Map(); +// import.meta.glob() 直接引入所有的模块 Vite 独有的功能 +const modules = import.meta.glob('./components/**/*.vue', { eager: true }); +// 加入到路由集合中 +Object.keys(modules).forEach((key) => { + if (!key.includes('-ignore')) { + const mod = (modules as any)[key].default || {}; + // ./components/ApiDict.vue + // 获取ApiDict + const compName = key.replace('./components/', '').replace('.vue', ''); + componentMap.set(kebabToCamelCase(compName), mod); + } +}); + +export function add(compName: string, component: Component) { + componentMap.set(compName, component); +} + +export function del(compName: string) { + componentMap.delete(compName); +} +/** + * 注册组件 + * @param components + */ +export const registerComponent = (components: any) => { + componentMap.forEach((value, key) => { + components[key] = value as Component; + }); +}; +export { componentMap }; diff --git a/apps/web-antd/src/components/form/components/api-checkbox-group.vue b/apps/web-antd/src/components/form/components/api-checkbox-group.vue new file mode 100644 index 0000000000000000000000000000000000000000..1ef81da25b82da28b3e80a79c5358d9456d70112 --- /dev/null +++ b/apps/web-antd/src/components/form/components/api-checkbox-group.vue @@ -0,0 +1,137 @@ + + + diff --git a/apps/web-antd/src/components/form/components/api-dict.vue b/apps/web-antd/src/components/form/components/api-dict.vue new file mode 100644 index 0000000000000000000000000000000000000000..6b9f80db36c6a127a278a94d8019b904eece918e --- /dev/null +++ b/apps/web-antd/src/components/form/components/api-dict.vue @@ -0,0 +1,53 @@ + + diff --git a/apps/web-antd/src/components/form/components/api-radio-group.vue b/apps/web-antd/src/components/form/components/api-radio-group.vue new file mode 100644 index 0000000000000000000000000000000000000000..d87e744562f3775b2f79d4928f093c2f0c8944c0 --- /dev/null +++ b/apps/web-antd/src/components/form/components/api-radio-group.vue @@ -0,0 +1,143 @@ + + + diff --git a/apps/web-antd/src/components/form/components/api-select.vue b/apps/web-antd/src/components/form/components/api-select.vue new file mode 100644 index 0000000000000000000000000000000000000000..4e6f1772aa57b5373631b2962b8d4f58a96db1cd --- /dev/null +++ b/apps/web-antd/src/components/form/components/api-select.vue @@ -0,0 +1,150 @@ + + + diff --git a/apps/web-antd/src/components/form/components/api-tree-select.vue b/apps/web-antd/src/components/form/components/api-tree-select.vue new file mode 100644 index 0000000000000000000000000000000000000000..776ce772039efafc3f70891486c4fe90a7f3fee2 --- /dev/null +++ b/apps/web-antd/src/components/form/components/api-tree-select.vue @@ -0,0 +1,140 @@ + + + diff --git a/apps/web-antd/src/components/form/index.ts b/apps/web-antd/src/components/form/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..750820af19c1b51d18a0d9cf04834c6e2eb103ff --- /dev/null +++ b/apps/web-antd/src/components/form/index.ts @@ -0,0 +1,5 @@ +export { default as ApiCheckboxGroup } from './components/api-checkbox-group.vue'; +export { default as ApiDict } from './components/api-dict.vue'; +export { default as ApiRadioGroup } from './components/api-radio-group.vue'; +export { default as ApiSelect } from './components/api-select.vue'; +export { default as ApiTreeSelect } from './components/api-tree-select.vue'; diff --git a/apps/web-antd/src/components/form/types/index.d.ts b/apps/web-antd/src/components/form/types/index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..e60e17e0f0f2bf650a46326eeaa06eee629b0d23 --- /dev/null +++ b/apps/web-antd/src/components/form/types/index.d.ts @@ -0,0 +1,6 @@ +export type CustomComponentType = + | 'ApiCheckboxGroup' + | 'ApiDict' + | 'ApiRadioGroup' + | 'ApiSelect' + | 'ApiTreeSelect'; diff --git a/apps/web-antd/src/components/view/component-map.ts b/apps/web-antd/src/components/view/component-map.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0a1b2a8699cd81d9e63868114888a03a88c953e --- /dev/null +++ b/apps/web-antd/src/components/view/component-map.ts @@ -0,0 +1,27 @@ +import type { Component } from 'vue'; + +import { toPascalCase } from '#/util/tool'; + +const componentMap = new Map(); +// import.meta.glob() 直接引入所有的模块 Vite 独有的功能 +const modules = import.meta.glob('./components/**/*.vue', { eager: true }); +// 加入到路由集合中 +Object.keys(modules).forEach((key) => { + if (!key.includes('-ignore')) { + const mod = (modules as any)[key].default || {}; + // ./components/ApiDict.vue + // 获取ApiDict + const compName = key.replace('./components/', '').replace('.vue', ''); + componentMap.set(toPascalCase(compName), mod); + } +}); + +export function add(compName: string, component: Component) { + componentMap.set(compName, component); +} + +export function del(compName: string) { + componentMap.delete(compName); +} + +export { componentMap }; diff --git a/apps/web-antd/src/components/view/components/api-checkbox-group.vue b/apps/web-antd/src/components/view/components/api-checkbox-group.vue new file mode 100644 index 0000000000000000000000000000000000000000..dbca93f94f2689ea2493212adbd0d3d03fa7bd5d --- /dev/null +++ b/apps/web-antd/src/components/view/components/api-checkbox-group.vue @@ -0,0 +1,6 @@ + + diff --git a/apps/web-antd/src/components/view/components/api-dict.vue b/apps/web-antd/src/components/view/components/api-dict.vue new file mode 100644 index 0000000000000000000000000000000000000000..d4ec0df61e4e8538dd78b50c74e3d9695647dba2 --- /dev/null +++ b/apps/web-antd/src/components/view/components/api-dict.vue @@ -0,0 +1,64 @@ + + + diff --git a/apps/web-antd/src/components/view/components/api-radio-group.vue b/apps/web-antd/src/components/view/components/api-radio-group.vue new file mode 100644 index 0000000000000000000000000000000000000000..dbca93f94f2689ea2493212adbd0d3d03fa7bd5d --- /dev/null +++ b/apps/web-antd/src/components/view/components/api-radio-group.vue @@ -0,0 +1,6 @@ + + diff --git a/apps/web-antd/src/components/view/components/api-select.vue b/apps/web-antd/src/components/view/components/api-select.vue new file mode 100644 index 0000000000000000000000000000000000000000..de41774717ddfa0d77a0d0fdcf72769025856ebd --- /dev/null +++ b/apps/web-antd/src/components/view/components/api-select.vue @@ -0,0 +1,154 @@ + + + diff --git a/apps/web-antd/src/components/view/components/api-tree-select.vue b/apps/web-antd/src/components/view/components/api-tree-select.vue new file mode 100644 index 0000000000000000000000000000000000000000..c581a06e6d7f612731ae3c0d948d0d7ebdc8ef3f --- /dev/null +++ b/apps/web-antd/src/components/view/components/api-tree-select.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue index 5c23354f10bba54726fd4304d1eaff78c12f2113..a8e790c6ebe2ad01786cd0ce465a72dc94b0b826 100644 --- a/apps/web-antd/src/layouts/basic.vue +++ b/apps/web-antd/src/layouts/basic.vue @@ -101,7 +101,7 @@ const menus = computed(() => [ ]); const avatar = computed(() => { - return userStore.userInfo?.user.avatar ?? preferences.app.defaultAvatar; + return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar; }); async function handleLogout() { @@ -138,7 +138,7 @@ watch( diff --git a/apps/web-antd/src/preferences.ts b/apps/web-antd/src/preferences.ts index dc3cc35f9672cdcdf3521fbbac14a634155394c0..4e28df967c34afc86fb0d6406abd74e1c693c856 100644 --- a/apps/web-antd/src/preferences.ts +++ b/apps/web-antd/src/preferences.ts @@ -8,9 +8,9 @@ import { defineOverridesPreferences } from '@vben/preferences'; export const overridesPreferences = defineOverridesPreferences({ // overrides app: { + name: import.meta.env.VITE_APP_TITLE, /** 后端路由模式 */ accessMode: 'backend', - name: import.meta.env.VITE_APP_TITLE, enableRefreshToken: true, }, }); diff --git a/apps/web-antd/src/router/access.ts b/apps/web-antd/src/router/access.ts index db9fda0c6018dd2dc0d8d8af6bb3702d4cbc0620..de599e8611e5f49fa2985a05ef6e7351a508d9d9 100644 --- a/apps/web-antd/src/router/access.ts +++ b/apps/web-antd/src/router/access.ts @@ -1,16 +1,14 @@ import type { ComponentRecordType, GenerateMenuAndRoutesOptions, - RouteRecordStringComponent, } from '@vben/types'; import { generateAccessible } from '@vben/access'; import { preferences } from '@vben/preferences'; -import { useUserStore } from '@vben/stores'; -import { cloneDeep } from '@vben/utils'; import { message } from 'ant-design-vue'; +import { getAuthPermissionInfoApi } from '#/api'; import { BasicLayout, IFrameView } from '#/layouts'; import { $t } from '#/locales'; @@ -18,75 +16,6 @@ import { buildMenus } from './helper'; const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue'); -/** - * base路由 - */ -const baseMenus: RouteRecordStringComponent[] = [ - { - component: 'BasicLayout', - meta: { - order: -1, - title: 'page.dashboard.title', - }, - name: 'Dashboard', - path: '/', - redirect: '/analytics', - children: [ - { - name: 'Analytics', - path: '/analytics', - component: '/dashboard/analytics/index', - meta: { - affixTab: true, - icon: 'lucide:area-chart', - title: 'page.dashboard.analytics', - }, - }, - { - name: 'Workspace', - path: '/workspace', - component: '/dashboard/workspace/index', - meta: { - icon: 'carbon:workspace', - title: 'page.dashboard.workspace', - }, - }, - { - name: 'VbenAbout', - path: '/about', - component: '/_core/about/index.vue', - meta: { - icon: 'lucide:copyright', - title: 'demos.vben.about', - }, - }, - ], - }, - { - component: 'BasicLayout', - meta: { - icon: 'ant-design:user-outlined', - order: -1, - title: '个人中心', - hideInMenu: true, - }, - name: 'profile', - path: '/profile', - children: [ - { - name: 'UserProfile', - path: '/profile/index', - component: '/_core/profile/profile.vue', - meta: { - icon: 'ant-design:user-outlined', - title: '个人中心', - hideInMenu: true, - }, - }, - ], - }, -]; - async function generateAccess(options: GenerateMenuAndRoutesOptions) { const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue'); @@ -102,10 +31,10 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) { content: `${$t('common.loadingMenu')}...`, duration: 1.5, }); - const userStore = useUserStore(); - const menus = userStore.userInfo?.menus; + const authPermissionInfo = await getAuthPermissionInfoApi(); + const menus = authPermissionInfo.menus; const routes = buildMenus(menus); - const menuList = [...cloneDeep(baseMenus), ...routes]; + const menuList = [...routes]; return menuList; }, // 可以指定没有权限跳转403页面 diff --git a/apps/web-antd/src/router/guard.ts b/apps/web-antd/src/router/guard.ts index fce5a892c2193eebef9ad674c44e1c64ba9c51fa..94213301739d4cc2102ea011758891624b459e4c 100644 --- a/apps/web-antd/src/router/guard.ts +++ b/apps/web-antd/src/router/guard.ts @@ -87,9 +87,11 @@ function setupAccessGuard(router: Router) { // 生成路由表 // 当前登录用户拥有的角色标识列表 - const userInfo = userStore.userInfo || (await authStore.fetchUserInfo()); - const userRoles = userInfo.roles ?? []; - + let userRoles = userStore.userRoles; + if (!userRoles) { + const authPermissionInfo = await authStore.getAuthPermissionInfo(); + userRoles = authPermissionInfo?.roles ?? []; + } // 生成菜单和路由 const { accessibleMenus, accessibleRoutes } = await generateAccess({ roles: userRoles, diff --git a/apps/web-antd/src/router/helper.ts b/apps/web-antd/src/router/helper.ts index 3c365baabf928c91e1c474f973c95ea460b97fa2..b47b3f2e47aa9f60d640ff44a3ddb95277b280d2 100644 --- a/apps/web-antd/src/router/helper.ts +++ b/apps/web-antd/src/router/helper.ts @@ -1,6 +1,7 @@ -import type { RouteRecordStringComponent } from '@vben/types'; - -import type { AppRouteRecordRaw } from '#/types'; +import type { + AppRouteRecordRaw, + RouteRecordStringComponent, +} from '@vben/types'; import { isHttpUrl } from '@vben/utils'; diff --git a/apps/web-antd/src/store/auth.ts b/apps/web-antd/src/store/auth.ts index f90bac07b6e663b584fdf5e7fcbb7313f1f2af9f..22f75e22633fe308fdb0a25b3e055cbc5707eb1d 100644 --- a/apps/web-antd/src/store/auth.ts +++ b/apps/web-antd/src/store/auth.ts @@ -1,6 +1,4 @@ -import type { Recordable } from '@vben/types'; - -import type { YudaoUserInfo } from '#/types'; +import type { AuthPermissionInfo, Recordable } from '@vben/types'; import { ref } from 'vue'; import { useRouter } from 'vue-router'; @@ -11,16 +9,12 @@ import { resetAllStores, useAccessStore, useUserStore } from '@vben/stores'; import { notification } from 'ant-design-vue'; import { defineStore } from 'pinia'; -import { getUserInfo, loginApi, logoutApi } from '#/api'; +import { getAuthPermissionInfoApi, loginApi, logoutApi } from '#/api'; import { $t } from '#/locales'; -import { setAccessToken, setRefreshToken } from '#/utils'; - -import { useDictStore } from './dict'; export const useAuthStore = defineStore('auth', () => { const accessStore = useAccessStore(); const userStore = useUserStore(); - const dictStore = useDictStore(); const router = useRouter(); const loginLoading = ref(false); @@ -35,44 +29,37 @@ export const useAuthStore = defineStore('auth', () => { onSuccess?: () => Promise | void, ) { // 异步处理用户登录操作并获取 accessToken - let userInfo: null | YudaoUserInfo = null; + let authPermissionInfo: AuthPermissionInfo | null = null; try { loginLoading.value = true; - const { accessToken, expiresTime, refreshToken } = await loginApi(params); + const { accessToken, refreshToken } = await loginApi(params); // 如果成功获取到 accessToken if (accessToken) { + // 将 accessToken 存储到 accessStore 中 accessStore.setAccessToken(accessToken); accessStore.setRefreshToken(refreshToken); - setAccessToken(accessToken, expiresTime); - setRefreshToken(refreshToken); - - // 获取用户信息并存储到 accessStore 中 - const fetchUserInfoResult = await fetchUserInfo(); - userInfo = fetchUserInfoResult; - if (userInfo) { - if (userInfo.roles) { - userStore.setUserRoles(userInfo.roles); - } - // userStore.setMenus(userInfo.menus); - accessStore.setAccessCodes(userInfo.permissions); - if (accessStore.loginExpired) { - accessStore.setLoginExpired(false); - } else { - onSuccess - ? await onSuccess?.() - : await router.push(userInfo.homePath || DEFAULT_HOME_PATH); - } - dictStore.setDictMap(); + authPermissionInfo = await getAuthPermissionInfo(); - if (userInfo?.realName) { - notification.success({ - description: `${$t('authentication.loginSuccessDesc')}:${userInfo?.realName}`, - duration: 3, - message: $t('authentication.loginSuccess'), - }); - } + if (accessStore.loginExpired) { + accessStore.setLoginExpired(false); + } else { + // 执行成功回调 + await onSuccess?.(); + // 跳转首页 + await router.push(authPermissionInfo.homePath || DEFAULT_HOME_PATH); + } + + if ( + authPermissionInfo?.user.realName || + authPermissionInfo.user.nickname + ) { + notification.success({ + description: `${$t('authentication.loginSuccessDesc')}:${authPermissionInfo?.user.realName ?? authPermissionInfo?.user.nickname}`, + duration: 3, + message: $t('authentication.loginSuccess'), + }); } } } finally { @@ -80,7 +67,7 @@ export const useAuthStore = defineStore('auth', () => { } return { - userInfo, + authPermissionInfo, }; } @@ -104,11 +91,13 @@ export const useAuthStore = defineStore('auth', () => { }); } - async function fetchUserInfo() { - let userInfo: null | YudaoUserInfo = null; - userInfo = await getUserInfo(); - userStore.setUserInfo(userInfo); - return userInfo; + async function getAuthPermissionInfo() { + let authPermissionInfo: AuthPermissionInfo | null = null; + authPermissionInfo = await getAuthPermissionInfoApi(); + userStore.setUserInfo(authPermissionInfo.user); + userStore.setUserRoles(authPermissionInfo.roles); + accessStore.setAccessCodes(authPermissionInfo.permissions); + return authPermissionInfo; } function $reset() { @@ -118,7 +107,7 @@ export const useAuthStore = defineStore('auth', () => { return { $reset, authLogin, - fetchUserInfo, + getAuthPermissionInfo, loginLoading, logout, }; diff --git a/apps/web-antd/src/store/dict.ts b/apps/web-antd/src/store/dict.ts deleted file mode 100644 index ca2825d08eddf5a18e78c412cb10c1676360271c..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/store/dict.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { StorageManager } from '@vben/utils'; - -import { acceptHMRUpdate, defineStore } from 'pinia'; - -import { getSimpleDictDataList } from '#/api/system/dict/dict.data'; - -const DICT_STORAGE_KEY = 'DICT_STORAGE__'; - -interface DictValueType { - value: any; - label: string; - colorType?: string; - cssClass?: string; -} - -// interface DictTypeType { -// dictType: string; -// dictValue: DictValueType[]; -// } - -interface DictState { - dictMap: Map; - isSetDict: boolean; -} - -const storage = new StorageManager({ - prefix: import.meta.env.VITE_APP_NAMESPACE, - storageType: 'sessionStorage', -}); - -export const useDictStore = defineStore('dict', { - actions: { - async setDictMap() { - try { - const dataRes = await getSimpleDictDataList(); - - const dictDataMap = new Map(); - - dataRes.forEach((item: any) => { - let dictTypeArray = dictDataMap.get(item.dictType); - if (!dictTypeArray) { - dictTypeArray = []; - } - dictTypeArray.push({ - value: item.value, - label: item.label, - colorType: item.colorType, - cssClass: item.cssClass, - }); - dictDataMap.set(item.dictType, dictTypeArray); - }); - - this.dictMap = dictDataMap; - this.isSetDict = true; - - // 将字典数据存储到 sessionStorage 中 - storage.setItem(DICT_STORAGE_KEY, dictDataMap, 60); - } catch (error) { - console.error('Failed to set dictionary values:', error); - } - }, - }, - getters: { - getDictMap: (state) => state.dictMap, - getDictData: (state) => (dictType: string) => { - return state.dictMap.get(dictType); - }, - getDictOptions: (state) => (dictType: string) => { - return state.dictMap.get(dictType); - }, - }, - persist: [{ pick: ['dictMap', 'isSetDict'] }], - state: (): DictState => ({ - dictMap: new Map(), - isSetDict: false, - }), -}); - -// 解决热更新问题 -const hot = import.meta.hot; -if (hot) { - hot.accept(acceptHMRUpdate(useDictStore, hot)); -} diff --git a/apps/web-antd/src/store/index.ts b/apps/web-antd/src/store/index.ts index b6a7763b1fa8881b6d0830fc2925955df18b882d..269586ee8b8ae24b9a02f84ee4a663139f079a2d 100644 --- a/apps/web-antd/src/store/index.ts +++ b/apps/web-antd/src/store/index.ts @@ -1,2 +1 @@ export * from './auth'; -export * from './dict'; diff --git a/apps/web-antd/src/types/index.ts b/apps/web-antd/src/types/index.ts deleted file mode 100644 index f65cf3a8b0c2cfab8679e83c83b1afd0babce08b..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/types/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './menus'; -export * from './user'; diff --git a/apps/web-antd/src/types/user.ts b/apps/web-antd/src/types/user.ts deleted file mode 100644 index 570a73283d491e660b48a5aa838893322cb1efbc..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/types/user.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { BasicUserInfo } from '@vben/types'; - -import type { AppRouteRecordRaw } from '#/types'; - -/** 用户信息 */ -type ExBasicUserInfo = { - deptId: number; -} & BasicUserInfo; - -/** 用户信息 */ -interface YudaoUserInfo extends ExBasicUserInfo { - permissions: string[]; - menus: AppRouteRecordRaw[]; - /** - * 首页地址 - */ - homePath: string; - roles: string[]; - user: ExBasicUserInfo; -} - -export type { ExBasicUserInfo, YudaoUserInfo }; diff --git a/apps/web-antd/src/utils/auth.ts b/apps/web-antd/src/utils/auth.ts deleted file mode 100644 index 2b068515cab4598c9b64f5b0d61299601b4f83a3..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/utils/auth.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { StorageManager } from '@vben/utils'; -// token key -const ACCESS_TOKEN_KEY = 'ACCESS_TOKEN__'; - -const REFRESH_TOKEN_KEY = 'REFRESH_TOKEN__'; - -const TENANT_ID_KEY = 'TENANT_ID__'; - -const storage = new StorageManager({ - prefix: import.meta.env.VITE_APP_NAMESPACE, - storageType: 'sessionStorage', -}); - -function getAccessToken(): null | string { - return storage.getItem(ACCESS_TOKEN_KEY); -} - -function setAccessToken(value: string, unix: number) { - return storage.setItem(ACCESS_TOKEN_KEY, value, unix - Date.now()); -} - -function getRefreshToken(): null | string { - return storage.getItem(REFRESH_TOKEN_KEY); -} - -function setRefreshToken(value: string) { - return storage.setItem(REFRESH_TOKEN_KEY, value); -} - -function getTenantId(): null | number { - return storage.getItem(TENANT_ID_KEY); -} - -function setTenantId(value: number) { - return storage.setItem(TENANT_ID_KEY, value); -} - -export { - getAccessToken, - getRefreshToken, - getTenantId, - setAccessToken, - setRefreshToken, - setTenantId, -}; diff --git a/apps/web-antd/src/utils/index.ts b/apps/web-antd/src/utils/index.ts deleted file mode 100644 index 269586ee8b8ae24b9a02f84ee4a663139f079a2d..0000000000000000000000000000000000000000 --- a/apps/web-antd/src/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './auth'; diff --git a/apps/web-antd/src/views/_core/authentication/login.vue b/apps/web-antd/src/views/_core/authentication/login.vue index b708a43161b37152ad4d517a2f595be3e74429c6..4138dd55e214202240cb9e87689e9fa42bfbe52a 100644 --- a/apps/web-antd/src/views/_core/authentication/login.vue +++ b/apps/web-antd/src/views/_core/authentication/login.vue @@ -1,129 +1,132 @@ diff --git a/apps/web-antd/src/views/infra/codegen/codegen.data.ts b/apps/web-antd/src/views/infra/codegen/codegen.data.ts new file mode 100644 index 0000000000000000000000000000000000000000..2aaffca318cd80f740c39503a8a41b080de659bc --- /dev/null +++ b/apps/web-antd/src/views/infra/codegen/codegen.data.ts @@ -0,0 +1,98 @@ +import type { VbenFormProps } from '@vben/common-ui'; + +import type { VxeGridProps } from '#/adapter/vxe-table'; +import type { CodegenApi } from '#/api/infra/codegen'; + +export namespace CodegenDefaultData { + /** + * 代码生成字段定义 表格配置 + */ + export const tableColumns: VxeGridProps['columns'] = + [ + { + type: 'checkbox', + width: 50, + }, + { + type: 'seq', + width: 50, + }, + { field: 'id', title: '编号', width: 100 }, + { field: 'tableName', title: '表名' }, + { field: 'tableComment', title: '表描述' }, + { field: 'className', title: '实体类名' }, + { field: 'createTime', title: '创建时间', formatter: 'formatDateTime' }, + { field: 'updateTime', title: '更新时间', formatter: 'formatDateTime' }, + { + title: '操作', + width: 'auto', + fixed: 'right', + slots: { default: 'action' }, + }, + ]; + /** + * 代码生成表定义 表格查询表单配置 + */ + export const formSchema: VbenFormProps['schema'] = [ + { + label: '表名称', + fieldName: 'tableName', + component: 'Input', + }, + { + label: '表描述', + fieldName: 'tableComment', + component: 'Input', + }, + { + label: '创建时间', + fieldName: 'createTime', + component: 'DatePicker', + componentProps: { + type: 'daterange', + format: 'YYYY-MM-DD', + valueFormat: 'YYYY-MM-DD', + }, + }, + ]; +} + +//* ****************************** ImportTableModal.vue *******************************// + +export namespace CodegenImportTableModalData { + /** + * 导入表 表格配置 + */ + export const tableColumns: VxeGridProps['columns'] = + [ + { type: 'checkbox', width: 50 }, + { type: 'seq', title: '序号', width: 50 }, + { field: 'name', title: '表名' }, + { field: 'comment', title: '表描述' }, + ]; + + /** + * 导入表 表格查询表单配置 + */ + export const formSchema: VbenFormProps['schema'] = [ + { + label: '数据源', + fieldName: 'dataSourceConfigId', + component: 'Select', + componentProps: { + allowClear: true, + placeholder: '请选择数据源', + }, + }, + { + label: '表名称', + fieldName: 'name', + component: 'Input', + }, + { + label: '表描述', + fieldName: 'comment', + component: 'Input', + }, + ]; +} diff --git a/apps/web-antd/src/views/infra/codegen/components/import-table-modal.vue b/apps/web-antd/src/views/infra/codegen/components/import-table-modal.vue new file mode 100644 index 0000000000000000000000000000000000000000..d5beb9a79d75b4f64058e2921e7927fbb162ac24 --- /dev/null +++ b/apps/web-antd/src/views/infra/codegen/components/import-table-modal.vue @@ -0,0 +1,118 @@ + + + diff --git a/apps/web-antd/src/views/infra/codegen/index.vue b/apps/web-antd/src/views/infra/codegen/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..f80d023cc4c0d53f3bc9006c2226d422b7d67ee4 --- /dev/null +++ b/apps/web-antd/src/views/infra/codegen/index.vue @@ -0,0 +1,194 @@ + + + diff --git a/packages/effects/common-ui/package.json b/packages/effects/common-ui/package.json index 2ff5fdf3b811e9da78bae8b2458b50af09efc01b..dac0277fc579ad38765ac526c38726840ecd48d1 100644 --- a/packages/effects/common-ui/package.json +++ b/packages/effects/common-ui/package.json @@ -31,11 +31,13 @@ "@vben/types": "workspace:*", "@vueuse/core": "catalog:", "@vueuse/integrations": "catalog:", + "crypto-js": "catalog:", "qrcode": "catalog:", "vue": "catalog:", "vue-router": "catalog:" }, "devDependencies": { + "@types/crypto-js": "catalog:", "@types/qrcode": "catalog:" } } diff --git a/packages/effects/common-ui/src/components/captcha/index.ts b/packages/effects/common-ui/src/components/captcha/index.ts index 6ad68c49647ae9db9da3f252f3d03e32b4724a2c..e155c635907ece0409cc4da1027a4e131bd68bd7 100644 --- a/packages/effects/common-ui/src/components/captcha/index.ts +++ b/packages/effects/common-ui/src/components/captcha/index.ts @@ -1,6 +1,8 @@ export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue'; -export { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue'; +export { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue'; export { default as SliderCaptcha } from './slider-captcha/index.vue'; export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue'; export type * from './types'; + +export { default as Verification } from './verification/index.vue'; diff --git a/apps/web-antd/src/components/Verification/src/Verify/VerifyPoints.vue b/packages/effects/common-ui/src/components/captcha/verification/Verify/VerifyPoints.vue similarity index 63% rename from apps/web-antd/src/components/Verification/src/Verify/VerifyPoints.vue rename to packages/effects/common-ui/src/components/captcha/verification/Verify/VerifyPoints.vue index 3e962794cec92c97e16ed073435a4667ac52c7f2..f1dc502d76a33afe74c6e376ff97cf1bef91232a 100644 --- a/apps/web-antd/src/components/Verification/src/Verify/VerifyPoints.vue +++ b/packages/effects/common-ui/src/components/captcha/verification/Verify/VerifyPoints.vue @@ -1,9 +1,8 @@ -