commit
ba7662cb8b
|
|
@ -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/*"
|
||||
|
|
|
|||
|
|
@ -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; // 角色头像
|
||||
|
|
|
|||
|
|
@ -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; // 版本
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export namespace BpmOALeaveApi {
|
|||
startTime: number;
|
||||
endTime: number;
|
||||
createTime: Date;
|
||||
startUserSelectAssignees?: Record<string, string[]>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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; // 简介
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 / 枚举值上 */
|
||||
|
|
|
|||
|
|
@ -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; // 商品图片
|
||||
}
|
||||
|
||||
/** 拼团活动所需属性 */
|
||||
|
|
|
|||
|
|
@ -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 编号列表(仅表单使用)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export namespace MallSeckillActivityApi {
|
|||
totalStock?: number; // 秒杀总库存
|
||||
seckillPrice?: number; // 秒杀价格
|
||||
products?: SeckillProduct[]; // 秒杀商品列表
|
||||
picUrl?: any;
|
||||
picUrl?: string; // 商品图片
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export namespace MemberConfigApi {
|
|||
/** 积分设置信息 */
|
||||
export interface Config {
|
||||
id?: number;
|
||||
pointTradeDeductEnable: number;
|
||||
pointTradeDeductEnable: boolean;
|
||||
pointTradeDeductUnitPrice: number;
|
||||
pointTradeDeductMaxPrice: number;
|
||||
pointTradeGivePoint: number;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** 会员用户积分更新信息 */
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
||||
/** 同步公众号标签 */
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
}
|
||||
|
||||
/** 获得支付通知分页 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 没有任何对话情况
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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, // 图像生成的风格
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** 获取请假数据,用于重新发起时自动填充 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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 }">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
// 设置表单值
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ function handleRowCheckboxChange({
|
|||
}: {
|
||||
records: Demo03StudentApi.Demo03Student[];
|
||||
}) {
|
||||
checkedIds.value = records.map((item) => item.id)!;
|
||||
checkedIds.value = records.map((item) => item.id!);
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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="请输入文本字节长度"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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}`;
|
||||
}
|
||||
|
||||
/** 格式化【最低消费】 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
// 关闭并提示
|
||||
|
|
|
|||
|
|
@ -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/*"
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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; // 角色头像
|
||||
|
|
|
|||
|
|
@ -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; // 版本
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ export namespace BpmOALeaveApi {
|
|||
startTime: number;
|
||||
endTime: number;
|
||||
createTime: Date;
|
||||
startUserSelectAssignees?: Record<string, string[]>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ export namespace BpmProcessInstanceApi {
|
|||
reason: string;
|
||||
signPicUrl: string;
|
||||
status: number;
|
||||
attachments?: string[];
|
||||
}
|
||||
|
||||
/** 抄送流程实例 */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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; // 简介
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 / 枚举值上 */
|
||||
|
|
|
|||
|
|
@ -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; // 商品图片
|
||||
}
|
||||
|
||||
/** 拼团活动所需属性 */
|
||||
|
|
|
|||
|
|
@ -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 编号列表(仅表单使用)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export namespace MallSeckillActivityApi {
|
|||
totalStock?: number; // 秒杀总库存
|
||||
seckillPrice?: number; // 秒杀价格
|
||||
products?: SeckillProduct[]; // 秒杀商品列表
|
||||
picUrl?: any;
|
||||
picUrl?: string; // 商品图片
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ export namespace MemberConfigApi {
|
|||
/** 积分设置信息 */
|
||||
export interface Config {
|
||||
id?: number;
|
||||
pointTradeDeductEnable: number;
|
||||
pointTradeDeductEnable: boolean;
|
||||
pointTradeDeductUnitPrice: number;
|
||||
pointTradeDeductMaxPrice: number;
|
||||
pointTradeGivePoint: number;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** 会员用户积分更新信息 */
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
||||
/** 同步公众号标签 */
|
||||
|
|
|
|||
|
|
@ -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}`);
|
||||
}
|
||||
|
||||
/** 获得支付通知分页 */
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ export function useDescription(options?: Partial<DescriptionProps>) {
|
|||
inheritAttrs: false,
|
||||
setup(_props, { attrs, slots }) {
|
||||
return () => {
|
||||
// @ts-expect-error - 避免类型实例化过深
|
||||
return h(Description, { ...propsState, ...attrs }, slots);
|
||||
};
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface PopConfirm {
|
|||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ActionItem extends ButtonProps {
|
||||
export interface ActionItem extends Omit<ButtonProps, 'color'> {
|
||||
onClick?: () => void;
|
||||
type?: ButtonType;
|
||||
label?: string;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const getButtonProps = computed(() => {
|
|||
};
|
||||
});
|
||||
|
||||
async function customRequest(info: UploadRequestOption<any>) {
|
||||
async function customRequest(info: UploadRequestOption) {
|
||||
// 1. emit 上传中
|
||||
const file = info.file as File;
|
||||
const name = file?.name;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 没有任何对话情况
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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, // 图像生成的风格
|
||||
},
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ async function handleGenerateImage() {
|
|||
const req = {
|
||||
prompt: prompt.value,
|
||||
modelId: matchedModel.id,
|
||||
base64Array: [],
|
||||
width: imageSize.width,
|
||||
height: imageSize.height,
|
||||
version: selectVersion.value,
|
||||
|
|
|
|||
|
|
@ -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 'antdv-next';
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 'antdv-next';
|
|||
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>
|
||||
|
|
|
|||
|
|
@ -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 'antdv-next';
|
||||
|
||||
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');
|
||||
|
|
|
|||
|
|
@ -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 'antdv-next';
|
||||
|
||||
import { currentSongKey } from '../types';
|
||||
|
||||
defineOptions({ name: 'AiMusicSongInfoIndex' });
|
||||
|
||||
const currentSong = inject<any>('currentSong', {});
|
||||
const currentSong = inject(currentSongKey, ref<MusicSong>({}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -48,6 +48,25 @@ const dialogVisible = ref(false); // 弹窗可见性
|
|||
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;
|
||||
|
||||
const approvalColumns = computed<TableColumnType[]>(() => {
|
||||
const userColumn: TableColumnType =
|
||||
selectActivityType.value === 'bpmn:UserTask'
|
||||
|
|
@ -126,7 +145,7 @@ const approvalColumns = computed<TableColumnType[]>(() => {
|
|||
/** Zoom:恢复 */
|
||||
const processReZoom = () => {
|
||||
defaultZoom.value = 1;
|
||||
bpmnViewer.value?.get('canvas').zoom('fit-viewport', 'auto');
|
||||
getCanvas()?.zoom('fit-viewport', 'auto');
|
||||
};
|
||||
|
||||
let resizeObserver: null | ResizeObserver = null;
|
||||
|
|
@ -173,7 +192,7 @@ const processZoomIn = (zoomStep = 0.1) => {
|
|||
);
|
||||
}
|
||||
defaultZoom.value = newZoom;
|
||||
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
|
||||
getCanvas()?.zoom(defaultZoom.value);
|
||||
};
|
||||
|
||||
/** Zoom:缩小 */
|
||||
|
|
@ -185,7 +204,7 @@ const processZoomOut = (zoomStep = 0.1) => {
|
|||
);
|
||||
}
|
||||
defaultZoom.value = newZoom;
|
||||
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value);
|
||||
getCanvas()?.zoom(defaultZoom.value);
|
||||
};
|
||||
|
||||
/** 流程图预览清空 */
|
||||
|
|
@ -206,9 +225,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);
|
||||
};
|
||||
|
||||
/** 节点选中 */
|
||||
|
|
@ -304,8 +323,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)) {
|
||||
|
|
@ -313,7 +335,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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ watch(
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<Divider orientation="left">审批人超时未处理时</Divider>
|
||||
<Divider title-placement="left">审批人超时未处理时</Divider>
|
||||
<FormItem label="启用开关" name="timeoutHandlerEnable">
|
||||
<Switch
|
||||
v-model:checked="timeoutHandlerEnable"
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ onMounted(async () => {
|
|||
|
||||
<template>
|
||||
<div>
|
||||
<Divider orientation="left">审批类型</Divider>
|
||||
<Divider title-placement="left">审批类型</Divider>
|
||||
<FormItem name="approveType" label="审批类型">
|
||||
<RadioGroup v-model:value="approveType.value">
|
||||
<Radio
|
||||
|
|
@ -460,7 +460,7 @@ onMounted(async () => {
|
|||
</RadioGroup>
|
||||
</FormItem>
|
||||
|
||||
<Divider orientation="left">审批人拒绝时</Divider>
|
||||
<Divider title-placement="left">审批人拒绝时</Divider>
|
||||
<FormItem name="rejectHandlerType" label="处理方式">
|
||||
<RadioGroup
|
||||
v-model:value="rejectHandlerType"
|
||||
|
|
@ -492,7 +492,7 @@ onMounted(async () => {
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<Divider orientation="left">审批人为空时</Divider>
|
||||
<Divider title-placement="left">审批人为空时</Divider>
|
||||
<FormItem name="assignEmptyHandlerType">
|
||||
<RadioGroup
|
||||
v-model:value="assignEmptyHandlerType"
|
||||
|
|
@ -523,7 +523,7 @@ onMounted(async () => {
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<Divider orientation="left">审批人与提交人为同一人时</Divider>
|
||||
<Divider title-placement="left">审批人与提交人为同一人时</Divider>
|
||||
<RadioGroup
|
||||
v-model:value="assignStartUserHandlerType"
|
||||
@change="updateAssignStartUserHandlerType"
|
||||
|
|
@ -540,7 +540,7 @@ onMounted(async () => {
|
|||
</div>
|
||||
</RadioGroup>
|
||||
|
||||
<Divider orientation="left">操作按钮</Divider>
|
||||
<Divider title-placement="left">操作按钮</Divider>
|
||||
<div class="mt-2 text-sm">
|
||||
<!-- 头部标题行 -->
|
||||
<div
|
||||
|
|
@ -587,7 +587,7 @@ onMounted(async () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<Divider orientation="left">字段权限</Divider>
|
||||
<Divider title-placement="left">字段权限</Divider>
|
||||
<div v-if="formType === BpmModelFormType.NORMAL" class="mt-2 text-sm">
|
||||
<!-- 头部标题行 -->
|
||||
<div
|
||||
|
|
@ -663,7 +663,7 @@ onMounted(async () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<Divider orientation="left">是否需要签名</Divider>
|
||||
<Divider title-placement="left">是否需要签名</Divider>
|
||||
<FormItem name="signEnable">
|
||||
<Switch
|
||||
v-model:checked="signEnable.value"
|
||||
|
|
@ -673,7 +673,7 @@ onMounted(async () => {
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<Divider orientation="left">审批意见</Divider>
|
||||
<Divider title-placement="left">审批意见</Divider>
|
||||
<FormItem name="reasonRequire">
|
||||
<Switch
|
||||
v-model:checked="reasonRequire.value"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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[]>([]);
|
||||
|
||||
/** 保存配置 */
|
||||
|
|
@ -781,7 +787,7 @@ onMounted(async () => {
|
|||
]"
|
||||
>
|
||||
<InputNumber
|
||||
v-model:value="configForm.multiInstanceSource"
|
||||
v-model:value="multiInstanceSourceNumber"
|
||||
:min="1"
|
||||
/>
|
||||
</FormItem>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ defineExpose({ validate });
|
|||
:key="listenerIdx"
|
||||
class="pl-2"
|
||||
>
|
||||
<Divider orientation="left">
|
||||
<Divider title-placement="left">
|
||||
<TypographyText tag="b" size="large">
|
||||
{{ listener.name }}
|
||||
</TypographyText>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue