Merge remote-tracking branch 'yudao/dev' into dev

This commit is contained in:
puhui999
2025-09-14 19:54:23 +08:00
604 changed files with 7643 additions and 6997 deletions

View File

@@ -22,6 +22,9 @@ const AutoComplete = defineAsyncComponent(
() => import('ant-design-vue/es/auto-complete'),
);
const Button = defineAsyncComponent(() => import('ant-design-vue/es/button'));
const Cascader = defineAsyncComponent(
() => import('ant-design-vue/es/cascader'),
);
const Checkbox = defineAsyncComponent(
() => import('ant-design-vue/es/checkbox'),
);
@@ -59,6 +62,9 @@ const Textarea = defineAsyncComponent(() =>
const TimePicker = defineAsyncComponent(
() => import('ant-design-vue/es/time-picker'),
);
const TimeRangePicker = defineAsyncComponent(() =>
import('ant-design-vue/es/time-picker').then((res) => res.TimeRangePicker),
);
const TreeSelect = defineAsyncComponent(
() => import('ant-design-vue/es/tree-select'),
);
@@ -100,6 +106,7 @@ const withDefaultPlaceholder = <T extends Component>(
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType =
| 'ApiCascader'
| 'ApiSelect'
| 'ApiTreeSelect'
| 'AutoComplete'
@@ -126,6 +133,7 @@ export type ComponentType =
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TimeRangePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
@@ -135,6 +143,21 @@ async function initComponentAdapter() {
// 如果你的组件体积比较大,可以使用异步加载
// Button: () =>
// import('xxx').then((res) => res.Button),
ApiCascader: withDefaultPlaceholder(
{
...ApiComponent,
name: 'ApiCascader',
},
'select',
{
component: Cascader,
fieldNames: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
optionsPropName: 'treeData',
visibleEvent: 'onVisibleChange',
},
),
ApiSelect: withDefaultPlaceholder(
{
...ApiComponent,
@@ -195,6 +218,7 @@ async function initComponentAdapter() {
Textarea: withDefaultPlaceholder(Textarea, 'input'),
RichTextarea,
TimePicker,
TimeRangePicker,
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload,
FileUpload,

View File

@@ -1,79 +0,0 @@
/* 来自 @vben/plugins/vxe-table style.css覆盖 vxe-table 原有的样式定义,使用 vben 的样式主题 */
:root {
--vxe-ui-font-color: hsl(var(--foreground));
--vxe-ui-font-primary-color: hsl(var(--primary));
/* --vxe-ui-font-lighten-color: #babdc0;
--vxe-ui-font-darken-color: #86898e; */
--vxe-ui-font-disabled-color: hsl(var(--foreground) / 50%);
/* base */
--vxe-ui-base-popup-border-color: hsl(var(--border));
--vxe-ui-input-disabled-color: hsl(var(--border) / 60%);
/* --vxe-ui-base-popup-box-shadow: 0px 12px 30px 8px rgb(0 0 0 / 50%); */
/* layout */
--vxe-ui-layout-background-color: hsl(var(--background));
--vxe-ui-table-resizable-line-color: hsl(var(--heavy));
/* --vxe-ui-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px hsl(var(--accent));
--vxe-ui-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px hsl(var(--accent)); */
/* input */
--vxe-ui-input-border-color: hsl(var(--border));
/* --vxe-ui-input-placeholder-color: #8d9095; */
/* --vxe-ui-input-disabled-background-color: #262727; */
/* loading */
--vxe-ui-loading-background-color: hsl(var(--overlay-content));
/* table */
--vxe-ui-table-header-background-color: hsl(var(--accent));
--vxe-ui-table-border-color: hsl(var(--border));
--vxe-ui-table-row-hover-background-color: hsl(var(--accent-hover));
--vxe-ui-table-row-striped-background-color: hsl(var(--accent) / 60%);
--vxe-ui-table-row-hover-striped-background-color: hsl(var(--accent));
--vxe-ui-table-row-radio-checked-background-color: hsl(var(--accent));
--vxe-ui-table-row-hover-radio-checked-background-color: hsl(
var(--accent-hover)
);
--vxe-ui-table-row-checkbox-checked-background-color: hsl(var(--accent));
--vxe-ui-table-row-hover-checkbox-checked-background-color: hsl(
var(--accent-hover)
);
--vxe-ui-table-row-current-background-color: hsl(var(--accent));
--vxe-ui-table-row-hover-current-background-color: hsl(var(--accent-hover));
--vxe-ui-font-primary-tinge-color: hsl(var(--primary));
--vxe-ui-font-primary-lighten-color: hsl(var(--primary) / 60%);
--vxe-ui-font-primary-darken-color: hsl(var(--primary));
/* height: auto !important; */
/* --vxe-ui-table-fixed-scrolling-box-shadow-color: rgb(0 0 0 / 80%); */
}
.vxe-tools--operate {
margin-right: 0.25rem;
margin-left: 0.75rem;
}
.vxe-table-custom--checkbox-option:hover {
background: none !important;
}
.vxe-toolbar {
padding: 0;
}
.vxe-buttons--wrapper:not(:empty),
.vxe-tools--operate:not(:empty),
.vxe-tools--wrapper:not(:empty) {
padding: 0.6em 0;
}
.vxe-tools--operate:not(:has(button)) {
margin-left: 0;
}

View File

@@ -6,7 +6,8 @@ import { h } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { $te } from '@vben/locales';
import {
AsyncComponents,
AsyncVxeColumn,
AsyncVxeTable,
createRequiredValidation,
setupVbenVxeTable,
useVbenVxeGrid,
@@ -34,8 +35,6 @@ import { $t } from '#/locales';
import { useVbenForm } from './form';
import '#/adapter/style.css';
setupVbenVxeTable({
configVxeTable: (vxeUI) => {
vxeUI.setConfig({
@@ -357,16 +356,8 @@ setupVbenVxeTable({
export { createRequiredValidation, useVbenVxeGrid };
const [VxeTable, VxeColumn, VxeToolbar] = AsyncComponents;
export { VxeColumn, VxeTable, VxeToolbar };
export const [VxeTable, VxeColumn] = [AsyncVxeTable, AsyncVxeColumn];
// add by 芋艿from https://github.com/vbenjs/vue-vben-admin/blob/main/playground/src/adapter/vxe-table.ts#L264-L270
export type OnActionClickParams<T = Recordable<any>> = {
code: string;
row: T;
};
export type OnActionClickFn<T = Recordable<any>> = (
params: OnActionClickParams<T>,
) => void;
export * from '#/components/table-action';
export type * from '@vben/plugins/vxe-table';

View File

@@ -71,7 +71,7 @@ export namespace InfraCodegenApi {
}
/** 创建代码生成请求 */
export interface CodegenCreateListReq {
export interface CodegenCreateListReqVO {
dataSourceConfigId?: number;
tableNames: string[];
}
@@ -136,7 +136,7 @@ export function getSchemaTableList(params: any) {
}
/** 基于数据库的表结构,创建代码生成器的表定义 */
export function createCodegenList(data: InfraCodegenApi.CodegenCreateListReq) {
export function createCodegenList(data: InfraCodegenApi.CodegenCreateListReqVO) {
return requestClient.post('/infra/codegen/create-list', data);
}

View File

@@ -113,6 +113,8 @@ export namespace MallSpuApi {
createTime?: Date;
/** 商品状态 */
status?: number;
/** 浏览量 */
browseCount?: number;
}
/** 商品状态更新 */

View File

@@ -31,6 +31,8 @@ export namespace MallDeliveryPickUpStoreApi {
status: number;
/** 绑定用户编号组数 */
verifyUserIds: number[];
/** 营业时间 用于fieldMappingTime */
rangeTime: any[];
}
/** 绑定自提店员请求 */

View File

@@ -16,6 +16,7 @@ export namespace PayAppApi {
merchantId: number;
merchantName: string;
createTime?: Date;
channelCodes: string[];
}
/** 更新状态请求 */

View File

@@ -19,7 +19,7 @@ export namespace SystemMailTemplateApi {
}
/** 邮件发送信息 */
export interface MailSendReq {
export interface MailSendReqVO {
toMails: string[];
ccMails?: string[];
bccMails?: string[];
@@ -66,6 +66,6 @@ export function deleteMailTemplateList(ids: number[]) {
}
/** 发送邮件 */
export function sendMail(data: SystemMailTemplateApi.MailSendReq) {
export function sendMail(data: SystemMailTemplateApi.MailSendReqVO) {
return requestClient.post('/system/mail-template/send-mail', data);
}

View File

@@ -17,7 +17,7 @@ export namespace SystemNotifyTemplateApi {
}
/** 发送站内信请求 */
export interface NotifySendReq {
export interface NotifySendReqVO {
userId: number;
userType: number;
templateCode: string;
@@ -74,6 +74,6 @@ export function exportNotifyTemplate(params: any) {
}
/** 发送站内信 */
export function sendNotify(data: SystemNotifyTemplateApi.NotifySendReq) {
export function sendNotify(data: SystemNotifyTemplateApi.NotifySendReqVO) {
return requestClient.post('/system/notify-template/send-notify', data);
}

View File

@@ -55,3 +55,10 @@ export function updateOAuth2Client(data: SystemOAuth2ClientApi.OAuth2Client) {
export function deleteOAuth2Client(id: number) {
return requestClient.delete(`/system/oauth2-client/delete?id=${id}`);
}
/** 批量删除 OAuth2.0 客户端 */
export function deleteOAuth2ClientList(ids: number[]) {
return requestClient.delete(
`/system/oauth2-client/delete-list?ids=${ids.join(',')}`,
);
}

View File

@@ -20,7 +20,7 @@ export namespace SystemSmsTemplateApi {
}
/** 发送短信请求 */
export interface SmsSendReq {
export interface SmsSendReqVO {
mobile: string;
templateCode: string;
templateParams: Record<string, any>;
@@ -72,6 +72,6 @@ export function exportSmsTemplate(params: any) {
}
/** 发送短信 */
export function sendSms(data: SystemSmsTemplateApi.SmsSendReq) {
export function sendSms(data: SystemSmsTemplateApi.SmsSendReqVO) {
return requestClient.post('/system/sms-template/send-sms', data);
}

View File

@@ -46,3 +46,10 @@ export function updateSocialClient(data: SystemSocialClientApi.SocialClient) {
export function deleteSocialClient(id: number) {
return requestClient.delete(`/system/social-client/delete?id=${id}`);
}
/** 批量删除社交客户端 */
export function deleteSocialClientList(ids: number[]) {
return requestClient.delete(
`/system/social-client/delete-list?ids=${ids.join(',')}`,
);
}

View File

@@ -29,8 +29,8 @@ const Description = defineComponent({
},
setup(props: DescriptionsOptions) {
// TODO @puhui999:每个 field 的 slot 的考虑
// TODO @puhui999from 5.0extra: () => getSlot(slots, 'extra')
// TODO @xingyu:每个 field 的 slot 的考虑
// TODO @xingyufrom 5.0extra: () => getSlot(slots, 'extra')
/** 过滤掉不需要展示的 */
const shouldShowItem = (item: DescriptionItemSchema) => {
if (item.hidden === undefined) return true;
@@ -75,6 +75,6 @@ const Description = defineComponent({
},
});
// TODO @puhui999from 5.0emits: ['register'] 事件
// TODO @xingyufrom 5.0emits: ['register'] 事件
export default Description;
</script>

View File

@@ -2,9 +2,9 @@ import type { DescriptionsProps } from 'ant-design-vue';
import type { CSSProperties, VNode } from 'vue';
// TODO @puhui999【content】这个纠结下1vben2.0 是 renderhttps://doc.vvbin.cn/components/desc.html#usage 2
// TODO @puhui999vben2.0 还有 sapn【done】、labelMinWidth、contentMinWidth
// TODO @puhui999【hidden】这个纠结下1vben2.0 是 show
// TODO @xingyu【content】这个纠结下1vben2.0 是 renderhttps://doc.vvbin.cn/components/desc.html#usage 2
// TODO @xingyuvben2.0 还有 sapn【done】、labelMinWidth、contentMinWidth
// TODO @xingyu【hidden】这个纠结下1vben2.0 是 show
export interface DescriptionItemSchema {
label: string | VNode; // 内容的描述
field?: string; // 对应 data 中的字段名
@@ -15,11 +15,11 @@ export interface DescriptionItemSchema {
hidden?: ((data: any) => boolean) | boolean; // 是否显示
}
// TODO @puhui999vben2.0 还有 title【done】、bordered【done】d、useCollapse、collapseOptions
// TODO @puhui999from 5.0bordered 默认为 true
// TODO @puhui999from 5.0column 默认为 lg: 3, md: 3, sm: 2, xl: 3, xs: 1, xxl: 4
// TODO @puhui999from 5.0size 默认为 small有 'default', 'middle', 'small', undefined
// TODO @puhui999from 5.0useCollapse 默认为 true
// TODO @xingyuvben2.0 还有 title【done】、bordered【done】d、useCollapse、collapseOptions
// TODO @xingyufrom 5.0bordered 默认为 true
// TODO @xingyufrom 5.0column 默认为 lg: 3, md: 3, sm: 2, xl: 3, xs: 1, xxl: 4
// TODO @xingyufrom 5.0size 默认为 small有 'default', 'middle', 'small', undefined
// TODO @xingyufrom 5.0useCollapse 默认为 true
export interface DescriptionsOptions {
data?: Record<string, any>; // 数据
schema?: DescriptionItemSchema[]; // 描述项配置

View File

@@ -16,7 +16,7 @@ class DescriptionApi {
return this.state as DescriptionsOptions;
}
// TODO @puhui999【setState】纠结下1vben2.0 是 data https://doc.vvbin.cn/components/desc.html#usage
// TODO @xingyu【setState】纠结下1vben2.0 是 data https://doc.vvbin.cn/components/desc.html#usage
setState(newState: Partial<DescriptionsOptions>) {
this.state = { ...this.state, ...newState };
}
@@ -27,7 +27,7 @@ export type ExtendedDescriptionApi = DescriptionApi;
export function useDescription(options: DescriptionsOptions) {
const IS_REACTIVE = isReactive(options);
const api = new DescriptionApi(options);
// 扩展API
// 扩展 API
const extendedApi: ExtendedDescriptionApi = api as never;
const Desc = defineComponent({
name: 'UseDescription',

View File

@@ -1,12 +1,11 @@
<script setup lang="ts">
import { computed } from 'vue';
import { getDictObj } from '@vben/hooks';
import { isValidColor, TinyColor } from '@vben/utils';
import { Tag } from 'ant-design-vue';
import { getDictObj } from '#/utils';
interface DictTagProps {
/**
* 字典类型

View File

@@ -4,6 +4,8 @@ import type { DictSelectProps } from '../typing';
import { computed, useAttrs } from 'vue';
import { getDictOptions } from '@vben/hooks';
import {
Checkbox,
CheckboxGroup,
@@ -13,8 +15,6 @@ import {
SelectOption,
} from 'ant-design-vue';
import { getDictOptions } from '#/utils';
defineOptions({ name: 'DictSelect' });
const props = withDefaults(defineProps<DictSelectProps>(), {

View File

@@ -1,38 +0,0 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
interface IFrameProps {
/** iframe 的源地址 */
src: string;
}
const props = defineProps<IFrameProps>();
const loading = ref(true);
const height = ref('');
const frameRef = ref<HTMLElement | null>(null);
function init() {
height.value = `${document.documentElement.clientHeight - 94.5}px`;
loading.value = false;
}
onMounted(() => {
setTimeout(() => {
init();
}, 300);
});
// TODO @芋艿:优化:未来使用 vben 自带的内链实现
</script>
<template>
<div v-loading="loading" :style="`height:${height}`">
<iframe
ref="frameRef"
:src="props.src"
style="width: 100%; height: 100%"
frameborder="no"
scrolling="auto"
></iframe>
</div>
</template>

View File

@@ -1 +0,0 @@
export { default as IFrame } from './iframe.vue';

View File

@@ -1,12 +1,12 @@
<script setup lang="ts">
import type { OperateLogProps } from './typing';
import { DICT_TYPE } from '@vben/constants';
import { getDictLabel, getDictObj } from '@vben/hooks';
import { formatDateTime } from '@vben/utils';
import { Tag, Timeline } from 'ant-design-vue';
import { DICT_TYPE, getDictLabel, getDictObj } from '#/utils';
defineOptions({ name: 'OperateLogV2' });
withDefaults(defineProps<OperateLogProps>(), {

View File

@@ -1,6 +1,6 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
/** 流程实例列表字段 */
export function useGridColumns(): VxeTableGridOptions['columns'] {

View File

@@ -1,6 +1,6 @@
import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
/** 审批记录列表字段 */
export function useGridColumns(): VxeTableGridOptions['columns'] {

View File

@@ -1 +0,0 @@
export { default as TableToolbar } from './table-toolbar.vue';

View File

@@ -1,81 +0,0 @@
<!-- add by puhui999vxe table 工具栏二次封装提供给 vxe 原生列表使用 -->
<script setup lang="ts">
import type { VxeToolbarInstance } from '#/adapter/vxe-table';
import { ref } from 'vue';
import { useContentMaximize, useRefresh } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { Button, Tooltip } from 'ant-design-vue';
import { VxeToolbar } from '#/adapter/vxe-table';
/** 列表工具栏封装 */
defineOptions({ name: 'TableToolbar' });
const props = defineProps<{
hiddenSearch: boolean;
}>();
const emits = defineEmits(['update:hiddenSearch']);
const toolbarRef = ref<VxeToolbarInstance>();
const { toggleMaximizeAndTabbarHidden, contentIsMaximize } =
useContentMaximize();
const { refresh } = useRefresh();
/** 隐藏搜索栏 */
function onHiddenSearchBar() {
emits('update:hiddenSearch', !props.hiddenSearch);
}
defineExpose({
getToolbarRef: () => toolbarRef.value,
});
</script>
<template>
<VxeToolbar ref="toolbarRef" custom>
<template #toolPrefix>
<slot></slot>
<Tooltip placement="bottom">
<template #title>
<div class="max-w-52">搜索</div>
</template>
<Button
class="ml-2 font-normal"
shape="circle"
@click="onHiddenSearchBar"
>
<IconifyIcon icon="lucide:search" :size="15" />
</Button>
</Tooltip>
<Tooltip placement="bottom">
<template #title>
<div class="max-w-52">刷新</div>
</template>
<Button class="ml-2 font-medium" shape="circle" @click="refresh">
<IconifyIcon icon="lucide:refresh-cw" :size="15" />
</Button>
</Tooltip>
<Tooltip placement="bottom">
<template #title>
<div class="max-w-52">
{{ contentIsMaximize ? '还原' : '全屏' }}
</div>
</template>
<Button
class="ml-2 font-medium"
shape="circle"
@click="toggleMaximizeAndTabbarHidden"
>
<IconifyIcon
:icon="contentIsMaximize ? 'lucide:minimize' : 'lucide:maximize'"
:size="15"
/>
</Button>
</Tooltip>
</template>
</VxeToolbar>
</template>

View File

@@ -1 +0,0 @@
export * from './use-table-toolbar';

View File

@@ -1,47 +0,0 @@
import type { VxeTableInstance, VxeToolbarInstance } from '#/adapter/vxe-table';
import type { TableToolbar } from '#/components/table-toolbar';
import { ref, watch } from 'vue';
/**
* vxe 原生工具栏挂载封装
* 解决每个组件使用 vxe-table 组件时都需要写一遍的问题
*/
export function useTableToolbar() {
const hiddenSearchBar = ref(false); // 隐藏搜索栏
const tableToolbarRef = ref<InstanceType<typeof TableToolbar>>();
const tableRef = ref<VxeTableInstance>();
const isBound = ref<boolean>(false);
/** 挂载 toolbar 工具栏 */
async function bindTableToolbar() {
const table = tableRef.value;
const tableToolbar = tableToolbarRef.value;
if (table && tableToolbar) {
// 延迟 1 秒,确保 toolbar 组件已经挂载
setTimeout(async () => {
const toolbar = tableToolbar.getToolbarRef();
if (!toolbar) {
console.error('[toolbar 挂载失败] Table toolbar not found');
}
await table.connect(toolbar as VxeToolbarInstance);
isBound.value = true;
}, 1000); // 延迟挂载确保 toolbar 正确挂载
}
}
watch(
() => tableRef.value,
async (val) => {
if (!val || isBound.value) return;
await bindTableToolbar();
},
{ immediate: true },
);
return {
hiddenSearchBar,
tableToolbarRef,
tableRef,
};
}

View File

@@ -3,14 +3,14 @@ import type { Router } from 'vue-router';
import { LOGIN_PATH } from '@vben/constants';
import { $t } from '@vben/locales';
import { preferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores';
import { useAccessStore, useDictStore, useUserStore } from '@vben/stores';
import { startProgress, stopProgress } from '@vben/utils';
import { message } from 'ant-design-vue';
import { getSimpleDictDataList } from '#/api/system/dict/data';
import { accessRoutes, coreRouteNames } from '#/router/routes';
import { useAuthStore, useDictStore } from '#/store';
import { useAuthStore } from '#/store';
import { generateAccess } from './access';

View File

@@ -1,76 +1,76 @@
// import type { RouteRecordRaw } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';
// const routes: RouteRecordRaw[] = [
// {
// path: '/mall/product',
// name: 'ProductCenter',
// meta: {
// title: '商品中心',
// icon: 'lucide:shopping-bag',
// keepAlive: true,
// hideInMenu: true,
// },
// children: [
// {
// path: 'spu/add',
// name: 'ProductSpuAdd',
// meta: {
// title: '商品添加',
// activeMenu: '/mall/product/spu',
// },
// component: () => import('#/views/mall/product/spu/form/index.vue'),
// },
// {
// path: String.raw`spu/edit/:id(\d+)`,
// name: 'ProductSpuEdit',
// meta: {
// title: '商品编辑',
// activeMenu: '/mall/product/spu',
// },
// component: () => import('#/views/mall/product/spu/form/index.vue'),
// },
// {
// path: String.raw`spu/detail/:id(\d+)`,
// name: 'ProductSpuDetail',
// meta: {
// title: '商品详情',
// activeMenu: '/crm/business',
// },
// component: () => import('#/views/mall/product/spu/form/index.vue'),
// },
// ],
// },
// {
// path: '/mall/trade',
// name: 'TradeCenter',
// meta: {
// title: '交易中心',
// icon: 'lucide:shopping-cart',
// keepAlive: true,
// hideInMenu: true,
// },
// children: [
// {
// path: String.raw`order/detail/:id(\d+)`,
// name: 'TradeOrderDetail',
// meta: {
// title: '订单详情',
// activeMenu: '/mall/trade/order',
// },
// component: () => import('#/views/mall/trade/order/detail/index.vue'),
// },
// {
// path: String.raw`after-sale/detail/:id(\d+)`,
// name: 'TradeAfterSaleDetail',
// meta: {
// title: '退款详情',
// activeMenu: '/mall/trade/after-sale',
// },
// component: () =>
// import('#/views/mall/trade/afterSale/detail/index.vue'),
// },
// ],
// },
// ];
const routes: RouteRecordRaw[] = [
{
path: '/mall/product',
name: 'ProductCenter',
meta: {
title: '商品中心',
icon: 'lucide:shopping-bag',
keepAlive: true,
hideInMenu: true,
},
children: [
{
path: 'spu/add',
name: 'ProductSpuAdd',
meta: {
title: '商品添加',
activeMenu: '/mall/product/spu',
},
component: () => import('#/views/mall/product/spu/modules/form.vue'),
},
{
path: String.raw`spu/edit/:id(\d+)`,
name: 'ProductSpuEdit',
meta: {
title: '商品编辑',
activeMenu: '/mall/product/spu',
},
component: () => import('#/views/mall/product/spu/modules/form.vue'),
},
{
path: String.raw`spu/detail/:id(\d+)`,
name: 'ProductSpuDetail',
meta: {
title: '商品详情',
activeMenu: '/crm/business',
},
component: () => import('#/views/mall/product/spu/modules/detail.vue'),
},
],
},
{
path: '/mall/trade',
name: 'TradeCenter',
meta: {
title: '交易中心',
icon: 'lucide:shopping-cart',
keepAlive: true,
hideInMenu: true,
},
children: [
{
path: String.raw`order/detail/:id(\d+)`,
name: 'TradeOrderDetail',
meta: {
title: '订单详情',
activeMenu: '/mall/trade/order',
},
component: () => import('#/views/mall/trade/order/modules/detail.vue'),
},
{
path: String.raw`after-sale/detail/:id(\d+)`,
name: 'TradeAfterSaleDetail',
meta: {
title: '退款详情',
activeMenu: '/mall/trade/after-sale',
},
component: () =>
import('#/views/mall/trade/afterSale/modules/detail.vue'),
},
],
},
];
// export default routes;
export default routes;

View File

@@ -1,74 +0,0 @@
import { acceptHMRUpdate, defineStore } from 'pinia';
export interface DictItem {
colorType?: string;
cssClass?: string;
label: string;
value: string;
}
export type Dict = Record<string, DictItem[]>;
interface DictState {
dictCache: Dict;
}
// TODO @芋艿:可以共享么?
export const useDictStore = defineStore('dict', {
actions: {
getDictData(dictType: string, value: any) {
const dict = this.dictCache[dictType];
if (!dict) {
return undefined;
}
return (
dict.find((d) => d.value === value || d.value === value.toString()) ??
undefined
);
},
getDictOptions(dictType: string) {
const dictOptions = this.dictCache[dictType];
if (!dictOptions) {
return [];
}
return dictOptions;
},
setDictCache(dicts: Dict) {
this.dictCache = dicts;
},
setDictCacheByApi(
api: (params: Record<string, any>) => Promise<Record<string, any>[]>,
params: Record<string, any> = {},
labelField: string = 'label',
valueField: string = 'value',
) {
api(params).then((dicts) => {
const dictCacheData: Dict = {};
dicts.forEach((dict) => {
dictCacheData[dict.dictType] = dicts
.filter((d) => d.dictType === dict.dictType)
.map((d) => ({
colorType: d.colorType,
cssClass: d.cssClass,
label: d[labelField],
value: d[valueField],
}));
});
this.setDictCache(dictCacheData);
});
},
},
persist: {
// 持久化
pick: ['dictCache'],
},
state: (): DictState => ({
dictCache: {},
}),
});
// 解决热更新问题
const hot = import.meta.hot;
if (hot) {
hot.accept(acceptHMRUpdate(useDictStore, hot));
}

View File

@@ -1,2 +1 @@
export * from './auth';
export * from './dict';

View File

@@ -1,192 +0,0 @@
// TODO @芋艿:后续再优化
// TODO @芋艿:可以共享么?
import type { DictItem } from '#/store';
import { isObject } from '@vben/utils';
import { useDictStore } from '#/store';
// TODO @dhb52top-level 调用 导致:"getActivePinia()" was called but there was no active Pinia
// 先临时移入到方法中
// const dictStore = useDictStore();
/** AntD 组件的颜色类型 */
type ColorType = 'error' | 'info' | 'success' | 'warning';
/** 字典值类型 */
type DictValueType = 'boolean' | 'number' | 'string';
/** 基础字典数据类型 */
export interface DictDataType {
dictType?: string;
label: string;
value: boolean | number | string;
colorType?: string;
cssClass?: string;
}
/** 数字类型字典数据 */
export interface NumberDictDataType extends DictDataType {
value: number;
}
/** 字符串类型字典数据 */
export interface StringDictDataType extends DictDataType {
value: string;
}
/** 布尔类型字典数据 */
export interface BooleanDictDataType extends DictDataType {
value: boolean;
}
/** 字典缓存管理器 */
class DictCacheManager {
private cache = new Map<string, DictDataType[]>();
private maxCacheSize = 100; // 最大缓存数量
/** 清空缓存 */
clear(): void {
this.cache.clear();
}
/** 删除指定字典类型的缓存 */
delete(dictType: string): void {
const keysToDelete = [];
for (const key of this.cache.keys()) {
if (key.startsWith(`${dictType}:`)) {
keysToDelete.push(key);
}
}
keysToDelete.forEach((key) => this.cache.delete(key));
}
/** 获取缓存数据 */
get(dictType: string, valueType: DictValueType): DictDataType[] | undefined {
return this.cache.get(this.getCacheKey(dictType, valueType));
}
/** 设置缓存数据 */
set(dictType: string, valueType: DictValueType, data: DictDataType[]): void {
const key = this.getCacheKey(dictType, valueType);
// 如果缓存数量超过限制,删除最早的缓存
if (this.cache.size >= this.maxCacheSize) {
const firstKey = this.cache.keys().next().value;
if (firstKey) {
this.cache.delete(firstKey);
}
}
this.cache.set(key, data);
}
/** 获取缓存键 */
private getCacheKey(dictType: string, valueType: DictValueType): string {
return `${dictType}:${valueType}`;
}
}
/** 字典缓存实例 */
const dictCache = new DictCacheManager();
/** 值转换器映射 */
const valueConverters: Record<
DictValueType,
(value: any) => boolean | number | string
> = {
boolean: (value: any) => `${value}` === 'true',
number: (value: any) => Number.parseInt(`${value}`, 10),
string: (value: any) => `${value}`,
};
/**
* 获取字典标签
* @param dictType 字典类型
* @param value 字典值
* @returns 字典标签
*/
function getDictLabel(dictType: string, value: any): string {
const dictStore = useDictStore();
const dictObj = dictStore.getDictData(dictType, value);
return isObject(dictObj) ? dictObj.label : '';
}
/**
* 获取字典对象
* @param dictType 字典类型
* @param value 字典值
* @returns 字典对象
*/
function getDictObj(dictType: string, value: any): DictItem | null {
const dictStore = useDictStore();
const dictObj = dictStore.getDictData(dictType, value);
return isObject(dictObj) ? dictObj : null;
}
/**
* 获取字典数组 - 优化版本,支持缓存和泛型
* @param dictType 字典类型
* @param valueType 字典值类型,默认 string 类型
* @returns 字典数组
*/
function getDictOptions<T extends DictValueType = 'string'>(
dictType: string,
valueType: T = 'string' as T,
): T extends 'number'
? NumberDictDataType[]
: T extends 'boolean'
? BooleanDictDataType[]
: StringDictDataType[] {
// 检查缓存
const cachedData = dictCache.get(dictType, valueType);
if (cachedData) {
return cachedData as any;
}
const dictStore = useDictStore();
const dictOpts = dictStore.getDictOptions(dictType);
if (dictOpts.length === 0) {
return [] as any;
}
const converter = valueConverters[valueType];
const dictOptions: DictDataType[] = dictOpts.map((d: DictItem) => ({
value: converter(d.value),
label: d.label,
colorType: d.colorType,
cssClass: d.cssClass,
}));
// 缓存结果
dictCache.set(dictType, valueType, dictOptions);
return dictOptions as any;
}
/**
* 清空字典缓存
*/
export const clearDictCache = (): void => {
dictCache.clear();
};
/**
* 删除指定字典类型的缓存
* @param dictType 字典类型
*/
export const deleteDictCache = (dictType: string): void => {
dictCache.delete(dictType);
};
export {
type ColorType,
type DictValueType,
getDictLabel,
getDictObj,
getDictOptions,
};
export { DICT_TYPE } from '@vben/constants';

View File

@@ -1,5 +1,3 @@
export * from './dict';
export * from './formCreate';
export * from './rangePickerProps';
export * from './routerHelper';
export { CommonStatusEnum } from '@vben/constants';

View File

@@ -48,6 +48,7 @@ export function getRangePickerDefaultProps() {
format: 'HH:mm:ss',
},
transformDateFunc: (dates: any) => {
// TODO @xingyu貌似这个没用
if (dates && dates.length === 2) {
// 格式化为后台支持的时间格式
return [dates.createTime[0], dates.createTime[1]].join(',');

View File

@@ -5,13 +5,14 @@ import type { SystemUserProfileApi } from '#/api/system/user/profile';
import { watch } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { $t } from '@vben/locales';
import { message } from 'ant-design-vue';
import { useVbenForm, z } from '#/adapter/form';
import { updateUserProfile } from '#/api/system/user/profile';
import { DICT_TYPE, getDictOptions } from '#/utils';
const props = defineProps<{
profile?: SystemUserProfileApi.UserProfileResp;

View File

@@ -6,7 +6,8 @@ import { computed, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { confirm } from '@vben/common-ui';
import { SystemUserSocialTypeEnum } from '@vben/constants';
import { DICT_TYPE, SystemUserSocialTypeEnum } from '@vben/constants';
import { getDictLabel } from '@vben/hooks';
import { getUrlValue } from '@vben/utils';
import { Button, Card, Image, message } from 'ant-design-vue';
@@ -19,7 +20,6 @@ import {
socialUnbind,
} from '#/api/system/social/user';
import { $t } from '#/locales';
import { DICT_TYPE, getDictLabel } from '#/utils';
const emit = defineEmits<{
(e: 'update:activeName', v: string): void;

View File

@@ -1,8 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchemaConversation(): VbenFormSchema[] {

View File

@@ -225,7 +225,7 @@ defineExpose({ settingValues });
<Select
v-model:value="selectVersion"
class="!w-80"
clearable
allow-clear
placeholder="请选择版本"
>
<Select.Option

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -2,10 +2,10 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getModelSimpleList } from '#/api/ai/model/model';
import { getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -7,6 +7,7 @@ import { useRoute, useRouter } from 'vue-router';
import { useAccess } from '@vben/access';
import { confirm, Page } from '@vben/common-ui';
import { CommonStatusEnum } from '@vben/constants';
import { message, Switch } from 'ant-design-vue';
@@ -17,7 +18,6 @@ import {
updateKnowledgeDocumentStatus,
} from '#/api/ai/knowledge/document';
import { $t } from '#/locales';
import { CommonStatusEnum } from '#/utils';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -2,10 +2,12 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getModelSimpleList } from '#/api/ai/model/model';
import { getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,7 +1,9 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,8 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,13 +1,13 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { AiModelTypeEnum } from '@vben/constants';
import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getSimpleKnowledgeList } from '#/api/ai/knowledge/knowledge';
import { getModelSimpleList } from '#/api/ai/model/model';
import { getToolSimpleList } from '#/api/ai/model/tool';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,11 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { AiModelTypeEnum } from '@vben/constants';
import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getApiKeySimpleList } from '#/api/ai/model/apiKey';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,12 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -1,7 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -3,9 +3,10 @@ import type { Rule } from 'ant-design-vue/es/form';
import { ref } from 'vue';
import { Form, Input, Select } from 'ant-design-vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { Form, Input, Select } from 'ant-design-vue';
// 创建本地数据副本
const modelData = defineModel<any>();

View File

@@ -4,14 +4,13 @@ import type { AiWriteApi } from '#/api/ai/write';
import { ref } from 'vue';
import { AiWriteTypeEnum, WriteExample } from '@vben/constants';
import { AiWriteTypeEnum, DICT_TYPE, WriteExample } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { createReusableTemplate } from '@vueuse/core';
import { Button, message, Textarea } from 'ant-design-vue';
import { DICT_TYPE, getDictOptions } from '#/utils';
import Tag from './Tag.vue';
type TabType = AiWriteApi.Write['type'];

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -1,13 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -1,8 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -1,14 +1,12 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getSimpleUserList } from '#/api/system/user';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -1,7 +1,7 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { BpmProcessDefinitionApi } from '#/api/bpm/definition';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<BpmProcessDefinitionApi.ProcessDefinition>['columns'] {

View File

@@ -11,6 +11,8 @@ import type { SystemUserApi } from '#/api/system/user';
import { ref, watch } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import {
@@ -25,7 +27,6 @@ import {
import { DeptSelectModal, UserSelectModal } from '#/components/select-modal';
import { ImageUpload } from '#/components/upload';
import { DICT_TYPE, getDictOptions } from '#/utils';
const props = defineProps({
categoryList: {

View File

@@ -5,7 +5,8 @@ import type { BpmFormApi } from '#/api/bpm/form';
import { ref, watch } from 'vue';
import { BpmModelFormType } from '@vben/constants';
import { BpmModelFormType, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { CircleHelp } from '@vben/icons';
import FormCreate from '@form-create/ant-design-vue';
@@ -21,7 +22,7 @@ import {
} from 'ant-design-vue';
import { getFormDetail } from '#/api/bpm/form';
import { DICT_TYPE, getDictOptions, setConfAndFields2 } from '#/utils';
import { setConfAndFields2 } from '#/utils';
const props = defineProps({
formList: {
@@ -94,11 +95,11 @@ defineExpose({ validate });
<FormItem label="表单类型" name="formType" class="mb-5">
<RadioGroup v-model:value="modelData.formType">
<Radio
v-for="dict in getDictOptions(
v-for="(dict, index) in getDictOptions(
DICT_TYPE.BPM_MODEL_FORM_TYPE,
'number',
)"
:key="dict.value"
:key="index"
:value="dict.value"
>
{{ dict.label }}
@@ -111,7 +112,7 @@ defineExpose({ validate });
name="formId"
class="mb-5"
>
<Select v-model:value="modelData.formId" clearable>
<Select v-model:value="modelData.formId" allow-clear>
<SelectOption
v-for="form in props.formList"
:key="form.id"

View File

@@ -1,7 +1,7 @@
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { BpmModelApi } from '#/api/bpm/model';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<BpmModelApi.Model>['columns'] {

View File

@@ -4,10 +4,12 @@ import type { DescriptionItemSchema } from '#/components/description';
import { h } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { formatDateTime } from '@vben/utils';
import { DictTag } from '#/components/dict-tag';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -1,13 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import {
CommonStatusEnum,
DICT_TYPE,
getDictOptions,
getRangePickerDefaultProps,
} from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getCategorySimpleList } from '#/api/bpm/category';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -10,6 +10,7 @@ import {
BpmModelFormType,
BpmModelType,
BpmTaskStatusEnum,
DICT_TYPE,
} from '@vben/constants';
import { formatDateTime } from '@vben/utils';
@@ -21,7 +22,7 @@ import {
} from '#/api/bpm/processInstance';
import { getSimpleUserList } from '#/api/system/user';
import DictTag from '#/components/dict-tag/dict-tag.vue';
import { DICT_TYPE, registerComponent, setConfAndFields2 } from '#/utils';
import { registerComponent, setConfAndFields2 } from '#/utils';
import {
SvgBpmApproveIcon,
SvgBpmCancelIcon,

View File

@@ -991,7 +991,7 @@ defineExpose({ loadTodoTask });
<FormItem label="审批意见" name="reason">
<Textarea
v-model:value="transferForm.reason"
clearable
allow-clear
placeholder="请输入审批意见"
:rows="3"
/>
@@ -1064,7 +1064,7 @@ defineExpose({ loadTodoTask });
<FormItem label="审批意见" name="reason">
<Textarea
v-model:value="delegateForm.reason"
clearable
allow-clear
placeholder="请输入审批意见"
:rows="3"
/>
@@ -1138,7 +1138,7 @@ defineExpose({ loadTodoTask });
<FormItem label="审批意见" name="reason">
<Textarea
v-model:value="addSignForm.reason"
clearable
allow-clear
placeholder="请输入审批意见"
:rows="3"
/>
@@ -1217,7 +1217,7 @@ defineExpose({ loadTodoTask });
<FormItem label="审批意见" name="reason">
<Textarea
v-model:value="deleteSignForm.reason"
clearable
allow-clear
placeholder="请输入审批意见"
:rows="3"
/>
@@ -1288,7 +1288,7 @@ defineExpose({ loadTodoTask });
<FormItem label="退回理由" name="returnReason">
<Textarea
v-model:value="returnForm.returnReason"
clearable
allow-clear
placeholder="请输入退回理由"
:rows="3"
/>
@@ -1354,7 +1354,7 @@ defineExpose({ loadTodoTask });
/>
<Textarea
v-model:value="cancelForm.cancelReason"
clearable
allow-clear
placeholder="请输入取消理由"
:rows="3"
/>

View File

@@ -8,13 +8,14 @@ import type { BpmTaskApi } from '#/api/bpm/task';
import { nextTick, onMounted, ref, shallowRef } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { IconifyIcon } from '@vben/icons';
import { Button } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getTaskListByProcessInstanceId } from '#/api/bpm/task';
import { DICT_TYPE, setConfAndFields2 } from '#/utils';
import { setConfAndFields2 } from '#/utils';
defineOptions({
name: 'BpmProcessInstanceTaskList',

View File

@@ -4,11 +4,14 @@ import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance';
import { h } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { Button } from 'ant-design-vue';
import { getCategorySimpleList } from '#/api/bpm/category';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -5,7 +5,10 @@ import type {
} from '#/adapter/vxe-table';
import type { BpmProcessInstanceApi } from '#/api/bpm/processInstance';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getRangePickerDefaultProps } from '#/utils';
/** 搜索的表单 */
export function useGridFormSchema(

View File

@@ -1,8 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
export const EVENT_EXECUTION_OPTIONS = [
{

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getCategorySimpleList } from '#/api/bpm/category';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -1,7 +1,9 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE, getRangePickerDefaultProps } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -1,8 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getCategorySimpleList } from '#/api/bpm/category';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -149,13 +149,16 @@ export function useFormSchema(): VbenFormSchema[] {
}
/** 列表的搜索表单 */
// TODO @xingyu缺少 placeholder
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'name',
label: '商机名称',
component: 'Input',
componentProps: {
placeholder: '请输入商机名称',
allowClear: true,
},
},
];
}

View File

@@ -12,7 +12,7 @@ defineProps<{
business: CrmBusinessApi.Business; // 商机信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="business" />
<BaseDescriptions :data="business" />
<Divider />
<SystemDescription :data="business" />
<SystemDescriptions :data="business" />
</div>
</template>

View File

@@ -40,7 +40,7 @@ const business = ref<CrmBusinessApi.Business>({} as CrmBusinessApi.Business);
const businessLogList = ref<SystemOperateLogApi.OperateLog[]>([]);
const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队成员列表 Ref
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -134,7 +134,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="business" />
<Descriptions :data="business" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,11 +1,13 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { getAreaTree } from '#/api/system/area';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -12,7 +12,7 @@ defineProps<{
clue: CrmClueApi.Clue; // 线索信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="clue" />
<BaseDescriptions :data="clue" />
<Divider />
<SystemDescription :data="clue" />
<SystemDescriptions :data="clue" />
</div>
</template>

View File

@@ -42,7 +42,7 @@ const validateOwnerUser = computed(
);
const validateWrite = computed(() => permissionListRef.value?.validateWrite);
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -151,7 +151,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="clue" />
<Descriptions :data="clue" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,13 +1,14 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { getSimpleContactList } from '#/api/crm/contact';
import { getCustomerSimpleList } from '#/api/crm/customer';
import { getAreaTree } from '#/api/system/area';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -12,7 +12,7 @@ defineProps<{
contact: CrmContactApi.Contact; // 联系人信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="contact" />
<BaseDescriptions :data="contact" />
<Divider />
<SystemDescription :data="contact" />
<SystemDescriptions :data="contact" />
</div>
</template>

View File

@@ -34,7 +34,7 @@ const contact = ref<CrmContactApi.Contact>({} as CrmContactApi.Contact);
const contactLogList = ref<SystemOperateLogApi.OperateLog[]>([]);
const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队成员列表 Ref
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -113,7 +113,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="contact" />
<Descriptions :data="contact" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,6 +1,7 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { useUserStore } from '@vben/stores';
import { erpPriceInputFormatter, erpPriceMultiply } from '@vben/utils';
@@ -9,7 +10,6 @@ import { getSimpleBusinessList } from '#/api/crm/business';
import { getSimpleContactList } from '#/api/crm/contact';
import { getCustomerSimpleList } from '#/api/crm/customer';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -240,18 +240,25 @@ export function useFormSchema(): VbenFormSchema[] {
}
/** 列表的搜索表单 */
// TODO @xingyu缺少 placeholder
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'no',
label: '合同编号',
component: 'Input',
componentProps: {
placeholder: '请输入合同编号',
allowClear: true,
},
},
{
fieldName: 'name',
label: '合同名称',
component: 'Input',
componentProps: {
placeholder: '请输入合同名称',
allowClear: true,
},
},
{
fieldName: 'customerId',
@@ -264,6 +271,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
value: 'id',
},
placeholder: '请选择客户',
allowClear: true,
},
},
];

View File

@@ -3,10 +3,10 @@ import type { DescriptionItemSchema } from '#/components/description';
import { h } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { erpPriceInputFormatter, formatDateTime } from '@vben/utils';
import { DictTag } from '#/components/dict-tag';
import { DICT_TYPE } from '#/utils';
/** 详情头部的配置 */
export function useDetailSchema(): DescriptionItemSchema[] {
return [

View File

@@ -12,7 +12,7 @@ defineProps<{
contract: CrmContractApi.Contract; // 合同信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="contract" />
<BaseDescriptions :data="contract" />
<Divider />
<SystemDescription :data="contract" />
<SystemDescriptions :data="contract" />
</div>
</template>

View File

@@ -45,7 +45,7 @@ const validateOwnerUser = computed(
);
const validateWrite = computed(() => permissionListRef.value?.validateWrite);
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -125,7 +125,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="contract" />
<Descriptions :data="contract" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,13 +1,13 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { getAreaTree } from '#/api/system/area';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
// TODO @xingyu缺少 placeholder
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -26,6 +26,10 @@ export function useFormSchema(): VbenFormSchema[] {
label: '客户名称',
component: 'Input',
rules: 'required',
componentProps: {
placeholder: '请输入客户名称',
allowClear: true,
},
},
{
fieldName: 'source',
@@ -40,6 +44,10 @@ export function useFormSchema(): VbenFormSchema[] {
fieldName: 'mobile',
label: '手机',
component: 'Input',
componentProps: {
placeholder: '请输入手机',
allowClear: true,
},
},
{
fieldName: 'ownerUserId',
@@ -51,6 +59,8 @@ export function useFormSchema(): VbenFormSchema[] {
label: 'nickname',
value: 'id',
},
placeholder: '请选择负责人',
allowClear: true,
},
defaultValue: userStore.userInfo?.id,
rules: 'required',
@@ -59,21 +69,37 @@ export function useFormSchema(): VbenFormSchema[] {
fieldName: 'telephone',
label: '电话',
component: 'Input',
componentProps: {
placeholder: '请输入电话',
allowClear: true,
},
},
{
fieldName: 'email',
label: '邮箱',
component: 'Input',
componentProps: {
placeholder: '请输入邮箱',
allowClear: true,
},
},
{
fieldName: 'wechat',
label: '微信',
component: 'Input',
componentProps: {
placeholder: '请输入微信',
allowClear: true,
},
},
{
fieldName: 'qq',
label: 'QQ',
component: 'Input',
componentProps: {
placeholder: '请输入QQ',
allowClear: true,
},
},
{
fieldName: 'industryId',
@@ -81,6 +107,8 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_INDUSTRY, 'number'),
placeholder: '请选择客户行业',
allowClear: true,
},
},
{
@@ -89,6 +117,8 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.CRM_CUSTOMER_LEVEL, 'number'),
placeholder: '请选择客户级别',
allowClear: true,
},
},
{
@@ -98,12 +128,18 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: {
api: () => getAreaTree(),
fieldNames: { label: 'name', value: 'id', children: 'children' },
placeholder: '请选择地址',
allowClear: true,
},
},
{
fieldName: 'detailAddress',
label: '详细地址',
component: 'Input',
componentProps: {
placeholder: '请输入详细地址',
allowClear: true,
},
},
{
fieldName: 'contactNextTime',
@@ -113,12 +149,18 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
placeholder: '请选择下次联系时间',
allowClear: true,
},
},
{
fieldName: 'remark',
label: '备注',
component: 'Textarea',
componentProps: {
placeholder: '请输入备注',
allowClear: true,
},
},
];
}
@@ -130,16 +172,28 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'name',
label: '客户名称',
component: 'Input',
componentProps: {
placeholder: '请输入客户名称',
allowClear: true,
},
},
{
fieldName: 'mobile',
label: '手机号',
component: 'Input',
componentProps: {
placeholder: '请输入手机号',
allowClear: true,
},
},
{
fieldName: 'telephone',
label: '电话',
component: 'Input',
componentProps: {
placeholder: '请输入电话',
allowClear: true,
},
},
{
fieldName: 'createTime',
@@ -147,6 +201,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
placeholder: '请选择创建时间',
allowClear: true,
},
},

View File

@@ -12,7 +12,7 @@ defineProps<{
customer: CrmCustomerApi.Customer; // 客户信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="customer" />
<BaseDescriptions :data="customer" />
<Divider />
<SystemDescription :data="customer" />
<SystemDescriptions :data="customer" />
</div>
</template>

View File

@@ -51,7 +51,7 @@ const customer = ref<CrmCustomerApi.Customer>({} as CrmCustomerApi.Customer);
const customerLogList = ref<SystemOperateLogApi.OperateLog[]>([]);
const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队成员列表 Ref
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -269,7 +269,7 @@ onMounted(() => {
/>
</template>
<Card class="min-h-[10%]">
<Description :data="customer" />
<Descriptions :data="customer" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,7 +1,8 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE, getDictOptions } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {

View File

@@ -4,6 +4,8 @@ import type { CrmFollowUpApi } from '#/api/crm/followup';
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { message } from 'ant-design-vue';
@@ -12,7 +14,6 @@ import { getBusinessPageByCustomer } from '#/api/crm/business';
import { getContactPageByCustomer } from '#/api/crm/contact';
import { createFollowUpRecord } from '#/api/crm/followup';
import { $t } from '#/locales';
import { DICT_TYPE, getDictOptions } from '#/utils';
const emit = defineEmits(['success']);

View File

@@ -1,9 +1,11 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { BizTypeEnum, PermissionLevelEnum } from '#/api/crm/permission';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useTransferFormSchema(): VbenFormSchema[] {

View File

@@ -1,13 +1,14 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { handleTree } from '@vben/utils';
import { z } from '#/adapter/form';
import { getProductCategoryList } from '#/api/crm/product/category';
import { getSimpleUserList } from '#/api/system/user';
import { CommonStatusEnum, DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {

View File

@@ -9,7 +9,7 @@ defineProps<{
product: CrmProductApi.Product; // 产品信息
}>();
const [ProductDescription] = useDescription({
const [ProductDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,6 +22,6 @@ const [ProductDescription] = useDescription({
<template>
<div class="p-4">
<ProductDescription :data="product" />
<ProductDescriptions :data="product" />
</div>
</template>

View File

@@ -30,7 +30,7 @@ const productId = ref(0);
const product = ref<CrmProductApi.Product>({} as CrmProductApi.Product);
const productLogList = ref<SystemOperateLogApi.OperateLog[]>([]);
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -73,7 +73,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="product" />
<Descriptions :data="product" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,6 +1,8 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { getContractSimpleList } from '#/api/crm/contract';
@@ -10,7 +12,6 @@ import {
getReceivablePlanSimpleList,
} from '#/api/crm/receivable/plan';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -45,6 +46,7 @@ export function useFormSchema(): VbenFormSchema[] {
value: 'id',
},
placeholder: '请选择负责人',
allowClear: true,
},
defaultValue: userStore.userInfo?.id,
},
@@ -163,13 +165,16 @@ export function useFormSchema(): VbenFormSchema[] {
}
/** 列表的搜索表单 */
// TODO @xingyu缺少 placeholder
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'no',
label: '回款编号',
component: 'Input',
componentProps: {
placeholder: '请输入回款编号',
allowClear: true,
},
},
{
fieldName: 'customerId',
@@ -182,6 +187,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
value: 'id',
},
placeholder: '请选择客户',
allowClear: true,
},
},
];

View File

@@ -12,7 +12,7 @@ defineProps<{
receivable: CrmReceivableApi.Receivable; // 收款信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="receivable" />
<BaseDescriptions :data="receivable" />
<Divider />
<SystemDescription :data="receivable" />
<SystemDescriptions :data="receivable" />
</div>
</template>

View File

@@ -39,7 +39,7 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
// 校验编辑权限
const validateWrite = computed(() => permissionListRef.value?.validateWrite);
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -105,7 +105,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="receivable" />
<Descriptions :data="receivable" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,13 +1,14 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import { erpPriceInputFormatter } from '@vben/utils';
import { getContractSimpleList } from '#/api/crm/contract';
import { getCustomerSimpleList } from '#/api/crm/customer';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
@@ -148,7 +149,6 @@ export function useFormSchema(): VbenFormSchema[] {
}
/** 列表的搜索表单 */
// TODO @xingyu缺少 placeholder
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
@@ -162,6 +162,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
value: 'id',
},
placeholder: '请选择客户',
allowClear: true,
},
},
{
@@ -170,6 +171,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'Input',
componentProps: {
placeholder: '请输入合同编号',
allowClear: true,
},
},
];

View File

@@ -12,7 +12,7 @@ defineProps<{
receivablePlan: CrmReceivablePlanApi.Plan; // 收款计划信息
}>();
const [BaseDescription] = useDescription({
const [BaseDescriptions] = useDescription({
componentProps: {
title: '基本信息',
bordered: false,
@@ -22,7 +22,7 @@ const [BaseDescription] = useDescription({
schema: useDetailBaseSchema(),
});
const [SystemDescription] = useDescription({
const [SystemDescriptions] = useDescription({
componentProps: {
title: '系统信息',
bordered: false,
@@ -35,8 +35,8 @@ const [SystemDescription] = useDescription({
<template>
<div class="p-4">
<BaseDescription :data="receivablePlan" />
<BaseDescriptions :data="receivablePlan" />
<Divider />
<SystemDescription :data="receivablePlan" />
<SystemDescriptions :data="receivablePlan" />
</div>
</template>

View File

@@ -39,7 +39,7 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
// 校验编辑权限
const validateWrite = computed(() => permissionListRef.value?.validateWrite);
const [Description] = useDescription({
const [Descriptions] = useDescription({
componentProps: {
bordered: false,
column: 4,
@@ -109,7 +109,7 @@ onMounted(() => {
</div>
</template>
<Card class="min-h-[10%]">
<Description :data="receivablePlan" />
<Descriptions :data="receivablePlan" />
</Card>
<Card class="mt-4 min-h-[60%]">
<Tabs>

View File

@@ -1,4 +1,5 @@
import { DICT_TYPE, getDictLabel } from '#/utils';
import { DICT_TYPE } from '@vben/constants';
import { getDictLabel } from '@vben/hooks';
export function getChartOptions(activeTabName: any, res: any): any {
switch (activeTabName) {

View File

@@ -1,6 +1,8 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { useUserStore } from '@vben/stores';
import {
beginOfDay,
@@ -12,7 +14,7 @@ import {
import { getSimpleDeptList } from '#/api/system/dept';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE, getDictOptions, getRangePickerDefaultProps } from '#/utils';
import { getRangePickerDefaultProps } from '#/utils';
const userStore = useUserStore();

Some files were not shown because too many files have changed in this diff Show More