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

This commit is contained in:
jason
2025-11-20 13:32:53 +08:00
727 changed files with 20322 additions and 21931 deletions

View File

@@ -42,7 +42,6 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
placeholder: '请输入温度参数',
class: 'w-full',
precision: 2,
min: 0,
max: 2,
@@ -55,7 +54,6 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
placeholder: '请输入回复数 Token 数',
class: 'w-full',
min: 0,
max: 8192,
},
@@ -67,7 +65,6 @@ export function useFormSchema(): VbenFormSchema[] {
component: 'InputNumber',
componentProps: {
placeholder: '请输入上下文数量',
class: 'w-full',
min: 0,
max: 20,
},

View File

@@ -230,31 +230,28 @@ async function updateConversationTitle(
async function deleteChatConversation(
conversation: AiChatConversationApi.ChatConversation,
) {
try {
// 删除的二次确认
await confirm(`是否确认删除对话 - ${conversation.title}?`);
// 发起删除
await deleteChatConversationMy(conversation.id);
message.success('对话已删除');
// 刷新列表
await getChatConversationList();
// 回调
emits('onConversationDelete', conversation);
} catch {}
// 删除的二次确认
await confirm(`是否确认删除对话 - ${conversation.title}?`);
// 发起删除
await deleteChatConversationMy(conversation.id);
message.success('对话已删除');
// 刷新列表
await getChatConversationList();
// 回调
emits('onConversationDelete', conversation);
}
/** 清空未置顶的对话 */
async function handleClearConversation() {
try {
await confirm('确认后对话会全部清空,置顶的对话除外。');
await deleteChatConversationMyByUnpinned();
message.success($t('ui.actionMessage.operationSuccess'));
// 清空对话、对话内容
activeConversationId.value = null;
// 获取对话列表
await getChatConversationList();
// 回调 方法
emits('onConversationClear');
} catch {}
await confirm('确认后对话会全部清空,置顶的对话除外。');
await deleteChatConversationMyByUnpinned();
message.success($t('ui.actionMessage.operationSuccess'));
// 清空对话、对话内容
activeConversationId.value = null;
// 获取对话列表
await getChatConversationList();
// 回调 方法
emits('onConversationClear');
}
/** 对话置顶 */

View File

@@ -18,11 +18,9 @@ async function handlerPromptClick(prompt: any) {
</script>
<template>
<div class="relative flex h-full w-full flex-row justify-center">
<!-- center-container -->
<div class="flex flex-col justify-center">
<!-- title -->
<div class="text-center text-3xl font-bold">芋道 AI</div>
<!-- role-list -->
<div class="mt-5 flex w-96 flex-wrap items-center justify-center">
<div

View File

@@ -88,6 +88,7 @@ async function copyContent(content: string) {
await copy(content);
message.success('复制成功!');
}
/** 删除 */
async function handleDelete(id: number) {
// 删除 message

View File

@@ -71,12 +71,15 @@ function toggleExpanded() {
.scrollbar-thin::-webkit-scrollbar {
width: 4px;
}
.scrollbar-thin::-webkit-scrollbar-track {
background: transparent;
}
.scrollbar-thin::-webkit-scrollbar-thumb {
@apply rounded-sm bg-gray-400/40;
}
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
@apply bg-gray-400/60;
}

View File

@@ -24,7 +24,7 @@ async function handleCategoryClick(category: string) {
</script>
<template>
<div class="flex flex-wrap items-center">
<div class="mx-0 flex flex-wrap items-center">
<div
class="mr-2 flex flex-row"
v-for="category in categoryList"

View File

@@ -58,67 +58,67 @@ async function handleTabsScroll() {
<template>
<div
class="relative flex h-full flex-wrap content-start items-start overflow-auto px-6 pb-36"
class="relative flex h-full flex-wrap content-start items-start overflow-auto pb-36"
ref="tabsRef"
@scroll="handleTabsScroll"
>
<div class="mb-5 mr-5 inline-block" v-for="role in roleList" :key="role.id">
<div class="mb-3 mr-3 inline-block" v-for="role in roleList" :key="role.id">
<Card
class="relative rounded-lg"
:body-style="{
position: 'relative',
display: 'flex',
flexDirection: 'row',
flexDirection: 'column',
justifyContent: 'flex-start',
width: '240px',
maxWidth: '240px',
padding: '15px 15px 10px',
padding: '15px',
}"
>
<!-- 更多操作 -->
<div v-if="showMore" class="absolute right-2 top-0">
<Dropdown>
<Button type="link">
<IconifyIcon icon="lucide:ellipsis-vertical" />
<!-- 头部头像名称 -->
<div class="flex items-center justify-between">
<div class="flex min-w-0 flex-1 items-center">
<Avatar
:src="role.avatar"
class="h-8 w-8 flex-shrink-0 overflow-hidden"
/>
<div class="ml-2 truncate text-base font-medium">
{{ role.name }}
</div>
</div>
</div>
<!-- 描述信息 -->
<div
class="mt-2 line-clamp-2 h-10 overflow-hidden text-sm text-gray-600"
>
{{ role.description }}
</div>
<!-- 底部操作按钮 -->
<div class="flex items-center justify-end gap-2">
<Dropdown v-if="showMore">
<Button size="small">
<IconifyIcon icon="lucide:ellipsis" />
</Button>
<template #overlay>
<Menu>
<Menu.Item @click="handleMoreClick(['edit', role])">
<div class="flex items-center">
<IconifyIcon icon="lucide:edit" color="#787878" />
<span class="text-primary">编辑</span>
</div>
</Menu.Item>
<Menu.Item @click="handleMoreClick(['delete', role])">
<div class="flex items-center">
<IconifyIcon icon="lucide:trash" color="red" />
<span class="text-red-500">删除</span>
<span class="ml-2 text-red-500">删除</span>
</div>
</Menu.Item>
<Menu.Item @click="handleMoreClick(['edit', role])">
<div class="flex items-center">
<IconifyIcon icon="lucide:edit" color="#787878" />
<span class="text-primary ml-2">编辑</span>
</div>
</Menu.Item>
</Menu>
</template>
</Dropdown>
</div>
<!-- 角色信息 -->
<div>
<Avatar :src="role.avatar" class="h-10 w-10 overflow-hidden" />
</div>
<div class="ml-2 w-4/5">
<div class="h-20">
<div class="max-w-32 text-lg font-bold">
{{ role.name }}
</div>
<div class="mt-2 text-sm">
{{ role.description }}
</div>
</div>
<div class="mt-1 flex flex-row-reverse">
<Button type="primary" size="small" @click="handleUseClick(role)">
使用
</Button>
</div>
<Button type="primary" size="small" @click="handleUseClick(role)">
使用
</Button>
</div>
</Card>
</div>

View File

@@ -112,6 +112,7 @@ async function handlerCategoryClick(category: string) {
async function handlerAddRole() {
formModalApi.setData({ formType: 'my-create' }).open();
}
/** 编辑角色 */
async function handlerCardEdit(role: any) {
formModalApi.setData({ formType: 'my-update', id: role.id }).open();
@@ -199,7 +200,6 @@ onMounted(async () => {
添加角色
</Button>
</div>
<!-- 标签页内容 -->
<Tabs
v-model:value="activeTab"
@@ -219,10 +219,8 @@ onMounted(async () => {
@on-edit="handlerCardEdit"
@on-use="handlerCardUse"
@on-page="handlerCardPage('my')"
class="mt-5"
/>
</Tabs.TabPane>
<Tabs.TabPane
key="public-role"
class="flex h-full flex-col overflow-y-auto"

View File

@@ -63,7 +63,7 @@ async function handleGenerateImage() {
width: width.value, // 图片宽度
height: height.value, // 图片高度
options: {},
} as unknown as AiImageApi.ImageDrawReq;
} as unknown as AiImageApi.ImageDrawReqVO;
await drawImage(form);
} finally {
// 回调

View File

@@ -116,7 +116,7 @@ async function handleGenerateImage() {
options: {
style: style.value, // 图像生成的风格
},
} as AiImageApi.ImageDrawReq;
} as AiImageApi.ImageDrawReqVO;
// 发送请求
await drawImage(form);
} finally {

View File

@@ -103,7 +103,7 @@ async function handleGenerateImage() {
height: imageSize.height,
version: selectVersion.value,
referImageUrl: referImageUrl.value,
} as AiImageApi.ImageMidjourneyImagineReq;
} as AiImageApi.ImageMidjourneyImagineReqVO;
await midjourneyImagine(req);
} finally {
// 回调

View File

@@ -103,7 +103,7 @@ async function handleGenerateImage() {
clipGuidancePreset: clipGuidancePreset.value, // 文本提示相匹配的图像 CLIP
stylePreset: stylePreset.value, // 风格
},
} as unknown as AiImageApi.ImageDrawReq;
} as unknown as AiImageApi.ImageDrawReqVO;
await drawImage(form);
} finally {
// 回调

View File

@@ -191,11 +191,17 @@ export function useGridFormSchema(): VbenFormSchema[] {
fieldName: 'name',
label: '角色名称',
component: 'Input',
componentProps: {
placeholder: '请输入角色名称',
},
},
{
fieldName: 'category',
label: '角色类别',
component: 'Input',
componentProps: {
placeholder: '请输入角色类别',
},
},
{
fieldName: 'publicStatus',

View File

@@ -18,7 +18,7 @@ import { decodeFields } from '#/components/form-create';
const userStore = useUserStore();
const printData = ref<BpmProcessInstanceApi.PrintData>();
const printData = ref<BpmProcessInstanceApi.ProcessPrintDataRespVO>();
const userName = computed(() => userStore.userInfo?.nickname ?? '');
const printTime = ref(formatDate(new Date(), 'YYYY-MM-DD HH:mm'));
const formFields = ref<any[]>([]);

View File

@@ -14,7 +14,7 @@ import { useGridColumns, useGridFormSchema } from './data';
defineOptions({ name: 'BpmCopyTask' });
/** 任务详情 */
function handleDetail(row: BpmProcessInstanceApi.Copy) {
function handleDetail(row: BpmProcessInstanceApi.ProcessInstanceCopyRespVO) {
const query = {
id: row.processInstanceId,
...(row.activityId && { activityId: row.activityId }),
@@ -52,7 +52,7 @@ const [Grid] = useVbenVxeGrid({
refresh: true,
search: true,
},
} as VxeTableGridOptions<BpmProcessInstanceApi.Copy>,
} as VxeTableGridOptions<BpmProcessInstanceApi.ProcessInstanceCopyRespVO>,
});
</script>

View File

@@ -49,7 +49,7 @@ const [Grid] = useVbenVxeGrid({
refresh: true,
search: true,
},
} as VxeTableGridOptions<BpmTaskApi.TaskManager>,
} as VxeTableGridOptions<BpmTaskApi.Task>,
});
</script>

View File

@@ -113,7 +113,7 @@ async function handleCreateContactBusinessList(businessIds: number[]) {
const data = {
contactId: props.bizId,
businessIds,
} as CrmContactApi.ContactBusinessReq;
} as CrmContactApi.ContactBusinessReqVO;
await createContactBusinessList(data);
handleRefresh();
}

View File

@@ -40,7 +40,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -30,7 +30,7 @@ const [SystemDescription] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescription :data="business" />
<Divider />
<SystemDescription :data="business" />

View File

@@ -46,7 +46,7 @@ async function handleDelete(row: CrmBusinessStatusApi.BusinessStatus) {
await deleteBusinessStatus(row.id!);
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
handleRefresh();
} catch {
} finally {
hideLoading();
}
}

View File

@@ -105,7 +105,7 @@ const [Modal, modalApi] = useVbenModal({
/** 添加状态 */
async function handleAddStatus() {
formData.value!.statuses!.unshift({
formData.value!.statuses!.splice(-3, 0, {
name: '',
percent: undefined,
} as any);

View File

@@ -36,7 +36,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -30,7 +30,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="clue" />
<Divider />
<SystemDescriptions :data="clue" />

View File

@@ -100,7 +100,7 @@ async function handleCreateBusinessContactList(contactIds: number[]) {
const data = {
businessId: props.bizId,
contactIds,
} as CrmContactApi.BusinessContactReq;
} as CrmContactApi.BusinessContactReqVO;
await createBusinessContactList(data);
handleRefresh();
}

View File

@@ -38,7 +38,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -30,7 +30,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="contact" />
<Divider />
<SystemDescriptions :data="contact" />

View File

@@ -110,6 +110,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: false,
format: 'YYYY-MM-DD',
valueFormat: 'x',
placeholder: '请选择下单日期',
},
},
{
@@ -120,6 +121,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: false,
format: 'YYYY-MM-DD',
valueFormat: 'x',
placeholder: '请选择合同开始时间',
},
},
{
@@ -130,6 +132,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: false,
format: 'YYYY-MM-DD',
valueFormat: 'x',
placeholder: '请选择合同结束时间',
},
},
{
@@ -197,6 +200,7 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: {
min: 0,
precision: 2,
placeholder: '请输入产品总金额',
},
rules: z.number().min(0).optional().default(0),
},
@@ -207,6 +211,7 @@ export function useFormSchema(): VbenFormSchema[] {
componentProps: {
min: 0,
precision: 2,
placeholder: '请输入整单折扣',
},
rules: z.number().min(0).max(100).optional().default(0),
},

View File

@@ -42,7 +42,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -30,7 +30,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="contract" />
<Divider />
<SystemDescriptions :data="contract" />

View File

@@ -49,7 +49,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -30,7 +30,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="customer" />
<Divider />
<SystemDescriptions :data="customer" />

View File

@@ -50,6 +50,7 @@ export function useFormSchema(
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
placeholder: '请选择下次联系时间',
},
rules: 'required',
},

View File

@@ -66,7 +66,8 @@ const [Modal, modalApi] = useVbenModal({
}
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as CrmPermissionApi.TransferReq;
const data =
(await formApi.getValues()) as CrmPermissionApi.BusinessTransferReqVO;
try {
switch (bizType.value) {
case BizTypeEnum.CRM_BUSINESS: {

View File

@@ -85,7 +85,7 @@ export function useGridColumns(): VxeTableGridOptions<CrmProductCategoryApi.Prod
{
field: 'actions',
title: '操作',
width: 200,
width: 250,
fixed: 'right',
slots: {
default: 'actions',

View File

@@ -68,6 +68,8 @@ const [Modal, modalApi] = useVbenModal({
// 加载数据
let data = modalApi.getData<CrmProductCategoryApi.ProductCategory>();
if (!data || !data.id) {
// 设置上级
await formApi.setValues(data);
return;
}
modalApi.lock();

View File

@@ -126,10 +126,8 @@ watch(
},
);
/** 产品下拉选项 */
const productOptions = ref<CrmProductApi.Product[]>([]);
/** 初始化 */
const productOptions = ref<CrmProductApi.Product[]>([]); // 产品下拉选项
onMounted(async () => {
productOptions.value = await getProductSimpleList();
});

View File

@@ -31,7 +31,6 @@ const logList = ref<SystemOperateLogApi.OperateLog[]>([]); // 操作日志
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -6,20 +6,18 @@ import { useDescription } from '#/components/description';
import { useDetailBaseSchema } from '../data';
defineProps<{
product: CrmProductApi.Product; // 产品信息
product: CrmProductApi.Product;
}>();
const [ProductDescriptions] = useDescription({
title: '基本信息',
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailBaseSchema(),
});
</script>
<template>
<div class="p-4">
<div>
<ProductDescriptions :data="product" />
</div>
</template>

View File

@@ -40,7 +40,6 @@ const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -29,7 +29,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="receivable" />
<Divider />
<SystemDescriptions :data="receivable" />

View File

@@ -161,7 +161,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
<FormModal @success="handleRefresh" />
<Grid>
<template toolbar-actions>
<template #toolbar-actions>
<Tabs class="w-full" @change="handleChangeSceneType">
<Tabs.TabPane tab="我负责的" key="1" />
<Tabs.TabPane tab="我参与的" key="2" />

View File

@@ -34,14 +34,11 @@ const receivablePlan = ref<CrmReceivablePlanApi.Plan>(
);
const logList = ref<SystemOperateLogApi.OperateLog[]>([]); // 操作日志
const permissionListRef = ref<InstanceType<typeof PermissionList>>(); // 团队成员列表 Ref
// 校验编辑权限
const validateWrite = () => permissionListRef.value?.validateWrite;
const validateWrite = () => permissionListRef.value?.validateWrite; // 校验编辑权限
const [Descriptions] = useDescription({
bordered: false,
column: 4,
class: 'mx-4',
schema: useDetailSchema(),
});

View File

@@ -29,7 +29,7 @@ const [SystemDescriptions] = useDescription({
</script>
<template>
<div class="p-4">
<div>
<BaseDescriptions :data="receivablePlan" />
<Divider />
<SystemDescriptions :data="receivablePlan" />

View File

@@ -66,7 +66,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
defaultValue: [
formatDateTime(beginOfDay(new Date(Date.now() - 3600 * 1000 * 24 * 7))),
formatDateTime(endOfDay(new Date(Date.now() - 3600 * 1000 * 24))),
] as [Date, Date],
],
},
{
fieldName: 'interval',
@@ -74,6 +74,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '请选择时间间隔',
options: getDictOptions(DICT_TYPE.DATE_INTERVAL, 'number'),
},
defaultValue: 2,
@@ -91,6 +92,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
valueField: 'id',
childrenField: 'children',
treeDefaultExpandAll: true,
placeholder: '请选择归属部门',
},
defaultValue: userStore.userInfo?.deptId,
},

View File

@@ -25,13 +25,11 @@ const { renderEcharts } = useEcharts(chartRef);
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
@@ -57,7 +55,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUser>,
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUserRespVO>,
});
/** tab 切换 */

View File

@@ -40,7 +40,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
defaultValue: [
formatDateTime(beginOfDay(new Date(Date.now() - 3600 * 1000 * 24 * 7))),
formatDateTime(endOfDay(new Date(Date.now() - 3600 * 1000 * 24))),
] as [Date, Date],
],
},
{
fieldName: 'interval',
@@ -48,6 +48,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'Select',
componentProps: {
allowClear: true,
placeholder: '请选择时间间隔',
options: getDictOptions(DICT_TYPE.DATE_INTERVAL, 'number'),
},
defaultValue: 2,
@@ -65,6 +66,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
valueField: 'id',
childrenField: 'children',
treeDefaultExpandAll: true,
placeholder: '请选择归属部门',
},
defaultValue: userStore.userInfo?.deptId,
},
@@ -77,6 +79,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
allowClear: true,
labelField: 'nickname',
valueField: 'id',
placeholder: '请选择员工',
},
},
];

View File

@@ -42,13 +42,11 @@ const gridEvents: VxeGridListeners = {
};
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
@@ -74,7 +72,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<CrmStatisticsFunnelApi.BusinessSummaryByDate>,
} as VxeTableGridOptions<CrmStatisticsFunnelApi.BusinessSummaryByDateRespVO>,
});
/** tab 切换 */

View File

@@ -1,11 +1,10 @@
import type { VbenFormSchema } from '#/adapter/form';
import { useUserStore } from '@vben/stores';
import { beginOfDay, endOfDay, formatDateTime, handleTree } from '@vben/utils';
import { handleTree } from '@vben/utils';
import { getSimpleDeptList } from '#/api/system/dept';
import { getSimpleUserList } from '#/api/system/user';
import { getRangePickerDefaultProps } from '#/utils';
const userStore = useUserStore();
@@ -28,20 +27,16 @@ export const customerSummaryTabs = [
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'times',
label: '时间范围',
component: 'RangePicker',
fieldName: 'time',
label: '选择年份',
component: 'DatePicker',
componentProps: {
...getRangePickerDefaultProps(),
picker: 'year',
showTime: false,
format: 'YYYY',
ranges: {},
valueFormat: 'YYYY',
placeholder: '请选择年份',
},
defaultValue: [
formatDateTime(beginOfDay(new Date(new Date().getFullYear(), 0, 1))),
formatDateTime(endOfDay(new Date(new Date().getFullYear(), 11, 31))),
] as [Date, Date],
defaultValue: new Date().getFullYear().toString(),
},
{
fieldName: 'deptId',
@@ -56,6 +51,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
valueField: 'id',
childrenField: 'children',
treeDefaultExpandAll: true,
placeholder: '请选择归属部门',
},
defaultValue: userStore.userInfo?.deptId,
},

