diff --git a/apps/web-antd/src/api/bpm/processExpression/index.ts b/apps/web-antd/src/api/bpm/processExpression/index.ts new file mode 100644 index 00000000..9444dd26 --- /dev/null +++ b/apps/web-antd/src/api/bpm/processExpression/index.ts @@ -0,0 +1,53 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace BpmProcessExpressionApi { + /** BPM 流程表达式 VO */ + export interface ProcessExpressionVO { + id: number; // 编号 + name: string; // 表达式名字 + status: number; // 表达式状态 + expression: string; // 表达式 + } +} + +/** 查询流程表达式分页 */ +export async function getProcessExpressionPage(params: PageParam) { + return requestClient.get< + PageResult + >('/bpm/process-expression/page', { params }); +} + +/** 查询流程表达式详情 */ +export async function getProcessExpression(id: number) { + return requestClient.get( + `/bpm/process-expression/get?id=${id}`, + ); +} + +/** 新增流程表达式 */ +export async function createProcessExpression( + data: BpmProcessExpressionApi.ProcessExpressionVO, +) { + return requestClient.post('/bpm/process-expression/create', data); +} + +/** 修改流程表达式 */ +export async function updateProcessExpression( + data: BpmProcessExpressionApi.ProcessExpressionVO, +) { + return requestClient.put('/bpm/process-expression/update', data); +} + +/** 删除流程表达式 */ +export async function deleteProcessExpression(id: number) { + return requestClient.delete( + `/bpm/process-expression/delete?id=${id}`, + ); +} + +/** 导出流程表达式 */ +export async function exportProcessExpression(params: any) { + return requestClient.download('/bpm/process-expression/export-excel', params); +} diff --git a/apps/web-antd/src/views/bpm/processExpression/data.ts b/apps/web-antd/src/views/bpm/processExpression/data.ts new file mode 100644 index 00000000..fd148b86 --- /dev/null +++ b/apps/web-antd/src/views/bpm/processExpression/data.ts @@ -0,0 +1,151 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { BpmProcessExpressionApi } from '#/api/bpm/processExpression'; + +import { useAccess } from '@vben/access'; + +import { z } from '#/adapter/form'; +import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils'; + +const { hasAccessByCodes } = useAccess(); +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + }, + rules: 'required', + }, + { + fieldName: 'status', + label: '状态', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + buttonStyle: 'solid', + optionType: 'button', + }, + rules: z.number().default(CommonStatusEnum.ENABLE), + }, + { + fieldName: 'expression', + label: '表达式', + component: 'Textarea', + componentProps: { + placeholder: '请输入表达式', + }, + rules: 'required', + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '名字', + component: 'Input', + componentProps: { + placeholder: '请输入名字', + allowClear: true, + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), + placeholder: '请选择状态', + allowClear: true, + }, + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + placeholder: ['开始时间', '结束时间'], + valueFormat: 'YYYY-MM-DD HH:mm:ss', + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'id', + title: '编号', + minWidth: 100, + }, + { + field: 'name', + title: '名字', + minWidth: 200, + }, + + { + field: 'status', + title: '状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.COMMON_STATUS }, + }, + }, + { + field: 'expression', + title: '表达式', + minWidth: 200, + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'operation', + title: '操作', + minWidth: 180, + align: 'center', + fixed: 'right', + cellRender: { + attrs: { + nameField: 'name', + nameTitle: '流程表达式', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'edit', + show: hasAccessByCodes(['bpm:process-expression:update']), + }, + { + code: 'delete', + show: hasAccessByCodes(['bpm:process-expression:delete']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/bpm/processExpression/index.vue b/apps/web-antd/src/views/bpm/processExpression/index.vue index 80bf15bf..0e32548c 100644 --- a/apps/web-antd/src/views/bpm/processExpression/index.vue +++ b/apps/web-antd/src/views/bpm/processExpression/index.vue @@ -1,31 +1,125 @@ diff --git a/apps/web-antd/src/views/bpm/processExpression/modules/form.vue b/apps/web-antd/src/views/bpm/processExpression/modules/form.vue new file mode 100644 index 00000000..9a9a526a --- /dev/null +++ b/apps/web-antd/src/views/bpm/processExpression/modules/form.vue @@ -0,0 +1,83 @@ + + + diff --git a/apps/web-antd/src/views/crm/business/data.ts b/apps/web-antd/src/views/crm/business/data.ts new file mode 100644 index 00000000..a010beda --- /dev/null +++ b/apps/web-antd/src/views/crm/business/data.ts @@ -0,0 +1,211 @@ +import type { VbenFormSchema } from '#/adapter/form'; +import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { CrmBusinessApi } from '#/api/crm/business'; + +import { useAccess } from '@vben/access'; + +import { getRangePickerDefaultProps } from '#/utils'; + +const { hasAccessByCodes } = useAccess(); + +/** 新增/修改的表单 */ +export function useFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'name', + label: '商机名称', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'customerId', + label: '客户', + component: 'Input', + rules: 'required', + }, + { + fieldName: 'totalPrice', + label: '商机金额', + component: 'InputNumber', + componentProps: { + min: 0, + controlsPosition: 'right', + placeholder: '请输入商机金额', + }, + rules: 'required', + }, + { + fieldName: 'dealTime', + label: '预计成交日期', + component: 'DatePicker', + rules: 'required', + componentProps: { + showTime: false, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + }, + { + fieldName: 'contactNextTime', + label: '下次联系时间', + component: 'DatePicker', + componentProps: { + showTime: false, + format: 'YYYY-MM-DD HH:mm:ss', + valueFormat: 'x', + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'name', + label: '商机名称', + component: 'Input', + }, + { + fieldName: 'createTime', + label: '创建时间', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns( + onActionClick: OnActionClickFn, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'name', + title: '商机名称', + minWidth: 160, + fixed: 'left', + slots: { + default: 'name', + }, + }, + { + field: 'customerName', + title: '客户名称', + minWidth: 120, + fixed: 'left', + slots: { + default: 'customerName', + }, + }, + { + field: 'totalPrice', + title: '商机金额(元)', + minWidth: 140, + formatter: 'formatAmount', + }, + { + field: 'dealTime', + title: '预计成交日期', + minWidth: 180, + formatter: 'formatDate', + }, + { + field: 'remark', + title: '备注', + minWidth: 200, + }, + { + field: 'contactNextTime', + title: '下次联系时间', + minWidth: 180, + formatter: 'formatDate', + }, + { + field: 'ownerUserName', + title: '负责人', + minWidth: 100, + }, + { + field: 'ownerUserDeptName', + title: '所属部门', + minWidth: 100, + }, + { + field: 'contactLastTime', + title: '最后跟进时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'updateTime', + title: '更新时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'createTime', + title: '创建时间', + minWidth: 180, + formatter: 'formatDateTime', + }, + { + field: 'creatorName', + title: '创建人', + minWidth: 100, + }, + { + field: 'statusTypeName', + title: '商机状态组', + minWidth: 140, + fixed: 'right', + }, + { + field: 'statusName', + title: '商机阶段', + minWidth: 120, + fixed: 'right', + }, + { + field: 'operation', + title: '操作', + width: 130, + fixed: 'right', + align: 'center', + cellRender: { + attrs: { + nameField: 'name', + nameTitle: '商机', + onClick: onActionClick, + }, + name: 'CellOperation', + options: [ + { + code: 'edit', + show: hasAccessByCodes(['crm:business:update']), + }, + { + code: 'delete', + show: hasAccessByCodes(['crm:business:delete']), + }, + ], + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/crm/business/index.vue b/apps/web-antd/src/views/crm/business/index.vue index 7ac461c3..14d2965c 100644 --- a/apps/web-antd/src/views/crm/business/index.vue +++ b/apps/web-antd/src/views/crm/business/index.vue @@ -1,38 +1,175 @@ diff --git a/apps/web-antd/src/views/crm/business/modules/form.vue b/apps/web-antd/src/views/crm/business/modules/form.vue new file mode 100644 index 00000000..dd8dbd61 --- /dev/null +++ b/apps/web-antd/src/views/crm/business/modules/form.vue @@ -0,0 +1,86 @@ + + + diff --git a/docs/src/en/guide/essentials/settings.md b/docs/src/en/guide/essentials/settings.md index b0b7bc83..856d2d8c 100644 --- a/docs/src/en/guide/essentials/settings.md +++ b/docs/src/en/guide/essentials/settings.md @@ -60,6 +60,29 @@ VITE_INJECT_APP_LOADING=true VITE_ARCHIVER=true ``` +```bash [.env.production] +# Public Path for Resources, must start and end with / +VITE_BASE=/ + +# API URL +VITE_GLOB_API_URL=https://mock-napi.vben.pro/api + +# Whether to enable compression, can be set to none, brotli, gzip +VITE_COMPRESS=gzip + +# Whether to enable PWA +VITE_PWA=false + +# vue-router mode +VITE_ROUTER_HISTORY=hash + +# Whether to inject global loading +VITE_INJECT_APP_LOADING=true + +# Whether to generate dist.zip after packaging +VITE_ARCHIVER=true +``` + ::: ## Dynamic Configuration in Production Environment @@ -142,6 +165,7 @@ import { defineOverridesPreferences } from '@vben/preferences'; /** * @description Project configuration file * Only a part of the configuration in the project needs to be covered, and unnecessary configurations do not need to be covered. The default configuration will be automatically used + * !!! Please clear the cache after changing the configuration, otherwise it may not take effect */ export const overridesPreferences = defineOverridesPreferences({ // overrides @@ -172,7 +196,7 @@ const defaultPreferences: Preferences = { isMobile: false, layout: 'sidebar-nav', locale: 'zh-CN', - loginExpiredMode: 'modal', + loginExpiredMode: 'page', name: 'Vben Admin', preferencesButtonPosition: 'auto', watermark: false, @@ -191,14 +215,16 @@ const defaultPreferences: Preferences = { enable: true, icp: '', icpLink: '', + settingShow: true, }, footer: { - enable: true, + enable: false, fixed: false, }, header: { enable: true, hidden: false, + menuAlign: 'start', mode: 'fixed', }, logo: { @@ -220,23 +246,28 @@ const defaultPreferences: Preferences = { sidebar: { autoActivateChild: false, collapsed: false, + collapsedButton: true, collapsedShowTitle: false, enable: true, expandOnHover: true, - extraCollapse: true, + extraCollapse: false, + fixedButton: true, hidden: false, - width: 230, + width: 224, }, tabbar: { draggable: true, enable: true, - height: 36, + height: 38, keepAlive: true, + maxCount: 0, + middleClickToClose: false, persist: true, showIcon: true, showMaximize: true, showMore: true, styleType: 'chrome', + wheelable: true, }, theme: { builtinType: 'default', @@ -247,7 +278,7 @@ const defaultPreferences: Preferences = { mode: 'dark', radius: '0.5', semiDarkHeader: false, - semiDarkSidebar: true, + semiDarkSidebar: false, }, transition: { enable: true, @@ -261,9 +292,9 @@ const defaultPreferences: Preferences = { languageToggle: true, lockScreen: true, notification: true, + refresh: true, sidebarToggle: true, themeToggle: true, - refresh: true, }, }; ``` @@ -345,6 +376,8 @@ interface CopyrightPreferences { icp: string; /** Link to the ICP */ icpLink: string; + /** Whether to show in settings panel */ + settingShow?: boolean; } interface FooterPreferences { @@ -359,6 +392,8 @@ interface HeaderPreferences { enable: boolean; /** Whether the header is hidden, css-hidden */ hidden: boolean; + /** Header menu alignment */ + menuAlign: LayoutHeaderMenuAlignType; /** Header display mode */ mode: LayoutHeaderModeType; } @@ -379,8 +414,12 @@ interface NavigationPreferences { styleType: NavigationStyleType; } interface SidebarPreferences { + /** Automatically activate child menu when clicking on directory */ + autoActivateChild: boolean; /** Whether the sidebar is collapsed */ collapsed: boolean; + /** Whether the sidebar collapse button is visible */ + collapsedButton: boolean; /** Whether to show title when sidebar is collapsed */ collapsedShowTitle: boolean; /** Whether the sidebar is visible */ @@ -389,6 +428,8 @@ interface SidebarPreferences { expandOnHover: boolean; /** Whether the sidebar extension area is collapsed */ extraCollapse: boolean; + /** Whether the sidebar fixed button is visible */ + fixedButton: boolean; /** Whether the sidebar is hidden - css */ hidden: boolean; /** Sidebar width */ @@ -417,6 +458,10 @@ interface TabbarPreferences { height: number; /** Whether tab caching is enabled */ keepAlive: boolean; + /** Maximum number of tabs */ + maxCount: number; + /** Whether to close tab when middle-clicked */ + middleClickToClose: boolean; /** Whether tabs are persistent */ persist: boolean; /** Whether icons in multiple tabs are enabled */ @@ -427,6 +472,8 @@ interface TabbarPreferences { showMore: boolean; /** Tab style */ styleType: TabsStyleType; + /** Whether mouse wheel response is enabled */ + wheelable: boolean; } interface ThemePreferences { /** Built-in theme name */ @@ -514,5 +561,6 @@ interface Preferences { - The `overridesPreferences` method only needs to override a part of the configurations in the project. There's no need to override configurations that are not needed; they will automatically use the default settings. - Any configuration item can be overridden. You just need to override it within the `overridesPreferences` method. Do not modify the default configuration file. +- Please clear the cache after changing the configuration, otherwise it may not take effect. ::: diff --git a/docs/src/guide/essentials/settings.md b/docs/src/guide/essentials/settings.md index 58c36dfd..e25bad70 100644 --- a/docs/src/guide/essentials/settings.md +++ b/docs/src/guide/essentials/settings.md @@ -195,7 +195,7 @@ const defaultPreferences: Preferences = { isMobile: false, layout: 'sidebar-nav', locale: 'zh-CN', - loginExpiredMode: 'modal', + loginExpiredMode: 'page', name: 'Vben Admin', preferencesButtonPosition: 'auto', watermark: false, @@ -214,14 +214,16 @@ const defaultPreferences: Preferences = { enable: true, icp: '', icpLink: '', + settingShow: true, }, footer: { - enable: true, + enable: false, fixed: false, }, header: { enable: true, hidden: false, + menuAlign: 'start', mode: 'fixed', }, logo: { @@ -243,23 +245,28 @@ const defaultPreferences: Preferences = { sidebar: { autoActivateChild: false, collapsed: false, + collapsedButton: true, collapsedShowTitle: false, enable: true, expandOnHover: true, - extraCollapse: true, + extraCollapse: false, + fixedButton: true, hidden: false, - width: 230, + width: 224, }, tabbar: { draggable: true, enable: true, - height: 36, + height: 38, keepAlive: true, + maxCount: 0, + middleClickToClose: false, persist: true, showIcon: true, showMaximize: true, showMore: true, styleType: 'chrome', + wheelable: true, }, theme: { builtinType: 'default', @@ -270,7 +277,7 @@ const defaultPreferences: Preferences = { mode: 'dark', radius: '0.5', semiDarkHeader: false, - semiDarkSidebar: true, + semiDarkSidebar: false, }, transition: { enable: true, @@ -369,6 +376,8 @@ interface CopyrightPreferences { icp: string; /** 备案号链接 */ icpLink: string; + /** 设置面板是否显示*/ + settingShow?: boolean; } interface FooterPreferences { @@ -383,6 +392,8 @@ interface HeaderPreferences { enable: boolean; /** 顶栏是否隐藏,css-隐藏 */ hidden: boolean; + /** 顶栏菜单位置 */ + menuAlign: LayoutHeaderMenuAlignType; /** header显示模式 */ mode: LayoutHeaderModeType; } @@ -404,8 +415,12 @@ interface NavigationPreferences { } interface SidebarPreferences { + /** 点击目录时自动激活子菜单 */ + autoActivateChild: boolean; /** 侧边栏是否折叠 */ collapsed: boolean; + /** 侧边栏折叠按钮是否可见 */ + collapsedButton: boolean; /** 侧边栏折叠时,是否显示title */ collapsedShowTitle: boolean; /** 侧边栏是否可见 */ @@ -414,6 +429,8 @@ interface SidebarPreferences { expandOnHover: boolean; /** 侧边栏扩展区域是否折叠 */ extraCollapse: boolean; + /** 侧边栏固定按钮是否可见 */ + fixedButton: boolean; /** 侧边栏是否隐藏 - css */ hidden: boolean; /** 侧边栏宽度 */ @@ -442,6 +459,10 @@ interface TabbarPreferences { height: number; /** 开启标签页缓存功能 */ keepAlive: boolean; + /** 限制最大数量 */ + maxCount: number; + /** 是否点击中键时关闭标签 */ + middleClickToClose: boolean; /** 是否持久化标签 */ persist: boolean; /** 是否开启多标签页图标 */ @@ -452,6 +473,8 @@ interface TabbarPreferences { showMore: boolean; /** 标签页风格 */ styleType: TabsStyleType; + /** 是否开启鼠标滚轮响应 */ + wheelable: boolean; } interface ThemePreferences { diff --git a/internal/tailwind-config/tsconfig.json b/internal/tailwind-config/tsconfig.json index b2ec3b61..dbd3bcc8 100644 --- a/internal/tailwind-config/tsconfig.json +++ b/internal/tailwind-config/tsconfig.json @@ -1,6 +1,9 @@ { "$schema": "https://json.schemastore.org/tsconfig", "extends": "@vben/tsconfig/node.json", + "compilerOptions": { + "moduleResolution": "bundler" + }, "include": ["src"], "exclude": ["node_modules"] }