Merge remote-tracking branch 'yudao/master'

This commit is contained in:
jason
2026-06-26 10:32:14 +08:00
361 changed files with 2296 additions and 2454 deletions

View File

@@ -20,7 +20,7 @@
"build:analyze": "pnpm vite build --mode analyze",
"dev": "pnpm vite --mode development",
"preview": "vite preview",
"typecheck": "vue-tsc --noEmit --skipLibCheck"
"typecheck": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vue-tsc --noEmit --skipLibCheck --incremental --tsBuildInfoFile node_modules/.cache/vue-tsc/tsconfig.tsbuildinfo"
},
"imports": {
"#/*": "./src/*"

View File

@@ -14,7 +14,7 @@ export namespace AiChatConversationApi {
temperature: number; // 温度参数
maxTokens: number; // 单条回复的最大 Token 数量
maxContexts: number; // 上下文的最大 Message 数量
createTime?: Date; // 创建时间
createTime: Date; // 创建时间
systemMessage?: string; // 角色设定
modelName?: string; // 模型名字
roleAvatar?: string; // 角色头像

View File

@@ -34,15 +34,15 @@ export namespace AiImageApi {
prompt: string; // 提示词
modelId: number; // 模型
style: string; // 图像生成的风格
width: string; // 图片宽度
height: string; // 图片高度
width: number; // 图片宽度
height: number; // 图片高度
options: object; // 绘制参数Map<String, String>
}
export interface ImageMidjourneyImagineReqVO {
prompt: string; // 提示词
modelId: number; // 模型
base64Array?: string[]; // size不能为空
base64Array: string[]; // 参考图 base64 列表
width: string; // 图片宽度
height: string; // 图片高度
version: string; // 版本

View File

@@ -12,7 +12,6 @@ export namespace BpmOALeaveApi {
startTime: number;
endTime: number;
createTime: Date;
startUserSelectAssignees?: Record<string, string[]>;
}
}

View File

@@ -11,15 +11,16 @@ export namespace CrmBusinessStatusApi {
deptNames?: string[];
creator?: string;
createTime?: Date;
statuses?: BusinessStatusType[];
statuses: BusinessStatusType[];
}
/** 商机状态信息 */
export interface BusinessStatusType {
id?: number;
name: string;
percent: number;
[x: string]: any;
percent?: number;
endStatus?: number;
key?: string;
}
}
@@ -43,7 +44,7 @@ export const DEFAULT_STATUSES = [
name: '无效',
percent: 0,
},
];
] satisfies CrmBusinessStatusApi.BusinessStatusType[];
/** 查询商机状态组列表 */
export function getBusinessStatusPage(params: PageParam) {

View File

@@ -35,11 +35,6 @@ export namespace CrmReceivableApi {
no: string;
totalPrice: number;
}
export interface ReceivablePageParam extends PageParam {
contractId?: number;
customerId?: number;
}
}
/** 查询回款列表 */
@@ -51,9 +46,7 @@ export function getReceivablePage(params: PageParam) {
}
/** 查询回款列表,基于指定客户 */
export function getReceivablePageByCustomer(
params: CrmReceivableApi.ReceivablePageParam,
) {
export function getReceivablePageByCustomer(params: PageParam) {
return requestClient.get<PageResult<CrmReceivableApi.Receivable>>(
'/crm/receivable/page-by-customer',
{ params },

View File

@@ -24,6 +24,18 @@ export namespace InfraCodegenApi {
parentMenuId: number;
}
/** 代码生成表保存请求 */
export interface CodegenTableSaveReqVO extends CodegenTable {
frontType?: null | number;
genPath?: string;
genType?: string;
masterTableId?: number;
subJoinColumnId?: number;
subJoinMany?: boolean;
treeParentColumnId?: number;
treeNameColumnId?: number;
}
/** 代码生成字段定义 */
export interface CodegenColumn {
id: number;
@@ -54,7 +66,7 @@ export namespace InfraCodegenApi {
/** 代码生成详情 */
export interface CodegenDetail {
table: CodegenTable;
table: CodegenTableSaveReqVO;
columns: CodegenColumn[];
}
@@ -66,7 +78,7 @@ export namespace InfraCodegenApi {
/** 更新代码生成请求 */
export interface CodegenUpdateReqVO {
table: any | CodegenTable;
table: CodegenTableSaveReqVO;
columns: CodegenColumn[];
}

View File

@@ -11,7 +11,7 @@ export namespace Demo02CategoryApi {
}
/** 查询示例分类列表 */
export function getDemo02CategoryList(params: any) {
export function getDemo02CategoryList(params?: any) {
return requestClient.get<Demo02CategoryApi.Demo02Category[]>(
'/infra/demo02-category/list',
{ params },

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
}
}

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
demo03courses?: Demo03Course[];
demo03grade?: Demo03Grade;

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
demo03courses?: Demo03Course[];
demo03grade?: Demo03Grade;

View File

@@ -6,11 +6,11 @@ export namespace IoTOtaTaskApi {
/** IoT OTA 升级任务 */
export interface Task {
id?: number;
name?: string;
name: string;
description?: string;
firmwareId?: number;
status?: number;
deviceScope?: number;
deviceScope: number;
deviceIds?: number[];
deviceTotalCount?: number;
deviceSuccessCount?: number;

View File

@@ -30,8 +30,8 @@ export namespace ThingModelApi {
required?: boolean;
dataType?: string;
description?: string;
dataSpecs?: any;
dataSpecsList?: any[];
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
}
/** IoT 物模型服务 */
@@ -64,8 +64,8 @@ export namespace ThingModelApi {
direction?: string;
paraOrder?: number;
dataType?: string;
dataSpecs?: any;
dataSpecsList?: any[];
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
}
/** IoT 物模型 TSL树形响应 */
@@ -78,19 +78,35 @@ export namespace ThingModelApi {
}
/** IoT 数据定义(数值型) */
export interface DataSpecsNumberData {
export interface ThingModelDataSpecs {
accessMode?: string;
childDataType?: string;
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
dataType?: string;
defaultValue?: string;
description?: string;
identifier?: string;
length?: number | string;
min?: number | string;
max?: number | string;
name?: string;
precise?: string;
required?: boolean;
size?: number | string;
step?: number | string;
unit?: string;
unitName?: string;
value?: number | string;
}
/** IoT 数据定义(数值型) */
export type DataSpecsNumberData = ThingModelDataSpecs;
/** IoT 数据定义(枚举/布尔型) */
export interface DataSpecsEnumOrBoolData {
value: number | string;
name: string;
}
export type DataSpecsEnumOrBoolData = ThingModelDataSpecs;
export type ThingModelPropertyDataSpecs = Property & ThingModelDataSpecs;
}
/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */

View File

@@ -76,9 +76,9 @@ export function getSpuPage(params: PageParam) {
});
}
/** 获得商品 SPU 列表 tabsCount */
export function getTabsCount() {
return requestClient.get<Record<string, number>>('/product/spu/get-count');
/** 获得商品 SPU 列表 tabsCount(支持按 name/categoryId/createTime 筛选) */
export function getTabsCount(params?: Record<string, any>) {
return requestClient.get<Record<string, number>>('/product/spu/get-count', { params });
}
/** 创建商品 SPU */

View File

@@ -8,6 +8,7 @@ export namespace MallCombinationActivityApi {
id?: number; // 活动编号
name?: string; // 活动名称
spuId?: number; // 商品 SPU 编号
spuName?: string; // 商品 SPU 名称
totalLimitCount?: number; // 总限购数量
singleLimitCount?: number; // 单次限购数量
startTime?: Date; // 开始时间
@@ -21,7 +22,7 @@ export namespace MallCombinationActivityApi {
limitDuration?: number; // 限制时长
combinationPrice?: number; // 拼团价格
products: CombinationProduct[]; // 商品列表
picUrl?: any;
picUrl?: string; // 商品图片
}
/** 拼团活动所需属性 */

View File

@@ -26,9 +26,9 @@ export namespace MallRewardActivityApi {
conditionType?: number; // 条件类型
productScope?: number; // 商品范围
rules: RewardRule[]; // 优惠规则列表
productScopeValues?: number[]; // 商品范围值(仅表单使用):值为品类编号列表、商品编号列表
productCategoryIds?: number[]; // 商品分类编号列表(仅表单使用)
productSpuIds?: number[]; // 商品 SPU 编号列表(仅表单使用)
productScopeValues: number[]; // 商品范围值(仅表单使用):值为品类编号列表、商品编号列表
productCategoryIds: number[]; // 商品分类编号列表(仅表单使用)
productSpuIds: number[]; // 商品 SPU 编号列表(仅表单使用)
}
}

View File

@@ -31,7 +31,7 @@ export namespace MallSeckillActivityApi {
totalStock?: number; // 秒杀总库存
seckillPrice?: number; // 秒杀价格
products?: SeckillProduct[]; // 秒杀商品列表
picUrl?: any;
picUrl?: string; // 商品图片
}
}

View File

@@ -4,20 +4,21 @@ export namespace MallTradeConfigApi {
/** 交易中心配置 */
export interface Config {
id?: number;
afterSaleRefundReasons?: string[];
afterSaleReturnReasons?: string[];
deliveryExpressFreeEnabled?: boolean;
deliveryExpressFreePrice?: number;
deliveryPickUpEnabled?: boolean;
afterSaleRefundReasons: string[];
afterSaleReturnReasons: string[];
deliveryExpressFreeEnabled: boolean;
deliveryExpressFreePrice: number;
deliveryPickUpEnabled: boolean;
brokerageEnabled?: boolean;
brokerageEnabledCondition?: number;
brokerageBindMode?: number;
brokeragePosterUrls?: string;
brokeragePosterUrls: string[];
brokerageFirstPercent?: number;
brokerageSecondPercent?: number;
brokerageWithdrawMinPrice?: number;
brokerageFrozenDays?: number;
brokerageWithdrawTypes?: string;
brokerageWithdrawMinPrice: number;
brokerageFrozenDays: number;
brokerageWithdrawFeePercent: number;
brokerageWithdrawTypes: number[];
tencentLbsKey?: string;
}
}

View File

@@ -7,6 +7,7 @@ export namespace MemberAddressApi {
name: string;
mobile: string;
areaId: number;
areaName?: string;
detailAddress: string;
defaultStatus: boolean;
}

View File

@@ -4,7 +4,7 @@ export namespace MemberConfigApi {
/** 积分设置信息 */
export interface Config {
id?: number;
pointTradeDeductEnable: number;
pointTradeDeductEnable: boolean;
pointTradeDeductUnitPrice: number;
pointTradeDeductMaxPrice: number;
pointTradeGivePoint: number;

View File

@@ -10,27 +10,31 @@ export namespace MemberUserApi {
birthday?: number;
createTime?: number;
loginDate?: number;
loginIp: string;
mark: string;
mobile: string;
loginIp?: string;
mark?: string;
mobile?: string;
email?: string;
name?: string;
nickname?: string;
registerIp: string;
sex: number;
status: number;
registerIp?: string;
sex?: number;
status?: number;
areaId?: number;
areaName?: string;
levelName: string;
point?: number;
totalPoint?: number;
experience?: number;
tagIds?: number[];
groupId?: number;
levelId?: number;
levelName?: null | string;
point?: null | number;
totalPoint?: null | number;
experience?: null | number;
}
/** 会员用户等级更新信息 */
export interface UserUpdateLevelReqVO {
id: number;
levelId: number;
reason: string;
}
/** 会员用户积分更新信息 */

View File

@@ -11,6 +11,12 @@ export namespace MpTagApi {
count?: number;
createTime?: Date;
}
/** 标签精简信息 */
export interface SimpleTag {
tagId: number;
name: string;
}
}
/** 创建公众号标签 */
@@ -46,7 +52,7 @@ export function getTagPage(params: PageParam) {
/** 获取公众号标签精简信息列表 */
export function getSimpleTagList() {
return requestClient.get<MpTagApi.Tag[]>('/mp/tag/list-all-simple');
return requestClient.get<MpTagApi.SimpleTag[]>('/mp/tag/list-all-simple');
}
/** 同步公众号标签 */

View File

@@ -3,6 +3,16 @@ import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace PayNotifyApi {
/** 支付通知日志 */
export interface NotifyLog {
id?: number;
status?: number;
notifyTimes?: number;
lastExecuteTime?: Date;
createTime?: Date;
response?: string;
}
/** 支付通知任务 */
export interface NotifyTask {
id: number;
@@ -20,13 +30,13 @@ export namespace PayNotifyApi {
maxNotifyTimes: number;
createTime: Date;
updateTime: Date;
logs?: any[];
logs?: NotifyLog[];
}
}
/** 获得支付通知明细 */
export function getNotifyTaskDetail(id: number) {
return requestClient.get(`/pay/notify/get-detail?id=${id}`);
return requestClient.get<PayNotifyApi.NotifyTask>(`/pay/notify/get-detail?id=${id}`);
}
/** 获得支付通知分页 */

View File

@@ -110,7 +110,10 @@ export function getSimpleUser(id: number | string) {
/** 按昵称模糊搜索用户 */
export function getSimpleUserListByNickname(nickname: string) {
return requestClient.get<SystemUserApi.UserSimple[]>('/system/user/list-by-nickname', {
params: { nickname },
});
return requestClient.get<SystemUserApi.UserSimple[]>(
'/system/user/list-by-nickname',
{
params: { nickname },
},
);
}

View File

@@ -109,21 +109,6 @@ const coreRoutes: RouteRecordRaw[] = [
},
],
},
/**
* 用于 bpm 移动端流程表单 web-view 的嵌入
*/
{
component: () => import('#/views/bpm/form/mobile/index.vue'),
meta: {
hideInBreadcrumb: true,
hideInMenu: true,
hideInTab: true,
ignoreAccess: true,
title: '移动端流程表单展示',
},
name: 'BpmMobileFormPreview',
path: '/bpm/mobile/form-preview',
},
];
export { coreRoutes, fallbackNotFoundRoute };

View File

@@ -90,7 +90,7 @@ export const useMallKefuStore = defineStore('mall-kefu', {
},
conversationSort() {
// 按置顶属性和最后消息时间排序
this.conversationList.toSorted((a, b) => {
this.conversationList = this.conversationList.toSorted((a, b) => {
// 按照置顶排序,置顶的会在前面
if (a.adminPinned !== b.adminPinned) {
return a.adminPinned ? -1 : 1;

View File

@@ -90,7 +90,7 @@ async function getChatConversationList() {
// 1.1 获取 对话数据
conversationList.value = await getChatConversationMyList();
// 1.2 排序
conversationList.value.toSorted((a, b) => {
conversationList.value = conversationList.value.toSorted((a, b) => {
return Number(b.createTime) - Number(a.createTime);
});
// 1.3 没有任何对话情况

View File

@@ -20,8 +20,8 @@ const props = defineProps({
const emits = defineEmits(['onBtnClick', 'onMjBtnClick']);
/** 处理点击事件 */
async function handleButtonClick(type: string, detail: AiImageApi.Image) {
emits('onBtnClick', type, detail);
async function handleButtonClick(type: string) {
emits('onBtnClick', type, props.detail);
}
/** 处理 Midjourney 按钮点击事件 */
@@ -79,28 +79,28 @@ onMounted(async () => {
<Button
class="m-0 p-2"
type="text"
@click="handleButtonClick('download', detail)"
@click="handleButtonClick('download')"
>
<IconifyIcon icon="lucide:download" />
</Button>
<Button
class="m-0 p-2"
type="text"
@click="handleButtonClick('regeneration', detail)"
@click="handleButtonClick('regeneration')"
>
<IconifyIcon icon="lucide:refresh-cw" />
</Button>
<Button
class="m-0 p-2"
type="text"
@click="handleButtonClick('delete', detail)"
@click="handleButtonClick('delete')"
>
<IconifyIcon icon="lucide:trash" />
</Button>
<Button
class="m-0 p-2"
type="text"
@click="handleButtonClick('more', detail)"
@click="handleButtonClick('more')"
>
<IconifyIcon icon="lucide:ellipsis-vertical" />
</Button>
@@ -119,8 +119,8 @@ onMounted(async () => {
<div class="mt-2 flex w-full flex-wrap justify-start">
<Button
size="small"
v-for="(button, index) in detail?.buttons"
:key="index"
v-for="button in detail?.buttons"
:key="button.customId"
class="m-2 ml-0 min-w-10"
@click="handleMidjourneyBtnClick(button)"
>

View File

@@ -111,8 +111,8 @@ async function handleGenerateImage() {
prompt: prompt.value, // 提示词
modelId: matchedModel.id, // 使用匹配到的模型
style: style.value, // 图像生成的风格
width: imageSize.width, // size 不能为空
height: imageSize.height, // size 不能为空
width: Number(imageSize.width), // size 不能为空
height: Number(imageSize.height), // size 不能为空
options: {
style: style.value, // 图像生成的风格
},

View File

@@ -99,6 +99,7 @@ async function handleGenerateImage() {
const req = {
prompt: prompt.value,
modelId: matchedModel.id,
base64Array: [],
width: imageSize.width,
height: imageSize.height,
version: selectVersion.value,

View File

@@ -1,16 +1,22 @@
<script lang="ts" setup>
import { inject, reactive, ref } from 'vue';
import type { MusicSong } from '../types';
import { computed, inject, nextTick, reactive, ref, watch } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { formatPast } from '@vben/utils';
import { Image, Slider } from 'ant-design-vue';
import { currentSongKey } from '../types';
defineOptions({ name: 'AiMusicAudioBarIndex' });
const currentSong = inject<any>('currentSong', {});
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
const currentAudioUrl = computed(() => currentSong.value.audioUrl || undefined);
const audioRef = ref<HTMLAudioElement | null>(null);
const audioProgress = ref(0);
const audioDuration = ref(0);
const audioProps = reactive<any>({
autoplay: true,
paused: false,
@@ -20,6 +26,17 @@ const audioProps = reactive<any>({
volume: 50,
}); // 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
function formatAudioTime(seconds: number) {
if (!Number.isFinite(seconds)) {
return '00:00';
}
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.floor(seconds % 60);
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds
.toString()
.padStart(2, '0')}`;
}
function toggleStatus(type: string) {
audioProps[type] = !audioProps[type];
if (type === 'paused' && audioRef.value) {
@@ -32,9 +49,40 @@ function toggleStatus(type: string) {
}
/** 更新播放位置 */
function audioTimeUpdate(args: any) {
audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss');
function audioTimeUpdate() {
if (!audioRef.value) {
return;
}
audioProgress.value = audioRef.value.currentTime;
audioProps.currentTime = formatAudioTime(audioRef.value.currentTime);
}
function audioLoadedMetadata() {
if (!audioRef.value) {
return;
}
audioDuration.value = audioRef.value.duration;
audioProps.duration = formatAudioTime(audioRef.value.duration);
}
function handleProgressChange(value: number | [number, number]) {
if (!audioRef.value || Array.isArray(value)) {
return;
}
audioRef.value.currentTime = value;
audioProgress.value = value;
audioProps.currentTime = formatAudioTime(value);
}
watch(currentAudioUrl, () => {
audioProgress.value = 0;
audioDuration.value = 0;
audioProps.currentTime = '00:00';
audioProps.duration = '00:00';
nextTick(() => {
audioRef.value?.load();
});
});
</script>
<template>
@@ -48,8 +96,10 @@ function audioTimeUpdate(args: any) {
:width="45"
/>
<div>
<div>{{ currentSong.name }}</div>
<div class="text-xs text-gray-400">{{ currentSong.singer }}</div>
<div>{{ currentSong.title || '暂无音乐' }}</div>
<div class="text-xs text-gray-400">
{{ currentSong.singer || currentSong.desc }}
</div>
</div>
</div>
<!-- 音频controls -->
@@ -74,22 +124,25 @@ function audioTimeUpdate(args: any) {
<div class="flex items-center gap-4">
<span>{{ audioProps.currentTime }}</span>
<Slider
v-model:value="audioProps.duration"
v-model:value="audioProgress"
:max="audioDuration"
color="#409eff"
class="!w-40"
@change="handleProgressChange"
/>
<span>{{ audioProps.duration }}</span>
</div>
<!-- 音频 -->
<audio
v-bind="audioProps"
:src="currentAudioUrl"
:autoplay="audioProps.autoplay"
:muted="audioProps.muted"
ref="audioRef"
controls
v-show="!audioProps"
@timeupdate="audioTimeUpdate"
>
<!-- <source :src="audioUrl" /> -->
</audio>
@loadedmetadata="audioLoadedMetadata"
></audio>
</div>
<div class="flex items-center gap-4">
<IconifyIcon

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { Recordable } from '@vben/types';
import type { MusicSong } from './types';
import { provide, ref } from 'vue';
@@ -8,14 +9,15 @@ import { Col, Empty, Row, TabPane, Tabs } from 'ant-design-vue';
import audioBar from './audioBar/index.vue';
import songCard from './songCard/index.vue';
import songInfo from './songInfo/index.vue';
import { currentSongKey } from './types';
defineOptions({ name: 'AiMusicListIndex' });
const currentType = ref('mine');
const loading = ref(false); // loading 状态
const currentSong = ref({}); // 当前音乐
const mySongList = ref<Recordable<any>[]>([]);
const squareSongList = ref<Recordable<any>[]>([]);
const currentSong = ref<MusicSong>({}); // 当前音乐
const mySongList = ref<MusicSong[]>([]);
const squareSongList = ref<MusicSong[]>([]);
function generateMusic(_formData: Recordable<any>) {
loading.value = true;
@@ -45,7 +47,7 @@ function generateMusic(_formData: Recordable<any>) {
}, 3000);
}
function setCurrentSong(music: Recordable<any>) {
function setCurrentSong(music: MusicSong) {
currentSong.value = music;
}
@@ -53,7 +55,7 @@ defineExpose({
generateMusic,
});
provide('currentSong', currentSong);
provide(currentSongKey, currentSong);
</script>
<template>

View File

@@ -1,22 +1,23 @@
<script lang="ts" setup>
import { inject } from 'vue';
import type { MusicSong } from '../types';
import { inject, ref } from 'vue';
import { IconifyIcon } from '@vben/icons';
import { Image } from 'ant-design-vue';
import { currentSongKey } from '../types';
defineOptions({ name: 'AiMusicSongCardIndex' });
defineProps({
songInfo: {
type: Object,
default: () => ({}),
},
withDefaults(defineProps<{ songInfo?: MusicSong }>(), {
songInfo: () => ({}),
});
const emits = defineEmits(['play']);
const currentSong = inject<any>('currentSong', {});
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
function playSong() {
emits('play');

View File

@@ -1,11 +1,15 @@
<script lang="ts" setup>
import { inject } from 'vue';
import type { MusicSong } from '../types';
import { inject, ref } from 'vue';
import { Button, Card, Image } from 'ant-design-vue';
import { currentSongKey } from '../types';
defineOptions({ name: 'AiMusicSongInfoIndex' });
const currentSong = inject<any>('currentSong', {});
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
</script>
<template>

View File

@@ -0,0 +1,16 @@
import type { InjectionKey, Ref } from 'vue';
export interface MusicSong {
audioUrl?: string;
date?: string;
desc?: string;
id?: number;
imageUrl?: string;
lyric?: string;
singer?: string;
title?: string;
videoUrl?: string;
}
export const currentSongKey: InjectionKey<Ref<MusicSong>> =
Symbol('currentSong');

View File

@@ -245,6 +245,9 @@ const moddleExtensions = computed(() => {
const initBpmnModeler = () => {
if (bpmnModeler) return;
const data: any = document.querySelector('#bpmnCanvas');
if (!data) {
return;
}
// console.log(data, 'data');
// console.log(props.keyboard, 'props.keyboard');
// console.log(additionalModules, 'additionalModules()');
@@ -261,7 +264,7 @@ const initBpmnModeler = () => {
// propertiesPanel: {
// parent: '#js-properties-panel'
// },
keyboard: props.keyboard ? { bindTo: document } : null,
keyboard: props.keyboard ? { bind: true } : null,
// additionalModules: additionalModules.value,
additionalModules: additionalModules.value as any[],
moddleExtensions: moddleExtensions.value,

View File

@@ -39,10 +39,29 @@ const dialogTitle = ref<string | undefined>(undefined); // 弹窗标题
const selectActivityType = ref<string | undefined>(undefined); // 选中 Task 的活动编号
const selectTasks = ref<any[]>([]); // 选中的任务数组
type BpmnCanvas = {
_svg?: SVGSVGElement;
addMarker: (element: any, marker: string) => void;
removeMarker: (element: any, marker: string) => void;
zoom: (
newScale?: 'fit-viewport' | number,
center?: 'auto' | { x: number; y: number },
) => number;
};
type ElementRegistry = {
filter: (callback: (element: any) => boolean) => any[];
get: (id: string) => any;
};
const getCanvas = () =>
bpmnViewer.value?.get('canvas') as BpmnCanvas | undefined;
const getElementRegistry = () =>
bpmnViewer.value?.get('elementRegistry') as ElementRegistry | undefined;
/** Zoom恢复 */
const processReZoom = () => {
defaultZoom.value = 1;
bpmnViewer.value?.get('canvas').zoom('fit-viewport', 'auto');
getCanvas()?.zoom('fit-viewport', 'auto');
};
let resizeObserver: null | ResizeObserver = null;
@@ -89,7 +108,7 @@ const processZoomIn = (zoomStep = 0.1) => {
);
}
defaultZoom.value = newZoom;
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
getCanvas()?.zoom(defaultZoom.value);
};
/** Zoom缩小 */
@@ -101,7 +120,7 @@ const processZoomOut = (zoomStep = 0.1) => {
);
}
defaultZoom.value = newZoom;
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
getCanvas()?.zoom(defaultZoom.value);
};
/** 流程图预览清空 */
@@ -122,9 +141,9 @@ const addCustomDefs = () => {
if (!bpmnViewer.value) {
return;
}
const canvas = bpmnViewer.value?.get('canvas');
const canvas = getCanvas();
const svg = canvas?._svg;
svg.append(customDefs.value);
svg?.append(customDefs.value);
};
/** 节点选中 */
@@ -220,8 +239,11 @@ const setProcessStatus = (view: any) => {
finishedSequenceFlowActivityIds,
rejectedTaskActivityIds,
} = view;
const canvas: any = bpmnViewer.value.get('canvas');
const elementRegistry: any = bpmnViewer.value.get('elementRegistry');
const canvas = getCanvas();
const elementRegistry = getElementRegistry();
if (!canvas || !elementRegistry) {
return;
}
// 已完成节点
if (Array.isArray(finishedSequenceFlowActivityIds)) {
@@ -229,7 +251,7 @@ const setProcessStatus = (view: any) => {
if (item !== null) {
canvas.addMarker(item, 'success');
const element = elementRegistry.get(item);
const conditionExpression = element.businessObject.conditionExpression;
const conditionExpression = element?.businessObject.conditionExpression;
if (conditionExpression) {
canvas.addMarker(item, 'condition-expression');
}

View File

@@ -40,7 +40,7 @@ const props = defineProps({
default: '',
},
});
const prefix = inject<string>('prefix', 'flowable'); // 增加默认值flowable
const prefix = inject<string>('prefix', 'flowable');
const elementListenersList = ref<any[]>([]); // 监听器列表
const listenerForm = ref<any>({}); // 监听器详情表单
const fieldsListOfListener = ref<any[]>([]);

View File

@@ -61,8 +61,8 @@ interface LoopInstanceForm {
}
const loopInstanceForm = ref<LoopInstanceForm>({});
const bpmnElement = ref<any>(null);
const multiLoopInstance = ref<any>(null);
const bpmnElement = ref<any | null>(null);
const multiLoopInstance = ref<any | null>(null);
declare global {
interface Window {
bpmnInstances?: () => any;
@@ -276,7 +276,7 @@ const approveMethod = ref<ApproveMethodType | undefined>();
const approveRatio = ref<number>(100);
const otherExtensions = ref<any[]>([]);
const getElementLoopNew = (): void => {
if (props.type === 'UserTask') {
if (props.type === 'UserTask' && bpmnElement.value) {
const loopCharacteristics =
bpmnElement.value.businessObject?.loopCharacteristics;
const extensionElements =
@@ -320,6 +320,9 @@ const onApproveRatioChange = (): void => {
updateLoopCharacteristics();
};
const updateLoopCharacteristics = (): void => {
if (!bpmnElement.value) {
return;
}
// 根据ApproveMethod生成multiInstanceLoopCharacteristics节点
if (approveMethod.value === ApproveMethodType.RANDOM_SELECT_ONE_APPROVE) {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
@@ -367,9 +370,11 @@ const updateLoopCharacteristics = (): void => {
body: `\${ nrOfCompletedInstances >= nrOfInstances }`,
});
}
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
loopCharacteristics: toRaw(multiLoopInstance.value),
});
if (multiLoopInstance.value) {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
loopCharacteristics: toRaw(multiLoopInstance.value),
});
}
}
// 添加ApproveMethod到ExtensionElements

View File

@@ -186,6 +186,12 @@ const multiFormFieldOptions = computed(() => {
(item) => item.type === 'select' || item.type === 'checkbox',
);
});
const multiInstanceSourceNumber = computed({
get: () => Number(configForm.value.multiInstanceSource || 1),
set: (value?: number) => {
configForm.value.multiInstanceSource = String(value || '');
},
});
const childFormFieldOptions = ref<any[]>([]);
/** 保存配置 */
@@ -806,7 +812,7 @@ onMounted(async () => {
}"
>
<InputNumber
v-model:value="configForm.multiInstanceSource"
v-model:value="multiInstanceSourceNumber"
:min="1"
/>
</FormItem>

View File

@@ -1,405 +0,0 @@
<script lang="ts" setup>
/**
* 移动端流程表单展示页面 - Ant Design Vue 版本
* 使用 @form-create/ant-design-vue 渲染表单
* 用于 UniApp 通过 iframe/webview 嵌入
*
* URL 参数说明:
* - type: 环境类型(必填)'miniapp' 小程序(微信/支付宝/百度等) | 'h5' H5
* - processInstanceId: 流程实例ID查看已有流程时使用
* - taskId: 任务ID可选
* - activityId: 活动节点ID可选
* - token: 访问令牌(用于 API 认证)
*/
import { computed, nextTick, onMounted, ref, toRaw } from 'vue';
import { useRoute } from 'vue-router';
import { BpmFieldPermissionType, BpmModelFormType } from '@vben/constants';
import { updatePreferences } from '@vben/preferences';
import { useAccessStore } from '@vben/stores';
import { Button, Empty, Spin } from 'ant-design-vue';
import { getApprovalDetail } from '#/api/bpm/processInstance';
import { setConfAndFields2 } from '#/components/form-create';
type EnvType = 'h5' | 'miniapp'; // 环境类型
// UniApp WebView 类型声明
interface UniWebView {
postMessage: (options: { data: any }, targetOrigin?: string) => void;
getEnv: (callback: (res: any) => void) => void;
navigateTo: (options: {
fail?: () => void;
success?: () => void;
url: string;
}) => void;
navigateBack: (options?: { delta?: number }) => void;
switchTab: (options: { url: string }) => void;
reLaunch: (options: { url: string }) => void;
redirectTo: (options: { url: string }) => void;
}
declare global {
interface Window {
uni?: UniWebView;
}
}
defineOptions({ name: 'BpmMobileFormPreview' });
const route = useRoute();
const accessStore = useAccessStore();
const envType = ref<EnvType>('h5'); // 环境类型
const loading = ref(true); // 页面加载状态
const error = ref<null | string>(null);
const processInstance = ref<any>(null);
const processDefinition = ref<any>(null);
const detailForm = ref<{
option: any;
rule: any[];
value: Record<string, any>;
}>({
option: {},
rule: [],
value: {},
}); // 流程实例的表单详情
const fApi = ref<any>(null); // form-create API 引用
const fieldPermissions = ref<Record<string, string>>({}); // 字段权限
// 是否有表单内容
const hasFormContent = computed(() => {
return detailForm.value.rule && detailForm.value.rule.length > 0;
});
/**
* 初始化 Token
* 从 URL 参数获取 token 并设置到 store
*/
function initToken() {
const token = route.query.token as string;
if (token) {
accessStore.setAccessToken(token);
}
}
/**
* 验证并初始化环境类型
*/
function initEnvType(): boolean {
const type = route.query.type as string;
if (!type) {
error.value = '缺少必填参数: type';
return false;
}
if (type !== 'h5' && type !== 'miniapp') {
error.value = 'type 参数值无效,必须是 h5 或 miniapp';
return false;
}
envType.value = type as EnvType;
return true;
}
/**
* 获取审批详情
*/
async function getDetail() {
loading.value = true;
error.value = null;
try {
const processInstanceId = route.query.processInstanceId as string;
const taskId = route.query.taskId as string;
const activityId = route.query.activityId as string;
if (!processInstanceId) {
throw new Error('缺少流程实例ID参数');
}
const data = await getApprovalDetail({
processInstanceId,
taskId,
activityId,
});
if (!data) {
throw new Error('查询不到审批详情信息');
}
if (!data.processDefinition || !data.processInstance) {
throw new Error('查询不到流程信息');
}
processInstance.value = data.processInstance;
processDefinition.value = data.processDefinition;
// 设置普通表单信息
if (data.processDefinition.formType === BpmModelFormType.NORMAL) {
if (detailForm.value.rule?.length > 0) {
// 避免刷新 form-create 显示不了
detailForm.value.value = processInstance.value.formVariables;
} else {
setConfAndFields2(
detailForm,
processDefinition.value.formConf,
processDefinition.value.formFields,
processInstance.value.formVariables,
);
}
await nextTick();
fApi.value?.btn.show(false);
fApi.value?.resetBtn.show(false);
fApi.value?.disabled(true);
// 设置表单字段权限
if (data.formFieldsPermission) {
Object.keys(data.formFieldsPermission).forEach((item) => {
setFieldPermission(item, data.formFieldsPermission[item]);
});
}
}
} finally {
loading.value = false;
}
}
/**
* 向父页面发送消息
* 根据环境类型选择不同的通信方式
*/
function postMessageToParent(message: { data: any; type: string }) {
const messageData = {
source: 'bpm-mobile-form',
type: message.type,
data: message.data,
};
// 小程序环境:使用 uni.postMessage
if (envType.value === 'miniapp') {
if (window.uni?.postMessage) {
// 传递的消息信息,必须写在 data 对象中
window.uni.postMessage({ data: message.data }, window.location.origin);
} else {
console.error('小程序环境下 uni 对象未定义');
}
return;
}
// H5 环境:使用 window.postMessage
if (envType.value === 'h5' && window.parent !== window) {
window.parent.postMessage(messageData, '*');
}
}
/**
* 安全地克隆对象,移除不可序列化的属性
*/
function safeClone(obj: any): any {
try {
// 先使用 toRaw 移除 Vue 的响应式代理
const raw = toRaw(obj);
// 使用 JSON 序列化来移除函数、DOM 元素等不可序列化的内容
// eslint-disable-next-line unicorn/prefer-structured-clone
return JSON.parse(JSON.stringify(raw));
} catch (error) {
console.error('克隆对象失败:', error);
return {};
}
}
/** 设置表单权限 */
function setFieldPermission(field: string, permission: string) {
fieldPermissions.value[field] = permission;
if (permission === BpmFieldPermissionType.READ) {
fApi.value?.disabled(true, field);
}
if (permission === BpmFieldPermissionType.WRITE) {
fApi.value?.disabled(false, field);
}
if (permission === BpmFieldPermissionType.NONE) {
fApi.value?.hidden(true, field);
}
}
/**
* 确定按钮点击事件
* 获取表单数据并发送给父页面
*/
function handleConfirm() {
// 获取最新的表单值(转换为普通对象,避免 Proxy 序列化问题)
const rawValue = detailForm.value.value;
const currentValue = safeClone(rawValue);
// 发送表单数据给父页面
postMessageToParent({
type: 'FORM_SUBMIT',
data: {
formValue: currentValue,
fieldPermissions: safeClone(fieldPermissions.value),
processInstanceId: route.query.processInstanceId,
taskId: route.query.taskId,
},
});
window.uni?.navigateBack();
}
onMounted(() => {
// 验证环境类型
if (!initEnvType()) {
loading.value = false;
return;
}
// 1. 先加载微信 JSSDK微信小程序需要
const wxScript = document.createElement('script');
wxScript.type = 'text/javascript';
wxScript.src = 'https://res.wx.qq.com/open/js/jweixin-1.4.0.js';
wxScript.addEventListener('load', () => {
// 2. 微信 SDK 加载完成后,加载 UniApp WebView SDK
const uniScript = document.createElement('script');
uniScript.type = 'text/javascript';
uniScript.src = 'https://unpkg.com/@dcloudio/uni-webview-js@0.0.3/index.js';
uniScript.addEventListener('load', () => {
// 所有 SDK 加载完成后初始化
initApp();
});
uniScript.addEventListener('error', () => {
error.value = 'UniApp WebView SDK 加载失败';
loading.value = false;
});
document.head.append(uniScript);
});
wxScript.addEventListener('error', () => {
// 微信 SDK 加载失败,尝试只加载 UniApp SDK可能是其他小程序
const uniScript = document.createElement('script');
uniScript.type = 'text/javascript';
uniScript.src = 'https://unpkg.com/@dcloudio/uni-webview-js@0.0.3/index.js';
uniScript.addEventListener('load', () => {
initApp();
});
uniScript.addEventListener('error', () => {
error.value = 'SDK 加载失败';
loading.value = false;
});
document.head.append(uniScript);
});
document.head.append(wxScript);
// 初始化
initApp();
});
/**
* 初始化应用
*/
function initApp() {
// 设置主题为 light 模式
updatePreferences({
theme: {
mode: 'light',
},
});
// 初始化 token
initToken();
// 加载数据
if (route.query.processInstanceId) {
getDetail();
} else {
loading.value = false;
error.value = '缺少必要参数processInstanceId';
}
}
</script>
<template>
<div class="mobile-form-preview-antd">
<!-- 加载状态 -->
<div v-if="loading" class="loading-container">
<Spin size="large" tip="加载中..." />
</div>
<!-- 错误状态 -->
<Empty v-else-if="error" :description="error" />
<!-- 表单内容 -->
<template v-else>
<!-- 有表单规则时渲染 form-create -->
<div v-if="hasFormContent" class="mt-4">
<form-create
v-model="detailForm.value"
v-model:api="fApi"
:option="detailForm.option"
:rule="detailForm.rule"
/>
<!-- 确定按钮 -->
<div class="form-footer">
<Button type="primary" size="large" block @click="handleConfirm">
确定
</Button>
</div>
</div>
<!-- 无表单内容时显示空状态 -->
<Empty v-else description="暂无表单内容" />
</template>
</div>
</template>
<style scoped>
/* 响应式适配 */
@media (max-width: 768px) {
.mobile-form-preview-antd {
padding: 12px;
}
:deep(.ant-form-item) {
margin-bottom: 20px;
}
}
.mobile-form-preview-antd {
min-height: 100px;
padding: 16px;
}
.loading-container {
display: flex;
align-items: center;
justify-content: center;
padding: 60px 0;
}
.form-footer {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
padding: 16px;
border-top: 1px solid #f0f0f0;
box-shadow: 0 -2px 8px rgb(0 0 0 / 5%);
}
.form-footer :deep(.ant-btn) {
height: 48px;
font-size: 16px;
font-weight: 500;
border-radius: 8px;
}
</style>

View File

@@ -24,19 +24,21 @@ import {
import { getForm } from '#/api/bpm/form';
import { setConfAndFields2 } from '#/components/form-create';
const props = defineProps({
formList: {
type: Array<BpmFormApi.Form>,
required: true,
},
});
type FormCreateRule = {
[key: string]: unknown;
props?: Record<string, unknown>;
};
defineProps<{
formList: BpmFormApi.Form[];
}>();
const formRef = ref();
const modelData = defineModel<any>(); // 创建本地数据副本
const formPreview = ref({
formData: {} as any,
rule: [],
rule: [] as FormCreateRule[],
option: {
submitBtn: false,
resetBtn: false,
@@ -63,7 +65,7 @@ watch(
const data = await getForm(newFormId);
setConfAndFields2(formPreview.value, data.conf, data.fields);
// 设置只读
formPreview.value.rule.forEach((item: any) => {
formPreview.value.rule.forEach((item) => {
item.props = { ...item.props, disabled: true };
});
} else {
@@ -111,13 +113,12 @@ defineExpose({ validate });
>
<Select v-model:value="modelData.formId" allow-clear>
<SelectOption
v-for="form in props.formList"
v-for="form in formList"
:key="form.id"
:value="form.id"
>
{{ form.name }}
</SelectOption>
>
</Select>
</FormItem>
<FormItem

View File

@@ -28,10 +28,14 @@ const { query } = useRoute();
const formLoading = ref(false); // 表单的加载中1修改时的数据加载2提交的按钮禁用
const processTimeLineLoading = ref(false); // 审批流的加载中
type LeaveCreateData = BpmOALeaveApi.Leave & {
startUserSelectAssignees?: Record<string, number[]>;
};
const processDefineKey = 'oa_leave'; // 流程定义 Key
const startUserSelectTasks = ref<any>([]); // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref<any>({}); // 发起人选择审批人的数据
const tempStartUserSelectAssignees = ref<any>({}); // 历史发起人选择审批人的数据,用于每次表单变更时,临时保存
const startUserSelectTasks = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>([]); // 发起人需要选择审批人的用户任务列表
const startUserSelectAssignees = ref<Record<string, number[]>>({}); // 发起人选择审批人的数据
const tempStartUserSelectAssignees = ref<Record<string, number[]>>({}); // 历史发起人选择审批人的数据,用于每次表单变更时,临时保存
const activityNodes = ref<BpmProcessInstanceApi.ApprovalNodeInfo[]>([]); // 审批节点信息
const processDefinitionId = ref('');
@@ -65,23 +69,21 @@ async function onSubmit() {
// 1.2 审批相关:校验指定审批人
if (startUserSelectTasks.value?.length > 0) {
for (const userTask of startUserSelectTasks.value) {
if (
Array.isArray(startUserSelectAssignees.value[userTask.id]) &&
startUserSelectAssignees.value[userTask.id].length === 0
) {
const assignees = startUserSelectAssignees.value[userTask.id];
if (Array.isArray(assignees) && assignees.length === 0) {
return message.warning(`请选择${userTask.name}的审批人`);
}
}
}
// 提交表单
const data = (await formApi.getValues()) as BpmOALeaveApi.Leave;
const data = (await formApi.getValues()) as LeaveCreateData;
// 审批相关:设置指定审批人
if (startUserSelectTasks.value?.length > 0) {
data.startUserSelectAssignees = startUserSelectAssignees.value;
}
// 格式化开始时间和结束时间的值
const submitData: BpmOALeaveApi.Leave = {
const submitData: LeaveCreateData = {
...data,
startTime: Number(data.startTime),
endTime: Number(data.endTime),
@@ -144,11 +146,10 @@ async function getApprovalDetail() {
// 恢复之前的选择审批人
if (startUserSelectTasks.value?.length > 0) {
for (const node of startUserSelectTasks.value) {
startUserSelectAssignees.value[node.id] =
tempStartUserSelectAssignees.value[node.id] &&
tempStartUserSelectAssignees.value[node.id].length > 0
? tempStartUserSelectAssignees.value[node.id]
: [];
const tempAssignees = tempStartUserSelectAssignees.value[node.id];
startUserSelectAssignees.value[node.id] = tempAssignees?.length
? tempAssignees
: [];
}
}
} finally {
@@ -157,8 +158,8 @@ async function getApprovalDetail() {
}
/** 审批相关:选择发起人 */
function selectUserConfirm(id: string, userList: any[]) {
startUserSelectAssignees.value[id] = userList?.map((item: any) => item.id);
function selectUserConfirm(id: string, userList: Array<{ id: number }>) {
startUserSelectAssignees.value[id] = userList.map((item) => item.id);
}
/** 获取请假数据,用于重新发起时自动填充 */

View File

@@ -64,8 +64,8 @@ const detailForm = ref<ProcessFormData>({
const fApi = ref<any>();
const startUserSelectTasks = ref<UserTask[]>([]);
const startUserSelectAssignees = ref<Record<string, string[]>>({});
const tempStartUserSelectAssignees = ref<Record<string, string[]>>({});
const startUserSelectAssignees = ref<Record<string, number[]>>({});
const tempStartUserSelectAssignees = ref<Record<string, number[]>>({});
const bpmnXML = ref<string | undefined>(undefined);
const simpleJson = ref<string | undefined>(undefined);

View File

@@ -33,6 +33,7 @@ watch(
view.value = newModelView;
}
},
{ immediate: true },
);
/** 监听 bpmnXml */

View File

@@ -56,6 +56,7 @@ watch(
simpleModel.value = newModelView.simpleModel || {};
}
},
{ immediate: true },
);
/** 监控模型结构数据 */

View File

@@ -85,10 +85,10 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
export function useFormColumns(): VxeTableGridOptions['columns'] {
return [
{
field: 'defaultStatus',
field: 'endStatus',
title: '阶段',
minWidth: 100,
slots: { default: 'defaultStatus' },
slots: { default: 'endStatus' },
},
{
field: 'name',

View File

@@ -108,7 +108,7 @@ async function handleAddStatus() {
formData.value!.statuses!.splice(-3, 0, {
name: '',
percent: undefined,
} as any);
});
await nextTick();
await gridApi.grid.reloadData(formData.value!.statuses as any);
}
@@ -152,9 +152,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
<Form class="mx-4">
<template #statuses>
<Grid class="w-full">
<template #defaultStatus="{ row, rowIndex }">
<template #endStatus="{ row, rowIndex }">
<span>
{{ row.defaultStatus ? '结束' : `阶段${rowIndex + 1}` }}
{{ row.endStatus ? '结束' : `阶段${rowIndex + 1}` }}
</span>
</template>
<template #name="{ row }">

View File

@@ -70,17 +70,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
proxyConfig: {
ajax: {
query: async ({ page }) => {
const queryParams: CrmReceivableApi.ReceivablePageParam = {
const queryParams = {
...(props.customerId ? { customerId: props.customerId } : {}),
...(props.customerId && props.contractId
? { contractId: props.contractId }
: {}),
pageNo: page.currentPage,
pageSize: page.pageSize,
};
if (props.customerId && !props.contractId) {
queryParams.customerId = props.customerId;
} else if (props.customerId && props.contractId) {
// 如果是合同的话客户编号也需要带上因为权限基于客户
queryParams.customerId = props.customerId;
queryParams.contractId = props.contractId;
}
return await getReceivablePageByCustomer(queryParams);
},
},

View File

@@ -1,4 +1,4 @@
import { ref, type VNodeRef, watch } from 'vue'
import { type VNodeRef, watch } from 'vue'
/**
* 把响应式 MediaStream 挂到 `<video>` / `<audio>` 元素的 srcObject 上;
@@ -7,21 +7,34 @@ import { ref, type VNodeRef, watch } from 'vue'
export function useMediaStreamElement<T extends HTMLMediaElement>(
streamSource: () => MediaStream | null | undefined
): VNodeRef {
const elRef = ref<T>()
const syncStream = (stream = streamSource()) => {
if (elRef.value) {
elRef.value.srcObject = stream || null
let el: T | null = null
let currentStream: MediaStream | null | undefined
const syncStream = () => {
if (el) {
el.srcObject = currentStream || null
}
}
watch(
streamSource,
(stream) => {
syncStream(stream)
currentStream = stream
syncStream()
},
{ flush: 'post', immediate: true }
)
return (el) => {
elRef.value = el instanceof HTMLMediaElement ? (el as T) : undefined
syncStream()
return (value) => {
if (value instanceof HTMLMediaElement) {
el = value as T
syncStream()
return
}
if (el) {
el.srcObject = null
}
el = null
}
}

View File

@@ -112,7 +112,7 @@ defineExpose({ open });
row-key="userId"
size="small"
>
<template #bodyCell="{ column, record }">
<template #bodyCell="{ column, record, text }">
<template v-if="column.dataIndex === 'avatar'">
<Avatar :src="record.avatar" :size="40">
{{ record.nickname?.charAt(0) || '?' }}
@@ -143,7 +143,7 @@ defineExpose({ open });
<span v-else>-</span>
</template>
<template v-else>
{{ record[column.dataIndex] || '-' }}
{{ text || '-' }}
</template>
</template>
</Table>

View File

@@ -78,7 +78,7 @@ const [Grid] = useVbenVxeGrid({
<template #atUsers="{ row }">
<template v-if="row.atUserIds?.length">
<span v-for="(userId, index) in row.atUserIds" :key="userId">
<span v-if="index > 0"></span>
<span v-if="Number(index) > 0"></span>
<template v-if="userId === IM_AT_ALL_USER_ID">@{{ IM_AT_ALL_NICKNAME }}</template>
<template v-else>@{{ row.atUserNicknames?.[index] || userId }}</template>
</span>

View File

@@ -62,7 +62,7 @@ defineExpose({ open });
<DescriptionsItem label="@用户" :span="2">
<template v-if="detail.atUserIds?.length">
<span v-for="(userId, index) in detail.atUserIds" :key="userId">
<span v-if="index > 0"></span>
<span v-if="Number(index) > 0"></span>
<template v-if="userId === IM_AT_ALL_USER_ID">
@{{ IM_AT_ALL_NICKNAME }}
</template>

View File

@@ -100,7 +100,7 @@ defineExpose({ open });
row-key="id"
size="small"
>
<template #bodyCell="{ column, record }">
<template #bodyCell="{ column, record, text }">
<template v-if="column.dataIndex === 'role'">
<DictTag :type="DICT_TYPE.IM_RTC_PARTICIPANT_ROLE" :value="record.role" />
</template>
@@ -108,10 +108,10 @@ defineExpose({ open });
<DictTag :type="DICT_TYPE.IM_RTC_PARTICIPANT_STATUS" :value="record.status" />
</template>
<template v-else-if="['inviteTime', 'acceptTime', 'leaveTime'].includes(column.dataIndex as string)">
{{ formatDateTimeText(record[column.dataIndex]) }}
{{ formatDateTimeText(text) }}
</template>
<template v-else>
{{ record[column.dataIndex] || '-' }}
{{ text || '-' }}
</template>
</template>
</Table>

View File

@@ -17,7 +17,7 @@ import {
const props = defineProps<{
columns?: InfraCodegenApi.CodegenColumn[];
table?: InfraCodegenApi.CodegenTable;
table?: InfraCodegenApi.CodegenTableSaveReqVO;
}>();
const tables = ref<InfraCodegenApi.CodegenTable[]>([]);
@@ -70,7 +70,7 @@ function updateTreeSchema(): void {
schema: useGenerationInfoTreeFormSchema(props.columns),
});
// 树表信息回显
treeFormApi.setValues(props.table as any);
treeFormApi.setValues(props.table || {});
}
/** 更新主子表信息表单 schema */
@@ -79,7 +79,7 @@ function updateSubSchema(): void {
schema: useGenerationInfoSubTableFormSchema(props.columns, tables.value),
});
// 主子表信息回显
subFormApi.setValues(props.table as any);
subFormApi.setValues(props.table || {});
}
/** 获取合并的表单值 */
@@ -140,7 +140,7 @@ watch(
return;
}
const table = val as InfraCodegenApi.CodegenTable;
const table = val;
// 初始化树表的 schema
updateTreeSchema();
// 设置表单值

View File

@@ -148,7 +148,7 @@ function handleRowCheckboxChange({
}: {
records: Demo03StudentApi.Demo03Student[];
}) {
checkedIds.value = records.map((item) => item.id)!;
checkedIds.value = records.map((item) => item.id!);
}
/** 导出表格 */

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import type { Rule } from 'ant-design-vue/es/form';
import type { Dayjs } from 'dayjs';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/erp';
@@ -28,8 +29,15 @@ import { $t } from '#/locales';
const emit = defineEmits(['success']);
type Demo03StudentFormData = Omit<
Demo03StudentApi.Demo03Student,
'birthday'
> & {
birthday?: Dayjs | string;
};
const formRef = ref();
const formData = ref<Partial<Demo03StudentApi.Demo03Student>>({
const formData = ref<Partial<Demo03StudentFormData>>({
id: undefined,
name: undefined,
sex: undefined,
@@ -96,7 +104,10 @@ const [Modal, modalApi] = useVbenModal({
modalApi.unlock();
}
}
formData.value = data;
formData.value = {
...data,
birthday: data.birthday === undefined ? undefined : String(data.birthday),
};
},
});
</script>

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { onMounted, reactive, ref } from 'vue';
@@ -32,7 +32,7 @@ import {
deleteDemo03StudentList,
exportDemo03Student,
getDemo03StudentPage,
} from '#/api/infra/demo/demo03/normal';
} from '#/api/infra/demo/demo03/inner';
import { DictTag } from '#/components/dict-tag';
import { $t } from '#/locales';
import { getRangePickerDefaultProps } from '#/utils';

View File

@@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { VxeTableInstance } from '#/adapter/vxe-table';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { ref, watch } from 'vue';
@@ -9,7 +9,7 @@ import { IconifyIcon } from '@vben/icons';
import { Button, Input } from 'ant-design-vue';
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { getDemo03CourseListByStudentId } from '#/api/infra/demo/demo03/normal';
import { getDemo03CourseListByStudentId } from '#/api/infra/demo/demo03/inner';
import { $t } from '#/locales';
const props = defineProps<{

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { nextTick, ref, watch } from 'vue';
@@ -7,7 +7,7 @@ import { ContentWrap } from '@vben/common-ui';
import { formatDateTime } from '@vben/utils';
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { getDemo03CourseListByStudentId } from '#/api/infra/demo/demo03/normal';
import { getDemo03CourseListByStudentId } from '#/api/infra/demo/demo03/inner';
const props = defineProps<{
studentId?: number; // 学生编号(主表的关联字段)

View File

@@ -1,13 +1,13 @@
<script lang="ts" setup>
import type { Rule } from 'ant-design-vue/es/form';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { nextTick, ref, watch } from 'vue';
import { Form, Input } from 'ant-design-vue';
import { getDemo03GradeByStudentId } from '#/api/infra/demo/demo03/normal';
import { getDemo03GradeByStudentId } from '#/api/infra/demo/demo03/inner';
const props = defineProps<{
studentId?: number; // 学生编号(主表的关联字段)

View File

@@ -1,5 +1,5 @@
<script lang="ts" setup>
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { nextTick, ref, watch } from 'vue';
@@ -7,7 +7,7 @@ import { ContentWrap } from '@vben/common-ui';
import { formatDateTime } from '@vben/utils';
import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
import { getDemo03GradeByStudentId } from '#/api/infra/demo/demo03/normal';
import { getDemo03GradeByStudentId } from '#/api/infra/demo/demo03/inner';
const props = defineProps<{
studentId?: number; // 学生编号(主表的关联字段)

View File

@@ -1,7 +1,8 @@
<script lang="ts" setup>
import type { Rule } from 'ant-design-vue/es/form';
import type { Dayjs } from 'dayjs';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/inner';
import { computed, ref } from 'vue';
@@ -23,7 +24,7 @@ import {
createDemo03Student,
getDemo03Student,
updateDemo03Student,
} from '#/api/infra/demo/demo03/normal';
} from '#/api/infra/demo/demo03/inner';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { $t } from '#/locales';
@@ -32,8 +33,15 @@ import Demo03GradeForm from './demo03-grade-form.vue';
const emit = defineEmits(['success']);
type Demo03StudentFormData = Omit<
Demo03StudentApi.Demo03Student,
'birthday'
> & {
birthday?: Dayjs | string;
};
const formRef = ref();
const formData = ref<Partial<Demo03StudentApi.Demo03Student>>({
const formData = ref<Partial<Demo03StudentFormData>>({
id: undefined,
name: undefined,
sex: undefined,
@@ -116,7 +124,10 @@ const [Modal, modalApi] = useVbenModal({
modalApi.unlock();
}
}
formData.value = data;
formData.value = {
...data,
birthday: data.birthday === undefined ? undefined : String(data.birthday),
};
},
});
</script>

View File

@@ -1,5 +1,6 @@
<script lang="ts" setup>
import type { Rule } from 'ant-design-vue/es/form';
import type { Dayjs } from 'dayjs';
import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal';
@@ -32,8 +33,15 @@ import Demo03GradeForm from './demo03-grade-form.vue';
const emit = defineEmits(['success']);
type Demo03StudentFormData = Omit<
Demo03StudentApi.Demo03Student,
'birthday'
> & {
birthday?: Dayjs | string;
};
const formRef = ref();
const formData = ref<Partial<Demo03StudentApi.Demo03Student>>({
const formData = ref<Partial<Demo03StudentFormData>>({
id: undefined,
name: undefined,
sex: undefined,
@@ -115,7 +123,10 @@ const [Modal, modalApi] = useVbenModal({
modalApi.unlock();
}
}
formData.value = data;
formData.value = {
...data,
birthday: data.birthday === undefined ? undefined : String(data.birthday),
};
},
});
</script>

View File

@@ -76,7 +76,7 @@ const isDeviceCondition = computed(() => {
* @param value 字段值
*/
function updateConditionField(field: any, value: any) {
(condition.value as any)[field] = value;
Object.assign(condition.value, { [field]: value });
emit('update:modelValue', condition.value);
}

View File

@@ -122,7 +122,7 @@ const timeValue2 = computed(() => {
* @param value 字段值
*/
function updateConditionField(field: any, value: any) {
(condition.value as any)[field] = value;
Object.assign(condition.value, { [field]: value });
}
/**

View File

@@ -111,7 +111,7 @@ const serviceConfig = computed(() => {
* @param value 字段值
*/
function updateConditionField(field: any, value: any) {
(condition.value as any)[field] = value;
Object.assign(condition.value, { [field]: value });
}
/**

View File

@@ -166,7 +166,7 @@ if (!props.isStructDataSpecs && !props.isParams) {
label="数据长度"
>
<Input
v-model:value="property.dataSpecs.length"
v-model:value="property.dataSpecs!.length"
class="!w-[255px]"
placeholder="请输入文本字节长度"
>

View File

@@ -67,8 +67,8 @@ async function handleExport() {
}
/** 获得每个 Tab 的数量 */
async function getTabCount() {
const res = await getTabsCount();
async function getTabCount(params?: Record<string, any>) {
const res = await getTabsCount(params ?? (await gridApi.formApi.getValues()));
for (const objName in res) {
const index = Number(objName);
if (tabsData.value[index]) {
@@ -160,12 +160,14 @@ const [Grid, gridApi] = useVbenVxeGrid({
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getSpuPage({
const result = await getSpuPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
tabType: tabType.value,
...formValues,
});
void getTabCount(formValues); // 跟随筛选刷新 tab 数量
return result;
},
},
},

View File

@@ -19,6 +19,10 @@ const expanded = ref(false); // 是否展开
function handleToggleFab() {
expanded.value = !expanded.value;
}
function handleActive() {
expanded.value = false;
}
</script>
<template>
<div
@@ -35,6 +39,7 @@ function handleToggleFab() {
v-for="(item, index) in property.list"
:key="index"
class="flex flex-col items-center"
@click="handleActive"
>
<Image :src="item.imgUrl" :width="28" :height="28" :preview="false">
<template #error>

View File

@@ -21,7 +21,9 @@ const spuList = ref<MallSpuApi.Spu[]>([]);
watch(
() => props.property.spuIds,
async () => {
spuList.value = await getSpuDetailList(props.property.spuIds);
spuList.value = props.property.spuIds.length > 0
? await getSpuDetailList(props.property.spuIds)
: [];
},
{
immediate: true,

View File

@@ -47,7 +47,7 @@ export function totalCountFormat(row: MallCouponTemplateApi.CouponTemplate) {
if (row.totalCount === -1) {
return '不限制';
}
return row.totalCount;
return `${row.totalCount}`;
}
/** 格式化【剩余数量】 */
@@ -55,7 +55,7 @@ export function remainedCountFormat(row: MallCouponTemplateApi.CouponTemplate) {
if (row.totalCount === -1) {
return '不限制';
}
return row.totalCount - row.takeCount;
return `${row.totalCount - row.takeCount}`;
}
/** 格式化【最低消费】 */

View File

@@ -205,14 +205,7 @@ export function useFormSchema(): VbenFormSchema[] {
values.productScope === PromotionProductScopeEnum.CATEGORY.scope &&
values.productScopeValues
) {
const categoryIds = values.productScopeValues;
// 单选时使用数组不能反显,取第一个元素
form.setFieldValue(
'productCategoryIds',
Array.isArray(categoryIds) && categoryIds.length > 0
? categoryIds[0]
: categoryIds,
);
form.setFieldValue('productCategoryIds', values.productScopeValues);
}
},
},
@@ -237,9 +230,12 @@ export function useFormSchema(): VbenFormSchema[] {
trigger(values, form) {
switch (values.productScope) {
case PromotionProductScopeEnum.CATEGORY.scope: {
const categoryIds = Array.isArray(values.productCategoryIds)
? values.productCategoryIds
: [values.productCategoryIds];
let categoryIds: number[] = [];
if (Array.isArray(values.productCategoryIds)) {
categoryIds = values.productCategoryIds;
} else if (values.productCategoryIds) {
categoryIds = [values.productCategoryIds];
}
form.setFieldValue('productScopeValues', categoryIds);
break;
}

View File

@@ -27,11 +27,18 @@ import RewardRule from './reward-rule.vue';
const emit = defineEmits(['success']);
const formData = ref<Partial<MallRewardActivityApi.RewardActivity>>({
const createDefaultFormData = (): Partial<MallRewardActivityApi.RewardActivity> => ({
conditionType: PromotionConditionTypeEnum.PRICE.type,
productScope: PromotionProductScopeEnum.ALL.scope,
productScopeValues: [],
productCategoryIds: [],
productSpuIds: [],
rules: [],
});
const formData = ref<Partial<MallRewardActivityApi.RewardActivity>>(
createDefaultFormData(),
);
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['满减送'])
@@ -106,17 +113,22 @@ const [Modal, modalApi] = useVbenModal({
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = {};
formData.value = createDefaultFormData();
return;
}
// 加载数据
const data = modalApi.getData<MallRewardActivityApi.RewardActivity>();
if (!data || !data.id) {
formData.value = createDefaultFormData();
await formApi.setValues(formData.value);
return;
}
modalApi.lock();
try {
const result = await getReward(data.id);
const result = {
...createDefaultFormData(),
...(await getReward(data.id)),
};
result.startAndEndTime = [
result.startTime ? String(result.startTime) : undefined,
result.endTime ? String(result.endTime) : undefined,

View File

@@ -63,7 +63,10 @@ const [Modal, modalApi] = useVbenModal({
modalApi.lock();
try {
// 设置到 values
await formApi.setValues(data);
await formApi.setValues({
id: data.id,
remark: data.remark || '',
});
} finally {
modalApi.unlock();
}

View File

@@ -28,8 +28,8 @@ const columns = [
minWidth: 130,
},
{
field: 'areaId',
title: '地区编码',
field: 'areaName',
title: '所在地区',
minWidth: 120,
},
{

View File

@@ -17,7 +17,7 @@ import { useBalanceFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref({
id: 0,
id: undefined as number | undefined,
nickname: '',
balance: '0',
changeBalance: 0,
@@ -48,7 +48,7 @@ const [Modal, modalApi] = useVbenModal({
const data = await formApi.getValues();
try {
await updateWalletBalance({
userId: data.id,
userId: data.id!,
balance: yuanToFen(data.changeBalance) * data.changeType,
});
// 关闭并提示

View File

@@ -20,7 +20,7 @@
"build:analyze": "pnpm vite build --mode analyze",
"dev": "pnpm vite --mode development",
"preview": "vite preview",
"#typecheck": "vue-tsc --noEmit --skipLibCheck"
"#typecheck": "cross-env NODE_OPTIONS=--max-old-space-size=8192 vue-tsc --noEmit --skipLibCheck --incremental --tsBuildInfoFile node_modules/.cache/vue-tsc/tsconfig.tsbuildinfo"
},
"imports": {
"#/*": "./src/*"

View File

@@ -740,22 +740,18 @@ async function initComponentAdapter() {
Rate,
RichEditor: withDefaultPlaceholder(VbenTiptap, 'input', {
imageUpload: {
upload: (file: any, onProgress: any) => {
return new Promise((resolve, reject) => {
uploadFileApi({
file,
onProgress({ percent }) {
onProgress?.(percent);
},
onSuccess(response) {
// 从响应中提取图片URL
resolve(response?.data?.url ?? response?.url ?? '');
},
onError() {
reject(new Error($t('ui.tiptap.upload.uploadFailed')));
},
upload: async (file: File, onProgress?: (percent: number) => void) => {
try {
const response = await uploadFileApi({ file }, (progressEvent) => {
const percent = progressEvent.total
? Math.round((progressEvent.loaded * 100) / progressEvent.total)
: 0;
onProgress?.(percent);
});
});
return response?.data?.url ?? response?.url ?? '';
} catch {
throw new Error($t('ui.tiptap.upload.uploadFailed'));
}
},
},
}),

View File

@@ -14,7 +14,7 @@ export namespace AiChatConversationApi {
temperature: number; // 温度参数
maxTokens: number; // 单条回复的最大 Token 数量
maxContexts: number; // 上下文的最大 Message 数量
createTime?: Date; // 创建时间
createTime: Date; // 创建时间
systemMessage?: string; // 角色设定
modelName?: string; // 模型名字
roleAvatar?: string; // 角色头像

View File

@@ -34,15 +34,15 @@ export namespace AiImageApi {
prompt: string; // 提示词
modelId: number; // 模型
style: string; // 图像生成的风格
width: string; // 图片宽度
height: string; // 图片高度
width: number; // 图片宽度
height: number; // 图片高度
options: object; // 绘制参数Map<String, String>
}
export interface ImageMidjourneyImagineReqVO {
prompt: string; // 提示词
modelId: number; // 模型
base64Array?: string[]; // size不能为空
base64Array: string[]; // 参考图 base64 列表
width: string; // 图片宽度
height: string; // 图片高度
version: string; // 版本

View File

@@ -12,7 +12,6 @@ export namespace BpmOALeaveApi {
startTime: number;
endTime: number;
createTime: Date;
startUserSelectAssignees?: Record<string, string[]>;
}
}

View File

@@ -84,7 +84,6 @@ export namespace BpmProcessInstanceApi {
reason: string;
signPicUrl: string;
status: number;
attachments?: string[];
}
/** 抄送流程实例 */

View File

@@ -11,15 +11,16 @@ export namespace CrmBusinessStatusApi {
deptNames?: string[];
creator?: string;
createTime?: Date;
statuses?: BusinessStatusType[];
statuses: BusinessStatusType[];
}
/** 商机状态信息 */
export interface BusinessStatusType {
id?: number;
name: string;
percent: number;
[x: string]: any;
percent?: number;
endStatus?: number;
key?: string;
}
}
@@ -43,7 +44,7 @@ export const DEFAULT_STATUSES = [
name: '无效',
percent: 0,
},
];
] satisfies CrmBusinessStatusApi.BusinessStatusType[];
/** 查询商机状态组列表 */
export function getBusinessStatusPage(params: PageParam) {

View File

@@ -12,6 +12,7 @@ export namespace CrmReceivableApi {
customerId?: number;
customerName?: string;
contractId?: number;
contractNo?: string;
contract?: Contract;
auditStatus: number;
processInstanceId: number;

View File

@@ -24,6 +24,18 @@ export namespace InfraCodegenApi {
parentMenuId: number;
}
/** 代码生成表保存请求 */
export interface CodegenTableSaveReqVO extends CodegenTable {
frontType?: null | number;
genPath?: string;
genType?: string;
masterTableId?: number;
subJoinColumnId?: number;
subJoinMany?: boolean;
treeParentColumnId?: number;
treeNameColumnId?: number;
}
/** 代码生成字段定义 */
export interface CodegenColumn {
id: number;
@@ -54,7 +66,7 @@ export namespace InfraCodegenApi {
/** 代码生成详情 */
export interface CodegenDetail {
table: CodegenTable;
table: CodegenTableSaveReqVO;
columns: CodegenColumn[];
}
@@ -66,7 +78,7 @@ export namespace InfraCodegenApi {
/** 更新代码生成请求 */
export interface CodegenUpdateReqVO {
table: any | CodegenTable;
table: CodegenTableSaveReqVO;
columns: CodegenColumn[];
}

View File

@@ -11,7 +11,7 @@ export namespace Demo02CategoryApi {
}
/** 查询示例分类列表 */
export function getDemo02CategoryList(params: any) {
export function getDemo02CategoryList(params?: any) {
return requestClient.get<Demo02CategoryApi.Demo02Category[]>(
'/infra/demo02-category/list',
{ params },

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
}
}

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
demo03courses?: Demo03Course[];
demo03grade?: Demo03Grade;

View File

@@ -1,5 +1,3 @@
import type { Dayjs } from 'dayjs';
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
@@ -7,7 +5,7 @@ import { requestClient } from '#/api/request';
export namespace Demo03StudentApi {
/** 学生课程信息 */
export interface Demo03Course {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
score?: number; // 分数
@@ -15,7 +13,7 @@ export namespace Demo03StudentApi {
/** 学生班级信息 */
export interface Demo03Grade {
id: number; // 编号
id?: number; // 编号
studentId?: number; // 学生编号
name?: string; // 名字
teacher?: string; // 班主任
@@ -23,10 +21,10 @@ export namespace Demo03StudentApi {
/** 学生信息 */
export interface Demo03Student {
id: number; // 编号
id?: number; // 编号
name?: string; // 名字
sex?: number; // 性别
birthday?: Dayjs | string; // 出生日期
birthday?: number | string; // 出生日期
description?: string; // 简介
demo03courses?: Demo03Course[];
demo03grade?: Demo03Grade;

View File

@@ -6,11 +6,11 @@ export namespace IoTOtaTaskApi {
/** IoT OTA 升级任务 */
export interface Task {
id?: number;
name?: string;
name: string;
description?: string;
firmwareId?: number;
status?: number;
deviceScope?: number;
deviceScope: number;
deviceIds?: number[];
deviceTotalCount?: number;
deviceSuccessCount?: number;

View File

@@ -32,8 +32,8 @@ export namespace ThingModelApi {
required?: boolean;
dataType?: string;
description?: string;
dataSpecs?: any;
dataSpecsList?: any[];
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
}
/** IoT 物模型服务 */
@@ -66,8 +66,8 @@ export namespace ThingModelApi {
direction?: string;
paraOrder?: number;
dataType?: string;
dataSpecs?: any;
dataSpecsList?: any[];
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
}
/** IoT 物模型 TSL树形响应 */
@@ -80,19 +80,35 @@ export namespace ThingModelApi {
}
/** IoT 数据定义(数值型) */
export interface DataSpecsNumberData {
export interface ThingModelDataSpecs {
accessMode?: string;
childDataType?: string;
dataSpecs?: ThingModelDataSpecs;
dataSpecsList?: ThingModelPropertyDataSpecs[];
dataType?: string;
defaultValue?: string;
description?: string;
identifier?: string;
length?: number | string;
min?: number | string;
max?: number | string;
name?: string;
precise?: string;
required?: boolean;
size?: number | string;
step?: number | string;
unit?: string;
unitName?: string;
value?: number | string;
}
/** IoT 数据定义(数值型) */
export type DataSpecsNumberData = ThingModelDataSpecs;
/** IoT 数据定义(枚举/布尔型) */
export interface DataSpecsEnumOrBoolData {
value: number | string;
name: string;
}
export type DataSpecsEnumOrBoolData = ThingModelDataSpecs;
export type ThingModelPropertyDataSpecs = Property & ThingModelDataSpecs;
}
/** 生成「必填 + 数字」类校验器:拼到 size / length / 枚举值上 */

View File

@@ -76,9 +76,9 @@ export function getSpuPage(params: PageParam) {
});
}
/** 获得商品 SPU 列表 tabsCount */
export function getTabsCount() {
return requestClient.get<Record<string, number>>('/product/spu/get-count');
/** 获得商品 SPU 列表 tabsCount(支持按 name/categoryId/createTime 筛选) */
export function getTabsCount(params?: Record<string, any>) {
return requestClient.get<Record<string, number>>('/product/spu/get-count', { params });
}
/** 创建商品 SPU */

View File

@@ -8,6 +8,7 @@ export namespace MallCombinationActivityApi {
id?: number; // 活动编号
name?: string; // 活动名称
spuId?: number; // 商品 SPU 编号
spuName?: string; // 商品 SPU 名称
totalLimitCount?: number; // 总限购数量
singleLimitCount?: number; // 单次限购数量
startTime?: Date; // 开始时间
@@ -21,7 +22,7 @@ export namespace MallCombinationActivityApi {
limitDuration?: number; // 限制时长
combinationPrice?: number; // 拼团价格
products: CombinationProduct[]; // 商品列表
picUrl?: any;
picUrl?: string; // 商品图片
}
/** 拼团活动所需属性 */

View File

@@ -26,9 +26,9 @@ export namespace MallRewardActivityApi {
conditionType?: number; // 条件类型
productScope?: number; // 商品范围
rules: RewardRule[]; // 优惠规则列表
productScopeValues?: number[]; // 商品范围值(仅表单使用):值为品类编号列表、商品编号列表
productCategoryIds?: number[]; // 商品分类编号列表(仅表单使用)
productSpuIds?: number[]; // 商品 SPU 编号列表(仅表单使用)
productScopeValues: number[]; // 商品范围值(仅表单使用):值为品类编号列表、商品编号列表
productCategoryIds: number[]; // 商品分类编号列表(仅表单使用)
productSpuIds: number[]; // 商品 SPU 编号列表(仅表单使用)
}
}

View File

@@ -31,7 +31,7 @@ export namespace MallSeckillActivityApi {
totalStock?: number; // 秒杀总库存
seckillPrice?: number; // 秒杀价格
products?: SeckillProduct[]; // 秒杀商品列表
picUrl?: any;
picUrl?: string; // 商品图片
}
}

View File

@@ -4,20 +4,21 @@ export namespace MallTradeConfigApi {
/** 交易中心配置 */
export interface Config {
id?: number;
afterSaleRefundReasons?: string[];
afterSaleReturnReasons?: string[];
deliveryExpressFreeEnabled?: boolean;
deliveryExpressFreePrice?: number;
deliveryPickUpEnabled?: boolean;
afterSaleRefundReasons: string[];
afterSaleReturnReasons: string[];
deliveryExpressFreeEnabled: boolean;
deliveryExpressFreePrice: number;
deliveryPickUpEnabled: boolean;
brokerageEnabled?: boolean;
brokerageEnabledCondition?: number;
brokerageBindMode?: number;
brokeragePosterUrls?: string;
brokeragePosterUrls: string[];
brokerageFirstPercent?: number;
brokerageSecondPercent?: number;
brokerageWithdrawMinPrice?: number;
brokerageFrozenDays?: number;
brokerageWithdrawTypes?: string;
brokerageWithdrawMinPrice: number;
brokerageFrozenDays: number;
brokerageWithdrawFeePercent: number;
brokerageWithdrawTypes: number[];
tencentLbsKey?: string;
}
}

View File

@@ -7,6 +7,7 @@ export namespace MemberAddressApi {
name: string;
mobile: string;
areaId: number;
areaName?: string;
detailAddress: string;
defaultStatus: boolean;
}

View File

@@ -4,7 +4,7 @@ export namespace MemberConfigApi {
/** 积分设置信息 */
export interface Config {
id?: number;
pointTradeDeductEnable: number;
pointTradeDeductEnable: boolean;
pointTradeDeductUnitPrice: number;
pointTradeDeductMaxPrice: number;
pointTradeGivePoint: number;

View File

@@ -10,27 +10,31 @@ export namespace MemberUserApi {
birthday?: number;
createTime?: number;
loginDate?: number;
loginIp: string;
mark: string;
mobile: string;
loginIp?: string;
mark?: string;
mobile?: string;
email?: string;
name?: string;
nickname?: string;
registerIp: string;
sex: number;
status: number;
registerIp?: string;
sex?: number;
status?: number;
areaId?: number;
areaName?: string;
levelName: string;
point?: number;
totalPoint?: number;
experience?: number;
tagIds?: number[];
groupId?: number;
levelId?: number;
levelName?: null | string;
point?: null | number;
totalPoint?: null | number;
experience?: null | number;
}
/** 会员用户等级更新信息 */
export interface UserUpdateLevelReqVO {
id: number;
levelId: number;
reason: string;
}
/** 会员用户积分更新信息 */

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