View File

@@ -8,6 +8,7 @@ import { onMounted, ref } from 'vue';
import { ContentWrap, Page } from '@vben/common-ui';
import { EchartsUI, useEcharts } from '@vben/plugins/echarts';
import { beginOfDay, endOfDay, formatDateTime } from '@vben/utils';
import { Tabs } from 'ant-design-vue';
@@ -29,13 +30,11 @@ const { renderEcharts } = useEcharts(chartRef);
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
@@ -63,13 +62,18 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUser>,
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUserRespVO>,
});
/** tab 切换 */
async function handleTabChange(key: any) {
activeTabName.value = key;
const queryParams = (await formApi.getValues()) as any;
// 将年份转换为年初和年末的日期时间
const selectYear = Number.parseInt(queryParams.time);
queryParams.times = [];
queryParams.times[0] = formatDateTime(beginOfDay(new Date(selectYear, 0, 1)));
queryParams.times[1] = formatDateTime(endOfDay(new Date(selectYear, 11, 31)));
let data: any[] = [];
const columnsData: any[] = [];
let tableData: any[] = [];

View File

@@ -39,13 +39,11 @@ export function useGridFormSchema(): VbenFormSchema[] {
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
format: 'YYYY-MM-DD',
picker: 'year',
},
defaultValue: [
formatDateTime(beginOfDay(new Date(Date.now() - 3600 * 1000 * 24 * 7))),
formatDateTime(endOfDay(new Date(Date.now() - 3600 * 1000 * 24))),
] as [Date, Date],
],
},
{
fieldName: 'deptId',
@@ -60,6 +58,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
valueField: 'id',
childrenField: 'children',
treeDefaultExpandAll: true,
placeholder: '请选择归属部门',
},
defaultValue: userStore.userInfo?.deptId,
},

View File

@@ -27,13 +27,11 @@ const { renderEcharts: renderRightEcharts } = useEcharts(rightChartRef);
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
@@ -58,7 +56,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUser>,
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUserRespVO>,
});
/** tab 切换 */

View File

@@ -57,7 +57,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
defaultValue: [
formatDateTime(beginOfDay(new Date(Date.now() - 3600 * 1000 * 24 * 7))),
formatDateTime(endOfDay(new Date(Date.now() - 3600 * 1000 * 24))),
] as [Date, Date],
],
},
{
fieldName: 'deptId',
@@ -72,6 +72,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
valueField: 'id',
childrenField: 'children',
treeDefaultExpandAll: true,
placeholder: '请选择归属部门',
},
defaultValue: userStore.userInfo?.deptId,
},

View File

@@ -25,13 +25,11 @@ const { renderEcharts } = useEcharts(chartRef);
const [QueryForm, formApi] = useVbenForm({
commonConfig: {
// 所有表单项
componentProps: {
class: 'w-full',
},
},
schema: useGridFormSchema(),
// 是否可展开
showCollapseButton: true,
submitButtonOptions: {
content: $t('common.query'),
@@ -66,7 +64,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
toolbarConfig: {
enabled: false,
},
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUser>,
} as VxeTableGridOptions<CrmStatisticsCustomerApi.CustomerSummaryByUserRespVO>,
});
/** tab 切换 */

View File

@@ -47,6 +47,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
placeholder: '请选择出生年',
},
},
{

View File

@@ -47,6 +47,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
placeholder: '请选择出生日期',
},
},
{

View File

@@ -47,6 +47,7 @@ export function useFormSchema(): VbenFormSchema[] {
showTime: true,
format: 'YYYY-MM-DD HH:mm:ss',
valueFormat: 'x',
placeholder: '请选择出生日期',
},
},
{

View File

@@ -60,7 +60,6 @@ function beforeUpload(file: FileType) {
<Form class="mx-4">
<template #file>
<div class="w-full">
<!-- 上传区域 -->
<Upload.Dragger
name="file"
:max-count="1"

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MallArticleCategoryApi } from '#/api/mall/promotion/articleCategory';
import type { MallArticleCategoryApi } from '#/api/mall/promotion/article/category';
import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
@@ -10,7 +10,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteArticleCategory,
getArticleCategoryPage,
} from '#/api/mall/promotion/articleCategory';
} from '#/api/mall/promotion/article/category';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { MallArticleCategoryApi } from '#/api/mall/promotion/articleCategory';
import type { MallArticleCategoryApi } from '#/api/mall/promotion/article/category';
import { computed, ref } from 'vue';
@@ -12,7 +12,7 @@ import {
createArticleCategory,
getArticleCategory,
updateArticleCategory,
} from '#/api/mall/promotion/articleCategory';
} from '#/api/mall/promotion/article/category';
import { $t } from '#/locales';
import { useFormSchema } from '../data';

View File

@@ -1,12 +1,12 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeGridPropTypes } from '#/adapter/vxe-table';
import type { MallArticleCategoryApi } from '#/api/mall/promotion/articleCategory';
import type { MallArticleCategoryApi } from '#/api/mall/promotion/article/category';
import { CommonStatusEnum, DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { z } from '#/adapter/form';
import { getSimpleArticleCategoryList } from '#/api/mall/promotion/articleCategory';
import { getSimpleArticleCategoryList } from '#/api/mall/promotion/article/category';
import { getRangePickerDefaultProps } from '#/utils';
/** 关联数据 */

View File

@@ -1,13 +1,13 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MallBannerApi } from '#/api/mall/market/banner';
import type { MallBannerApi } from '#/api/mall/promotion/banner';
import { DocAlert, Page, useVbenModal } from '@vben/common-ui';
import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteBanner, getBannerPage } from '#/api/mall/market/banner';
import { deleteBanner, getBannerPage } from '#/api/mall/promotion/banner';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import type { MallBannerApi } from '#/api/mall/market/banner';
import type { MallBannerApi } from '#/api/mall/promotion/banner';
import type { SystemUserApi } from '#/api/system/user';
import { computed, ref } from 'vue';
@@ -12,7 +13,7 @@ import {
createBanner,
getBanner,
updateBanner,
} from '#/api/mall/market/banner';
} from '#/api/mall/promotion/banner';
import { $t } from '#/locales';
import { useFormSchema } from '../data';

View File

@@ -189,7 +189,7 @@ function handleSliderChange(prop: string) {
:max="100"
:min="0"
@change="handleSliderChange(dataRef.prop)"
class="mr-[16px]"
class="mr-4"
/>
</Col>
<Col :span="2">

View File

@@ -385,7 +385,7 @@ onMounted(() => {
}"
>
<div
class="bg-size-[auto_auto] relative mx-auto my-0 min-h-full w-96 items-center justify-center bg-no-repeat"
class="relative mx-auto my-0 min-h-full w-96 items-center justify-center bg-auto bg-no-repeat"
>
<draggable
v-model="pageComponents"

View File

@@ -9,7 +9,7 @@ import { useRoute } from 'vue-router';
import { useTabs } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { useAccessStore } from '@vben/stores';
import { isEmpty, isNumber } from '@vben/utils';
import { isEmpty } from '@vben/utils';
import { message, Radio, RadioGroup } from 'ant-design-vue';
@@ -26,29 +26,35 @@ defineOptions({ name: 'DiyTemplateDecorate' });
const route = useRoute();
const { refreshTab } = useTabs();
const DIY_PAGE_INDEX_KEY = 'diy_page_index'; // 特殊:存储 reset 重置时,当前 selectedTemplateItem 值,从而进行恢复
const domain = import.meta.env.VITE_MALL_H5_DOMAIN;
// 特殊:存储 reset 重置时,当前 selectedTemplateItem 值,从而进行恢复
const DIY_PAGE_INDEX_KEY = 'diy_page_index';
const selectedTemplateItem = ref(0);
// 左上角工具栏操作按钮
const templateItems = ref([
{ name: '基础设置', icon: 'lucide:settings' },
{ name: '首页', icon: 'lucide:home' },
{ name: '我的', icon: 'lucide:user' },
]); // 左上角工具栏操作按钮
{ key: 0, name: '基础设置', icon: 'lucide:settings' },
{ key: 1, name: '首页', icon: 'lucide:home' },
{ key: 2, name: '我的', icon: 'lucide:user' },
]);
const formData = ref<MallDiyTemplateApi.DiyTemplateProperty>();
// 当前编辑的属性
const currentFormData = ref<
MallDiyPageApi.DiyPage | MallDiyTemplateApi.DiyTemplateProperty
>({
property: '',
} as MallDiyPageApi.DiyPage); // 当前编辑的属性
} as MallDiyPageApi.DiyPage);
// templateItem 对应的缓存
const currentFormDataMap = ref<
Map<string, MallDiyPageApi.DiyPage | MallDiyTemplateApi.DiyTemplateProperty>
>(new Map()); // templateItem 对应的缓存
const previewUrl = ref(''); // 商城 H5 预览地址
const templateLibs = [] as DiyComponentLibrary[]; // 模板组件库
const libs = ref<DiyComponentLibrary[]>(templateLibs); // 当前组件库
>(new Map());
// 商城 H5 预览地址
const previewUrl = ref('');
// 模板组件库
const templateLibs = [] as DiyComponentLibrary[];
// 当前组件库
const libs = ref<DiyComponentLibrary[]>(templateLibs);
/** 获取详情 */
async function getPageDetail(id: any) {
@@ -58,38 +64,32 @@ async function getPageDetail(id: any) {
});
try {
formData.value = await getDiyTemplateProperty(id);
// 拼接手机预览链接
const domain = import.meta.env.VITE_MALL_H5_DOMAIN;
const accessStore = useAccessStore();
previewUrl.value = `${domain}?templateId=${formData.value.id}&${accessStore.tenantId}`;
previewUrl.value = `${domain}?templateId=${formData.value.id}&tenantId=${accessStore.tenantId}`;
} finally {
hideLoading();
}
}
/** 模板选项切换 */
// TODO @xingyu貌似切换不对“个人中心”切换不过去
function handleTemplateItemChange(event: any) {
// 从事件对象中获取值
const val = event.target?.value ?? event;
// 切换模版
selectedTemplateItem.value = isNumber(val)
? val
: templateItems.value.findIndex((item) => item.name === val.name);
function handleTemplateItemChange(val: any) {
const changeValue = val.target.value;
// 缓存模版编辑数据
currentFormDataMap.value.set(
templateItems.value[selectedTemplateItem.value]?.name || '',
templateItems.value[changeValue]!.name,
currentFormData.value!,
);
// 切换模版
selectedTemplateItem.value = changeValue;
// 读取模版缓存
const data = currentFormDataMap.value.get(
templateItems.value[selectedTemplateItem.value]?.name || '',
templateItems.value[changeValue]!.name,
);
// 情况一:编辑模板
if (val === 0) {
if (changeValue === 0) {
libs.value = templateLibs;
currentFormData.value = (isEmpty(data) ? formData.value : data) as
| MallDiyPageApi.DiyPage
@@ -99,22 +99,14 @@ function handleTemplateItemChange(event: any) {
// 情况二:编辑页面
libs.value = PAGE_LIBS;
const pageData = isEmpty(data)
? formData.value!.pages.find(
(page: MallDiyPageApi.DiyPage) =>
page.name === templateItems.value[val]?.name,
)
: data;
// 如果找不到页面数据,使用默认值
currentFormData.value = pageData
? (pageData as
| MallDiyPageApi.DiyPage
| MallDiyTemplateApi.DiyTemplateProperty)
: ({
property: '',
name: templateItems.value[val]?.name || '',
} as MallDiyPageApi.DiyPage);
currentFormData.value = (
isEmpty(data)
? formData.value!.pages.find(
(page: MallDiyPageApi.DiyPage) =>
page.name === templateItems.value[changeValue]!.name,
)
: data
) as MallDiyPageApi.DiyPage | MallDiyTemplateApi.DiyTemplateProperty;
}
/** 提交表单 */
@@ -210,15 +202,8 @@ onMounted(async () => {
size="large"
@change="handleTemplateItemChange"
>
<template v-for="(item, index) in templateItems" :key="index">
<Radio.Button
:value="item"
:class="
index === selectedTemplateItem
? 'bg-primary text-primary-foreground'
: ''
"
>
<template v-for="item in templateItems" :key="item.key">
<Radio.Button :value="item.key">
<IconifyIcon
:icon="item.icon"
class="mt-2 flex size-5 items-center"

View File

@@ -20,6 +20,9 @@ export function useFormSchema(): VbenFormSchema[] {
fieldName: 'name',
label: '秒杀时段名称',
component: 'Input',
componentProps: {
placeholder: '请输入秒杀时段名称',
},
rules: 'required',
},
{

View File

@@ -19,7 +19,7 @@ import MemberTerminalCard from './modules/terminal-card.vue';
defineOptions({ name: 'MemberStatistics' });
const loading = ref(true); // 加载中
const summary = ref<MallMemberStatisticsApi.Summary>(); // 会员统计数据
const summary = ref<MallMemberStatisticsApi.SummaryRespVO>(); // 会员统计数据
/** 查询会员统计 */
async function loadMemberSummary() {

View File

@@ -18,9 +18,9 @@ import { getAreaChartOptions, getAreaTableColumns } from './area-chart-options';
defineOptions({ name: 'MemberAreaCard' });
const loading = ref(true);
const areaStatisticsList = shallowRef<MallMemberStatisticsApi.AreaStatistics[]>(
[],
);
const areaStatisticsList = shallowRef<
MallMemberStatisticsApi.AreaStatisticsRespVO[]
>([]);
const chartRef = ref<EchartsUIType>();
const { renderEcharts } = useEcharts(chartRef);
@@ -49,7 +49,7 @@ async function loadMemberAreaStatisticsList() {
try {
const list = await getMemberAreaStatisticsList();
areaStatisticsList.value = list.map(
(item: MallMemberStatisticsApi.AreaStatistics) => ({
(item: MallMemberStatisticsApi.AreaStatisticsRespVO) => ({
...item,
areaName: areaReplace(item.areaName),
}),

View File

@@ -5,7 +5,7 @@ import { fenToYuan } from '@vben/utils';
/** 会员地域分布图表配置 */
export function getAreaChartOptions(
data: MallMemberStatisticsApi.AreaStatistics[],
data: MallMemberStatisticsApi.AreaStatisticsRespVO[],
): any {
if (!data || data.length === 0) {
return {

View File

@@ -31,7 +31,7 @@ async function loadMemberSexStatisticsList() {
dictDataList.push({ label: '未知', value: null } as any);
const chartData = dictDataList.map((dictData: any) => {
const userCount = list.find(
(item: MallMemberStatisticsApi.SexStatistics) =>
(item: MallMemberStatisticsApi.SexStatisticsRespVO) =>
item.sex === dictData.value,
)?.userCount;
return {

View File

@@ -37,7 +37,7 @@ defineOptions({ name: 'ProductSummaryCard' });
const trendLoading = ref(true); // 商品状态加载中
const exportLoading = ref(false); // 导出的加载中
const trendSummary =
ref<DataComparisonRespVO<MallProductStatisticsApi.ProductStatistics>>(); // 商品状况统计数据
ref<DataComparisonRespVO<MallProductStatisticsApi.ProductStatisticsRespVO>>(); // 商品状况统计数据
const searchTimes = ref<string[]>([]);
const chartRef = ref<EchartsUIType>();

View File

@@ -18,7 +18,7 @@ defineOptions({ name: 'TradeStatistics' });
const loading = ref(true); // 加载中
const summary =
ref<DataComparisonRespVO<MallTradeStatisticsApi.TradeSummary>>(); // 交易统计数据
ref<DataComparisonRespVO<MallTradeStatisticsApi.TradeSummaryRespVO>>(); // 交易统计数据
/** 计算环比百分比 */
function calculateRelativeRate(value?: number, reference?: number): string {

View File

@@ -37,7 +37,7 @@ defineOptions({ name: 'TradeTrendCard' });
const trendLoading = ref(true); // 交易状态加载中
const exportLoading = ref(false); // 导出的加载中
const trendSummary =
ref<DataComparisonRespVO<MallTradeStatisticsApi.TradeTrendSummary>>(); // 交易状况统计数据
ref<DataComparisonRespVO<MallTradeStatisticsApi.TradeTrendSummaryRespVO>>(); // 交易状况统计数据
const searchTimes = ref<string[]>([]);
const chartRef = ref<EchartsUIType>();

View File

@@ -4,7 +4,7 @@ import { fenToYuan } from '@vben/utils';
/** 交易趋势折线图配置 */
export function getTradeTrendChartOptions(
data: MallTradeStatisticsApi.TradeTrendSummary[],
data: MallTradeStatisticsApi.TradeTrendSummaryRespVO[],
): any {
// 处理数据:将分转换为元
const processedData = data.map((item) => ({

View File

@@ -39,7 +39,7 @@ const [Modal, modalApi] = useVbenModal({
// 提交表单
try {
const data =
(await formApi.getValues()) as MallAfterSaleApi.DisagreeRequest;
(await formApi.getValues()) as MallAfterSaleApi.AfterSaleDisagreeReqVO;
await disagreeAfterSale(data);
// 关闭并提示
await modalApi.close();

View File

@@ -160,12 +160,18 @@ export function useCreateFormSchema(): VbenFormSchema[] {
fieldName: 'userId',
label: '分销员编号',
component: 'InputSearch',
componentProps: {
placeholder: '请输入分销员编号',
},
rules: 'required',
},
{
fieldName: 'bindUserId',
label: '上级推广员编号',
component: 'InputSearch',
componentProps: {
placeholder: '请输入上级推广员编号',
},
rules: 'required',
},
];
@@ -178,6 +184,9 @@ export function useUpdateFormSchema(): VbenFormSchema[] {
fieldName: 'bindUserId',
label: '上级推广员编号',
component: 'InputSearch',
componentProps: {
placeholder: '请输入上级推广员编号',
},
rules: 'required',
},
];

View File

@@ -32,13 +32,15 @@ function handleCreate() {
}
/** 编辑快递模板 */
function handleEdit(row: MallDeliveryExpressTemplateApi.ExpressTemplate) {
function handleEdit(
row: MallDeliveryExpressTemplateApi.DeliveryExpressTemplate,
) {
formModalApi.setData(row).open();
}
/** 删除快递模板 */
async function handleDelete(
row: MallDeliveryExpressTemplateApi.ExpressTemplate,
row: MallDeliveryExpressTemplateApi.DeliveryExpressTemplate,
) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.name]),
@@ -80,7 +82,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
refresh: true,
search: true,
},
} as VxeTableGridOptions<MallDeliveryExpressTemplateApi.ExpressTemplate>,
} as VxeTableGridOptions<MallDeliveryExpressTemplateApi.DeliveryExpressTemplate>,
});
</script>

View File

@@ -11,7 +11,7 @@ import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { CHARGE_MODE_TITLE_MAP, useChargesColumns } from '../data';
interface Props {
items?: MallDeliveryExpressTemplateApi.TemplateCharge[];
items?: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateCharge[];
chargeMode?: number;
areaTree?: SystemAreaApi.Area[];
}

View File

@@ -23,7 +23,7 @@ import ChargeItemForm from './charge-item-form.vue';
import FreeItemForm from './free-item-form.vue';
const emit = defineEmits(['success']);
const formData = ref<MallDeliveryExpressTemplateApi.ExpressTemplate>();
const formData = ref<MallDeliveryExpressTemplateApi.DeliveryExpressTemplate>();
const chargeItemFormRef = ref<InstanceType<typeof ChargeItemForm>>();
const freeItemFormRef = ref<InstanceType<typeof FreeItemForm>>();
const areaTree = ref<SystemAreaApi.Area[]>([]);
@@ -55,10 +55,10 @@ const [Form, formApi] = useVbenForm({
/** 更新运费设置 */
const handleUpdateCharges = async (
charges: MallDeliveryExpressTemplateApi.TemplateCharge[],
charges: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateCharge[],
) => {
formData.value =
await formApi.getValues<MallDeliveryExpressTemplateApi.ExpressTemplate>();
await formApi.getValues<MallDeliveryExpressTemplateApi.DeliveryExpressTemplate>();
formData.value.charges = charges;
await formApi.setValues({
charges,
@@ -67,10 +67,10 @@ const handleUpdateCharges = async (
/** 更新包邮设置 */
const handleUpdateFrees = async (
frees: MallDeliveryExpressTemplateApi.TemplateFree[],
frees: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateFree[],
) => {
formData.value =
await formApi.getValues<MallDeliveryExpressTemplateApi.ExpressTemplate>();
await formApi.getValues<MallDeliveryExpressTemplateApi.DeliveryExpressTemplate>();
formData.value.frees = frees;
await formApi.setValues({
frees,
@@ -102,17 +102,19 @@ const [Modal, modalApi] = useVbenModal({
// 提交表单
const data = cloneDeep(
await formApi.getValues(),
) as MallDeliveryExpressTemplateApi.ExpressTemplate;
) as MallDeliveryExpressTemplateApi.DeliveryExpressTemplate;
try {
// 转换金额单位
data.charges?.forEach(
(item: MallDeliveryExpressTemplateApi.TemplateCharge) => {
(
item: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateCharge,
) => {
item.startPrice = yuanToFen(item.startPrice);
item.extraPrice = yuanToFen(item.extraPrice);
},
);
data.frees?.forEach(
(item: MallDeliveryExpressTemplateApi.TemplateFree) => {
(item: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateFree) => {
item.freePrice = yuanToFen(item.freePrice);
},
);
@@ -134,7 +136,7 @@ const [Modal, modalApi] = useVbenModal({
}
// 加载数据
const data =
modalApi.getData<MallDeliveryExpressTemplateApi.ExpressTemplate>();
modalApi.getData<MallDeliveryExpressTemplateApi.DeliveryExpressTemplate>();
if (!data || !data.id) {
return;
}
@@ -143,13 +145,15 @@ const [Modal, modalApi] = useVbenModal({
formData.value = await getDeliveryExpressTemplate(data.id);
// 转换金额单位
formData.value.charges?.forEach(
(item: MallDeliveryExpressTemplateApi.TemplateCharge) => {
(
item: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateCharge,
) => {
item.startPrice = Number.parseFloat(fenToYuan(item.startPrice));
item.extraPrice = Number.parseFloat(fenToYuan(item.extraPrice));
},
);
formData.value.frees?.forEach(
(item: MallDeliveryExpressTemplateApi.TemplateFree) => {
(item: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateFree) => {
item.freePrice = Number.parseFloat(fenToYuan(item.freePrice));
},
);

View File

@@ -11,7 +11,7 @@ import { TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { FREE_MODE_TITLE_MAP, useFreesColumns } from '../data';
interface Props {
items?: MallDeliveryExpressTemplateApi.TemplateFree[];
items?: MallDeliveryExpressTemplateApi.DeliveryExpressTemplateFree[];
chargeMode?: number;
areaTree?: SystemAreaApi.Area[];
}

View File

@@ -12,7 +12,7 @@ import { getRangePickerDefaultProps } from '#/utils';
/** 关联数据 */
const userStore = useUserStore();
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.PickUpStore[]>([]);
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.DeliveryPickUpStore[]>([]);
getSimpleDeliveryPickUpStoreList().then((res) => {
pickUpStoreList.value = res;
// 移除自己无法核销的门店

View File

@@ -20,7 +20,7 @@ import {
import { useGridColumns, useGridFormSchema } from './data';
const summary = ref<MallOrderApi.OrderSummary>();
const summary = ref<MallOrderApi.OrderSummaryRespVO>();
/** 刷新表格 */
function handleRefresh() {

View File

@@ -38,17 +38,19 @@ function handleCreate() {
}
/** 编辑门店 */
function handleEdit(row: MallDeliveryPickUpStoreApi.PickUpStore) {
function handleEdit(row: MallDeliveryPickUpStoreApi.DeliveryPickUpStore) {
formModalApi.setData(row).open();
}
/** 绑定店员 */
function handleBind(row: MallDeliveryPickUpStoreApi.PickUpStore) {
function handleBind(row: MallDeliveryPickUpStoreApi.DeliveryPickUpStore) {
bindFormModalApi.setData(row).open();
}
/** 删除门店 */
async function handleDelete(row: MallDeliveryPickUpStoreApi.PickUpStore) {
async function handleDelete(
row: MallDeliveryPickUpStoreApi.DeliveryPickUpStore,
) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.name]),
duration: 0,
@@ -89,7 +91,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
refresh: true,
search: true,
},
} as VxeTableGridOptions<MallDeliveryPickUpStoreApi.PickUpStore>,
} as VxeTableGridOptions<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>,
});
</script>

View File

@@ -17,7 +17,7 @@ import { $t } from '#/locales';
import { useBindFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<MallDeliveryPickUpStoreApi.PickUpStore>();
const formData = ref<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>();
const [Form, formApi] = useVbenForm({
commonConfig: {

View File

@@ -20,7 +20,7 @@ import { $t } from '#/locales';
import { useFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<MallDeliveryPickUpStoreApi.PickUpStore>();
const formData = ref<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['门店'])
@@ -94,7 +94,7 @@ const [Modal, modalApi] = useVbenModal({
modalApi.lock();
// 提交表单
const data =
(await formApi.getValues()) as MallDeliveryPickUpStoreApi.PickUpStore;
(await formApi.getValues()) as MallDeliveryPickUpStoreApi.DeliveryPickUpStore;
try {
await (formData.value?.id
? updateDeliveryPickUpStore(data)
@@ -113,7 +113,7 @@ const [Modal, modalApi] = useVbenModal({
return;
}
// 加载数据
const data = modalApi.getData<MallDeliveryPickUpStoreApi.PickUpStore>();
const data = modalApi.getData<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>();
if (!data || !data.id) {
// 初始化地图
await initTencentLbsMap();

View File

@@ -12,7 +12,7 @@ import { getAreaTree } from '#/api/system/area';
import { getRangePickerDefaultProps } from '#/utils';
/** 关联数据 */
let pickUpStoreList: MallDeliveryPickUpStoreApi.PickUpStore[] = [];
let pickUpStoreList: MallDeliveryPickUpStoreApi.DeliveryPickUpStore[] = [];
getSimpleDeliveryPickUpStoreList().then((data) => {
pickUpStoreList = data;
});

View File

@@ -54,11 +54,11 @@ const orderId = ref(0);
const order = ref<MallOrderApi.Order>({
logs: [],
});
const deliveryExpressList = ref<MallDeliveryExpressApi.SimpleDeliveryExpress[]>(
[],
);
const deliveryExpressList = ref<MallDeliveryExpressApi.DeliveryExpress[]>([]);
const expressTrackList = ref<any[]>([]);
const pickUpStore = ref<MallDeliveryPickUpStoreApi.PickUpStore | undefined>();
const pickUpStore = ref<
MallDeliveryPickUpStoreApi.DeliveryPickUpStore | undefined
>();
const [OrderInfoDescriptions] = useDescription({
title: '订单信息',

View File

@@ -40,7 +40,7 @@ const [Modal, modalApi] = useVbenModal({
// 提交表单
const data = await formApi.getValues();
try {
await updateOrderAddress(data as MallOrderApi.AddressRequest);
await updateOrderAddress(data as MallOrderApi.OrderUpdateAddressReqVO);
// 关闭并提示
await modalApi.close();
emit('success');

View File

@@ -50,7 +50,7 @@ const [Modal, modalApi] = useVbenModal({
data.logisticsNo = '';
}
try {
await deliveryOrder(data as MallOrderApi.DeliveryRequest);
await deliveryOrder(data as MallOrderApi.OrderUpdateDeliveryReqVO);
// 关闭并提示
await modalApi.close();
emit('success');

View File

@@ -15,7 +15,7 @@ import { useRemarkFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<MallOrderApi.DeliveryRequest>();
const formData = ref<MallOrderApi.OrderUpdateDeliveryReqVO>();
const [Form, formApi] = useVbenForm({
commonConfig: {
@@ -38,7 +38,8 @@ const [Modal, modalApi] = useVbenModal({
}
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as MallOrderApi.RemarkRequest;
const data =
(await formApi.getValues()) as MallOrderApi.OrderUpdateRemarkReqVO;
try {
await updateOrderRemark(data);
// 关闭并提示

View File

@@ -21,6 +21,9 @@ export function useFormSchema(): VbenFormSchema[] {
fieldName: 'name',
label: '分组名称',
component: 'Input',
componentProps: {
placeholder: '请输入分组名称',
},
rules: 'required',
},
{

View File

@@ -31,6 +31,9 @@ export function useFormSchema(): VbenFormSchema[] {
fieldName: 'mobile',
label: '手机号',
component: 'Input',
componentProps: {
placeholder: '请输入手机号',
},
rules: 'required',
},
{

View File

@@ -1,21 +1,15 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeGridPropTypes } from '#/adapter/vxe-table';
import type { MpAccountApi } from '#/api/mp/account';
import { markRaw } from 'vue';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getSimpleAccountList } from '#/api/mp/account';
import { WxReply } from '#/views/mp/components';
import { MsgType } from './types';
/** 关联数据 */
let accountList: MpAccountApi.AccountSimple[] = [];
getSimpleAccountList().then((data) => (accountList = data));
// TODO @芋艿:要不要使用统一枚举?
const RequestMessageTypes = new Set([
'image',
@@ -159,21 +153,12 @@ export function useFormSchema(msgType: MsgType): VbenFormSchema[] {
}
/** 列表的搜索表单 */
// TODO @芋艿:貌似可能微信号拿不到。
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'accountId',
label: '公众号',
component: 'ApiSelect',
componentProps: {
options: accountList.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择公众号',
},
defaultValue: accountList[0]?.id,
component: 'Input',
},
];
}

View File

@@ -16,6 +16,7 @@ import {
getAutoReplyPage,
} from '#/api/mp/autoReply';
import { $t } from '#/locales';
import { WxAccountSelect } from '#/views/mp/components';
import { useGridColumns, useGridFormSchema } from './data';
import ReplyContentCell from './modules/content.vue';
@@ -43,6 +44,12 @@ function handleRefresh() {
gridApi.query();
}
/** 公众号变化时查询数据 */
function handleAccountChange(accountId: number) {
gridApi.formApi.setValues({ accountId });
gridApi.formApi.submitForm();
}
/** 切换回复类型 */
async function onTabChange(tabName: any) {
msgType.value = tabName;
@@ -106,7 +113,6 @@ const [FormModal, formModalApi] = useVbenModal({
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
submitOnChange: true, // 表单值变化时自动提交,这样 accountId 会被正确传递到查询函数
},
gridOptions: {
columns: useGridColumns(Number(msgType.value) as MsgType),
@@ -123,6 +129,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
});
},
},
autoLoad: false,
},
rowConfig: {
keyField: 'id',
@@ -144,6 +151,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<FormModal @success="handleRefresh" />
<Grid>
<template #form-accountId>
<WxAccountSelect @change="handleAccountChange" />
</template>
<template #toolbar-actions>
<Tabs
v-model:active-key="msgType"

View File

@@ -1,5 +1,6 @@
// 消息类型Follow: 关注时回复Message: 消息回复Keyword: 关键词回复)
// 作为 tab.nameenum 的数字不能随意修改,与 api 参数相关
// TODO @hw可以搞到 biz-mp-enum.ts 里。
export enum MsgType {
Follow = 1,
Keyword = 3,

View File

@@ -1,3 +1,4 @@
// TODO @hw看看要不要迁移到 packages/constants/src/biz-mp-enum.ts
export enum ReplyType {
Image = 'image',
Music = 'music',

View File

@@ -9,3 +9,5 @@ export * from './wx-news';
export * from './wx-reply';
export * from './wx-video-play';
export * from './wx-voice-play';
// TODO @hw要不使用 export { default as WxAccountSelect } from './account-select.vue'; 形式;

View File

@@ -59,7 +59,7 @@ onMounted(handleQuery);
<Select
v-model:value="account.id"
placeholder="请选择公众号"
class="!w-[240px]"
class="!w-full"
@change="onChanged"
>
<Select.Option v-for="item in accountList" :key="item.id" :value="item.id">

View File

@@ -1,12 +1,5 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { MpAccountApi } from '#/api/mp/account';
import { getSimpleAccountList } from '#/api/mp/account';
/** 关联数据 */
let accountList: MpAccountApi.AccountSimple[] = [];
getSimpleAccountList().then((data) => (accountList = data));
/** 获取表格列配置 */
export function useGridColumns(): VxeTableGridOptions['columns'] {
@@ -32,15 +25,7 @@ export function useGridFormSchema(): VbenFormSchema[] {
{
fieldName: 'accountId',
label: '公众号',
component: 'ApiSelect',
componentProps: {
options: accountList.map((item) => ({
label: item.name,
value: item.id,
})),
placeholder: '请选择公众号',
},
defaultValue: accountList[0]?.id,
component: 'Input',
},
];
}

View File

@@ -11,6 +11,7 @@ import { message } from 'ant-design-vue';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import { deleteDraft, getDraftPage } from '#/api/mp/draft';
import { submitFreePublish } from '#/api/mp/freePublish';
import { WxAccountSelect } from '#/views/mp/components';
import { createEmptyNewsItem } from '#/views/mp/draft/modules/types';
import { useGridColumns, useGridFormSchema } from './data';
@@ -24,6 +25,12 @@ function handleRefresh() {
gridApi.query();
}
/** 公众号变化时查询数据 */
function handleAccountChange(accountId: number) {
gridApi.formApi.setValues({ accountId });
gridApi.formApi.submitForm();
}
/** 新增草稿 */
async function handleCreate() {
const formValues = await gridApi.formApi.getValues();
@@ -115,7 +122,6 @@ const [FormModal, formModalApi] = useVbenModal({
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
submitOnChange: true,
},
gridOptions: {
columns: useGridColumns(),
@@ -144,6 +150,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
};
},
},
autoLoad: false,
},
rowConfig: {
keyField: 'mediaId',
@@ -167,6 +174,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<FormModal @success="handleRefresh" />
<Grid table-title="草稿列表">
<template #form-accountId>
<WxAccountSelect @change="handleAccountChange" />
</template>
<template #toolbar-tools>
<TableAction
:actions="[

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