fix: 合并冲突
parent
241c70ebb0
commit
d29e53ff15
|
|
@ -4,7 +4,8 @@
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"codeLogin": "Code Login",
|
"codeLogin": "Code Login",
|
||||||
"qrcodeLogin": "Qr Code Login",
|
"qrcodeLogin": "Qr Code Login",
|
||||||
"forgetPassword": "Forget Password"
|
"forgetPassword": "Forget Password",
|
||||||
|
"profile": "Profile"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"title": "Dashboard",
|
"title": "Dashboard",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
"register": "注册",
|
"register": "注册",
|
||||||
"codeLogin": "验证码登录",
|
"codeLogin": "验证码登录",
|
||||||
"qrcodeLogin": "二维码登录",
|
"qrcodeLogin": "二维码登录",
|
||||||
"forgetPassword": "忘记密码"
|
"forgetPassword": "忘记密码",
|
||||||
|
"profile": "个人中心"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"title": "概览",
|
"title": "概览",
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ export const useMallKefuStore = defineStore('mall-kefu', {
|
||||||
},
|
},
|
||||||
conversationSort() {
|
conversationSort() {
|
||||||
// 按置顶属性和最后消息时间排序
|
// 按置顶属性和最后消息时间排序
|
||||||
this.conversationList.sort((a, b) => {
|
this.conversationList.toSorted((a, b) => {
|
||||||
// 按照置顶排序,置顶的会在前面
|
// 按照置顶排序,置顶的会在前面
|
||||||
if (a.adminPinned !== b.adminPinned) {
|
if (a.adminPinned !== b.adminPinned) {
|
||||||
return a.adminPinned ? -1 : 1;
|
return a.adminPinned ? -1 : 1;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Recordable } from '@vben/types';
|
||||||
|
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
import type { SystemUserProfileApi } from '#/api/system/user/profile';
|
||||||
|
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileBaseSetting, z } from '@vben/common-ui';
|
||||||
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
import { getDictOptions } from '@vben/hooks';
|
||||||
|
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { updateUserProfile } from '#/api/system/user/profile';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
profile?: SystemUserProfileApi.UserProfileRespVO;
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'success'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const profileBaseSettingRef = ref();
|
||||||
|
|
||||||
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '用户昵称',
|
||||||
|
fieldName: 'nickname',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户昵称',
|
||||||
|
},
|
||||||
|
rules: 'required',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户手机',
|
||||||
|
fieldName: 'mobile',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户手机',
|
||||||
|
},
|
||||||
|
rules: z.string(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户邮箱',
|
||||||
|
fieldName: 'email',
|
||||||
|
component: 'Input',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户邮箱',
|
||||||
|
},
|
||||||
|
rules: z.string().email('请输入正确的邮箱'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户性别',
|
||||||
|
fieldName: 'sex',
|
||||||
|
component: 'RadioGroup',
|
||||||
|
componentProps: {
|
||||||
|
options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'),
|
||||||
|
buttonStyle: 'solid',
|
||||||
|
optionType: 'button',
|
||||||
|
},
|
||||||
|
rules: z.number(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleSubmit(values: Recordable<any>) {
|
||||||
|
try {
|
||||||
|
profileBaseSettingRef.value.getFormApi().setLoading(true);
|
||||||
|
// 提交表单
|
||||||
|
await updateUserProfile(values as SystemUserProfileApi.UpdateProfileReqVO);
|
||||||
|
// 关闭并提示
|
||||||
|
emit('success');
|
||||||
|
message.success($t('ui.actionMessage.operationSuccess'));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
profileBaseSettingRef.value.getFormApi().setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 监听 profile 变化 */
|
||||||
|
watch(
|
||||||
|
() => props.profile,
|
||||||
|
(newProfile) => {
|
||||||
|
if (newProfile) {
|
||||||
|
profileBaseSettingRef.value.getFormApi().setValues(newProfile);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileBaseSetting
|
||||||
|
ref="profileBaseSettingRef"
|
||||||
|
:form-schema="formSchema"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileNotificationSetting } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const formSchema = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'accountPassword',
|
||||||
|
label: '账户密码',
|
||||||
|
description: '其他用户的消息将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'systemMessage',
|
||||||
|
label: '系统消息',
|
||||||
|
description: '系统消息将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'todoTask',
|
||||||
|
label: '待办任务',
|
||||||
|
description: '待办任务将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileNotificationSetting :form-schema="formSchema" />
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
import { ProfilePasswordSetting, z } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const profilePasswordSettingRef = ref();
|
||||||
|
|
||||||
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'oldPassword',
|
||||||
|
label: '旧密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入旧密码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'newPassword',
|
||||||
|
label: '新密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
passwordStrength: true,
|
||||||
|
placeholder: '请输入新密码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'confirmPassword',
|
||||||
|
label: '确认密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
passwordStrength: true,
|
||||||
|
placeholder: '请再次输入新密码',
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
rules(values) {
|
||||||
|
const { newPassword } = values;
|
||||||
|
return z
|
||||||
|
.string({ required_error: '请再次输入新密码' })
|
||||||
|
.min(1, { message: '请再次输入新密码' })
|
||||||
|
.refine((value) => value === newPassword, {
|
||||||
|
message: '两次输入的密码不一致',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
triggerFields: ['newPassword'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
message.success('密码修改成功');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfilePasswordSetting
|
||||||
|
ref="profilePasswordSettingRef"
|
||||||
|
class="w-1/3"
|
||||||
|
:form-schema="formSchema"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileSecuritySetting } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const formSchema = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'accountPassword',
|
||||||
|
label: '账户密码',
|
||||||
|
description: '当前密码强度:强',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityPhone',
|
||||||
|
label: '密保手机',
|
||||||
|
description: '已绑定手机:138****8293',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityQuestion',
|
||||||
|
label: '密保问题',
|
||||||
|
description: '未设置密保问题,密保问题可有效保护账户安全',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityEmail',
|
||||||
|
label: '备用邮箱',
|
||||||
|
description: '已绑定邮箱:ant***sign.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
fieldName: 'securityMfa',
|
||||||
|
label: 'MFA 设备',
|
||||||
|
description: '未绑定 MFA 设备,绑定后,可以进行二次确认',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileSecuritySetting :form-schema="formSchema" />
|
||||||
|
</template>
|
||||||
|
|
@ -403,8 +403,8 @@ async function doSendMessageStream(userMessage: AiChatMessageApi.ChatMessage) {
|
||||||
const lastMessage =
|
const lastMessage =
|
||||||
activeMessageList.value[activeMessageList.value.length - 1];
|
activeMessageList.value[activeMessageList.value.length - 1];
|
||||||
// 累加推理内容
|
// 累加推理内容
|
||||||
lastMessage.reasoningContent =
|
lastMessage!.reasoningContent =
|
||||||
(lastMessage.reasoningContent || '') +
|
(lastMessage!.reasoningContent || '') +
|
||||||
data.receive.reasoningContent;
|
data.receive.reasoningContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -554,7 +554,7 @@ onMounted(async () => {
|
||||||
<!-- 右侧:详情部分 -->
|
<!-- 右侧:详情部分 -->
|
||||||
<Layout class="bg-card mx-4">
|
<Layout class="bg-card mx-4">
|
||||||
<Layout.Header
|
<Layout.Header
|
||||||
class="!bg-card border-border flex !h-12 items-center justify-between border-b !px-4"
|
class="border-border !bg-card flex !h-12 items-center justify-between border-b !px-4"
|
||||||
>
|
>
|
||||||
<div class="text-lg font-bold">
|
<div class="text-lg font-bold">
|
||||||
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ async function getChatConversationList() {
|
||||||
// 1.1 获取 对话数据
|
// 1.1 获取 对话数据
|
||||||
conversationList.value = await getChatConversationMyList();
|
conversationList.value = await getChatConversationMyList();
|
||||||
// 1.2 排序
|
// 1.2 排序
|
||||||
conversationList.value.sort((a, b) => {
|
conversationList.value.toSorted((a, b) => {
|
||||||
return Number(b.createTime) - Number(a.createTime);
|
return Number(b.createTime) - Number(a.createTime);
|
||||||
});
|
});
|
||||||
// 1.3 没有任何对话情况
|
// 1.3 没有任何对话情况
|
||||||
|
|
|
||||||
|
|
@ -138,14 +138,14 @@ async function uploadFile(fileItem: FileItem) {
|
||||||
fileItem.progress = 100;
|
fileItem.progress = 100;
|
||||||
|
|
||||||
// 调试日志
|
// 调试日志
|
||||||
console.log('上传响应:', response);
|
console.warn('上传响应:', response);
|
||||||
|
|
||||||
// 兼容不同的返回格式:{ url: '...' } 或 { data: '...' } 或直接是字符串
|
// 兼容不同的返回格式:{ url: '...' } 或 { data: '...' } 或直接是字符串
|
||||||
const fileUrl =
|
const fileUrl =
|
||||||
(response as any)?.url || (response as any)?.data || response;
|
(response as any)?.url || (response as any)?.data || response;
|
||||||
fileItem.url = fileUrl;
|
fileItem.url = fileUrl;
|
||||||
|
|
||||||
console.log('提取的文件 URL:', fileUrl);
|
console.warn('提取的文件 URL:', fileUrl);
|
||||||
|
|
||||||
// 只有当 URL 有效时才添加到列表
|
// 只有当 URL 有效时才添加到列表
|
||||||
if (fileUrl && typeof fileUrl === 'string') {
|
if (fileUrl && typeof fileUrl === 'string') {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import {
|
||||||
getChatRole,
|
getChatRole,
|
||||||
updateChatRole,
|
updateChatRole,
|
||||||
} from '#/api/ai/model/chatRole';
|
} from '#/api/ai/model/chatRole';
|
||||||
import {} from '#/api/bpm/model';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import { createModel, getModel, updateModel } from '#/api/ai/model/model';
|
import { createModel, getModel, updateModel } from '#/api/ai/model/model';
|
||||||
import {} from '#/api/bpm/model';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const currentSong = ref({}); // 当前音乐
|
||||||
const mySongList = ref<Recordable<any>[]>([]);
|
const mySongList = ref<Recordable<any>[]>([]);
|
||||||
const squareSongList = ref<Recordable<any>[]>([]);
|
const squareSongList = ref<Recordable<any>[]>([]);
|
||||||
|
|
||||||
function generateMusic(formData: Recordable<any>) {
|
function generateMusic(_formData: Recordable<any>) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mySongList.value = Array.from({ length: 20 }, (_, index) => {
|
mySongList.value = Array.from({ length: 20 }, (_, index) => {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const emits = defineEmits<{
|
||||||
<span
|
<span
|
||||||
v-for="tag in props.tags"
|
v-for="tag in props.tags"
|
||||||
:key="tag.value"
|
:key="tag.value"
|
||||||
class="bg-card border-card-100 mb-2 cursor-pointer rounded border-2 border-solid px-1 text-xs leading-6"
|
class="border-card-100 bg-card mb-2 cursor-pointer rounded border-2 border-solid px-1 text-xs leading-6"
|
||||||
:class="
|
:class="
|
||||||
modelValue === tag.value && '!border-primary-500 !text-primary-500'
|
modelValue === tag.value && '!border-primary-500 !text-primary-500'
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -62,16 +62,16 @@ const resetElement = () => {
|
||||||
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
|
|
||||||
// 是否开启自定义用户任务超时处理
|
// 是否开启自定义用户任务超时处理
|
||||||
boundaryEventType.value = elExtensionElements.value.values?.filter(
|
boundaryEventType.value = elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:BoundaryEventType`,
|
(ex: any) => ex.$type === `${prefix}:BoundaryEventType`,
|
||||||
)?.[0];
|
);
|
||||||
if (boundaryEventType.value && boundaryEventType.value.value === 1) {
|
if (boundaryEventType.value && boundaryEventType.value.value === 1) {
|
||||||
timeoutHandlerEnable.value = true;
|
timeoutHandlerEnable.value = true;
|
||||||
configExtensions.value.push(boundaryEventType.value);
|
configExtensions.value.push(boundaryEventType.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行动作
|
// 执行动作
|
||||||
timeoutHandlerType.value = elExtensionElements.value.values?.filter(
|
timeoutHandlerType.value = elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:TimeoutHandlerType`,
|
(ex: any) => ex.$type === `${prefix}:TimeoutHandlerType`,
|
||||||
)?.[0];
|
)?.[0];
|
||||||
if (timeoutHandlerType.value) {
|
if (timeoutHandlerType.value) {
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 审批类型
|
// 审批类型
|
||||||
approveType.value =
|
approveType.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:ApproveType`,
|
(ex: any) => ex.$type === `${prefix}:ApproveType`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:ApproveType`, {
|
bpmnInstances().moddle.create(`${prefix}:ApproveType`, {
|
||||||
|
|
@ -121,7 +121,7 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 审批人与提交人为同一人时
|
// 审批人与提交人为同一人时
|
||||||
assignStartUserHandlerTypeEl.value =
|
assignStartUserHandlerTypeEl.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:AssignStartUserHandlerType`,
|
(ex: any) => ex.$type === `${prefix}:AssignStartUserHandlerType`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:AssignStartUserHandlerType`, {
|
bpmnInstances().moddle.create(`${prefix}:AssignStartUserHandlerType`, {
|
||||||
|
|
@ -131,13 +131,13 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 审批人拒绝时
|
// 审批人拒绝时
|
||||||
rejectHandlerTypeEl.value =
|
rejectHandlerTypeEl.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:RejectHandlerType`,
|
(ex: any) => ex.$type === `${prefix}:RejectHandlerType`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:RejectHandlerType`, { value: 1 });
|
bpmnInstances().moddle.create(`${prefix}:RejectHandlerType`, { value: 1 });
|
||||||
rejectHandlerType.value = rejectHandlerTypeEl.value.value;
|
rejectHandlerType.value = rejectHandlerTypeEl.value.value;
|
||||||
returnNodeIdEl.value =
|
returnNodeIdEl.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:RejectReturnTaskId`,
|
(ex: any) => ex.$type === `${prefix}:RejectReturnTaskId`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:RejectReturnTaskId`, {
|
bpmnInstances().moddle.create(`${prefix}:RejectReturnTaskId`, {
|
||||||
|
|
@ -147,7 +147,7 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 审批人为空时
|
// 审批人为空时
|
||||||
assignEmptyHandlerTypeEl.value =
|
assignEmptyHandlerTypeEl.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:AssignEmptyHandlerType`,
|
(ex: any) => ex.$type === `${prefix}:AssignEmptyHandlerType`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:AssignEmptyHandlerType`, {
|
bpmnInstances().moddle.create(`${prefix}:AssignEmptyHandlerType`, {
|
||||||
|
|
@ -155,7 +155,7 @@ const resetCustomConfigList = () => {
|
||||||
});
|
});
|
||||||
assignEmptyHandlerType.value = assignEmptyHandlerTypeEl.value.value;
|
assignEmptyHandlerType.value = assignEmptyHandlerTypeEl.value.value;
|
||||||
assignEmptyUserIdsEl.value =
|
assignEmptyUserIdsEl.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:AssignEmptyUserIds`,
|
(ex: any) => ex.$type === `${prefix}:AssignEmptyUserIds`,
|
||||||
)?.[0] ||
|
)?.[0] ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:AssignEmptyUserIds`, {
|
bpmnInstances().moddle.create(`${prefix}:AssignEmptyUserIds`, {
|
||||||
|
|
@ -172,7 +172,7 @@ const resetCustomConfigList = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 操作按钮
|
// 操作按钮
|
||||||
buttonsSettingEl.value = elExtensionElements.value.values?.filter(
|
buttonsSettingEl.value = elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:ButtonsSetting`,
|
(ex: any) => ex.$type === `${prefix}:ButtonsSetting`,
|
||||||
);
|
);
|
||||||
if (buttonsSettingEl.value.length === 0) {
|
if (buttonsSettingEl.value.length === 0) {
|
||||||
|
|
@ -189,7 +189,7 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 字段权限
|
// 字段权限
|
||||||
if (formType.value === BpmModelFormType.NORMAL) {
|
if (formType.value === BpmModelFormType.NORMAL) {
|
||||||
const fieldsPermissionList = elExtensionElements.value.values?.filter(
|
const fieldsPermissionList = elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:FieldsPermission`,
|
(ex: any) => ex.$type === `${prefix}:FieldsPermission`,
|
||||||
);
|
);
|
||||||
fieldsPermissionEl.value = [];
|
fieldsPermissionEl.value = [];
|
||||||
|
|
@ -206,21 +206,21 @@ const resetCustomConfigList = () => {
|
||||||
|
|
||||||
// 是否需要签名
|
// 是否需要签名
|
||||||
signEnable.value =
|
signEnable.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:SignEnable`,
|
(ex: any) => ex.$type === `${prefix}:SignEnable`,
|
||||||
)?.[0] ||
|
) ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:SignEnable`, { value: false });
|
bpmnInstances().moddle.create(`${prefix}:SignEnable`, { value: false });
|
||||||
|
|
||||||
// 审批意见
|
// 审批意见
|
||||||
reasonRequire.value =
|
reasonRequire.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:ReasonRequire`,
|
(ex: any) => ex.$type === `${prefix}:ReasonRequire`,
|
||||||
)?.[0] ||
|
) ||
|
||||||
bpmnInstances().moddle.create(`${prefix}:ReasonRequire`, { value: false });
|
bpmnInstances().moddle.create(`${prefix}:ReasonRequire`, { value: false });
|
||||||
|
|
||||||
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
// 保留剩余扩展元素,便于后面更新该元素对应属性
|
||||||
otherExtensions.value =
|
otherExtensions.value =
|
||||||
elExtensionElements.value.values?.filter(
|
elExtensionElements.value.values?.find(
|
||||||
(ex: any) =>
|
(ex: any) =>
|
||||||
ex.$type !== `${prefix}:AssignStartUserHandlerType` &&
|
ex.$type !== `${prefix}:AssignStartUserHandlerType` &&
|
||||||
ex.$type !== `${prefix}:RejectHandlerType` &&
|
ex.$type !== `${prefix}:RejectHandlerType` &&
|
||||||
|
|
|
||||||
|
|
@ -118,10 +118,10 @@ const resetTaskForm = () => {
|
||||||
const extensionElements =
|
const extensionElements =
|
||||||
businessObject?.extensionElements ??
|
businessObject?.extensionElements ??
|
||||||
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] });
|
||||||
userTaskForm.value.candidateStrategy = extensionElements.values?.filter(
|
userTaskForm.value.candidateStrategy = extensionElements.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:CandidateStrategy`,
|
(ex: any) => ex.$type === `${prefix}:CandidateStrategy`,
|
||||||
)?.[0]?.value;
|
)?.[0]?.value;
|
||||||
const candidateParamStr = extensionElements.values?.filter(
|
const candidateParamStr = extensionElements.values?.find(
|
||||||
(ex: any) => ex.$type === `${prefix}:CandidateParam`,
|
(ex: any) => ex.$type === `${prefix}:CandidateParam`,
|
||||||
)?.[0]?.value;
|
)?.[0]?.value;
|
||||||
if (candidateParamStr && candidateParamStr.length > 0) {
|
if (candidateParamStr && candidateParamStr.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ function setDuration(type, val) {
|
||||||
// 组装ISO 8601字符串
|
// 组装ISO 8601字符串
|
||||||
let d = isoDuration.value;
|
let d = isoDuration.value;
|
||||||
if (d.includes(type)) {
|
if (d.includes(type)) {
|
||||||
d = d.replace(new RegExp(`\\d+${type}`), val + type);
|
d = d.replace(new RegExp(String.raw`\d+${type}`), val + type);
|
||||||
} else {
|
} else {
|
||||||
d += val + type;
|
d += val + type;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,12 @@ export function updateElementExtensions(element, extensionList) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建一个id
|
// 创建一个id
|
||||||
export function uuid(length = 8, chars?) {
|
export function uuid(
|
||||||
|
length = 8,
|
||||||
|
charsString = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||||
|
) {
|
||||||
let result = '';
|
let result = '';
|
||||||
const charsString =
|
|
||||||
chars || '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
||||||
for (let i = length; i > 0; --i) {
|
for (let i = length; i > 0; --i) {
|
||||||
result += charsString[Math.floor(Math.random() * charsString.length)];
|
result += charsString[Math.floor(Math.random() * charsString.length)];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -54,7 +54,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -102,7 +102,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -150,7 +150,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -198,7 +198,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -246,7 +246,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -294,7 +294,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -342,7 +342,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ onMounted(() => {
|
||||||
{ name: '定制', value: 310 },
|
{ name: '定制', value: 310 },
|
||||||
{ name: '技术支持', value: 274 },
|
{ name: '技术支持', value: 274 },
|
||||||
{ name: '远程', value: 400 },
|
{ name: '远程', value: 400 },
|
||||||
].sort((a, b) => {
|
].toSorted((a, b) => {
|
||||||
return a.value - b.value;
|
return a.value - b.value;
|
||||||
}),
|
}),
|
||||||
name: '商业占比',
|
name: '商业占比',
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ function handleOpenSaleOut() {
|
||||||
|
|
||||||
function handleAddSaleOut(rows: ErpSaleOutApi.SaleOut[]) {
|
function handleAddSaleOut(rows: ErpSaleOutApi.SaleOut[]) {
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
|
// TODO 芋艿
|
||||||
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
||||||
bizId: row.id,
|
bizId: row.id,
|
||||||
bizType: ErpBizType.SALE_OUT,
|
bizType: ErpBizType.SALE_OUT,
|
||||||
|
|
@ -153,6 +154,7 @@ function handleOpenSaleReturn() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddSaleReturn(rows: ErpSaleReturnApi.SaleReturn[]) {
|
function handleAddSaleReturn(rows: ErpSaleReturnApi.SaleReturn[]) {
|
||||||
|
// TODO 芋艿
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
||||||
bizId: row.id,
|
bizId: row.id,
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ async function handleWarehouseChange(row: ErpPurchaseInApi.PurchaseInItem) {
|
||||||
|
|
||||||
/** 处理行数据变更 */
|
/** 处理行数据变更 */
|
||||||
function handleRowChange(row: any) {
|
function handleRowChange(row: any) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
tableData.value.push(row);
|
tableData.value.push(row);
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
|
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
|
function handleDelete(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
@ -153,6 +154,7 @@ async function handleWarehouseChange(
|
||||||
|
|
||||||
/** 处理行数据变更 */
|
/** 处理行数据变更 */
|
||||||
function handleRowChange(row: any) {
|
function handleRowChange(row: any) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
tableData.value.push(row);
|
tableData.value.push(row);
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleOutApi.SaleOutItem) {
|
function handleDelete(row: ErpSaleOutApi.SaleOutItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleReturnApi.SaleReturnItem) {
|
function handleDelete(row: ErpSaleReturnApi.SaleReturnItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockCheckApi.StockCheckItem) {
|
function handleDelete(row: ErpStockCheckApi.StockCheckItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ function handleAdd() {
|
||||||
totalPrice: undefined,
|
totalPrice: undefined,
|
||||||
remark: undefined,
|
remark: undefined,
|
||||||
};
|
};
|
||||||
|
// TODO 芋艿
|
||||||
tableData.value.push(newRow);
|
tableData.value.push(newRow);
|
||||||
// 通知父组件更新
|
// 通知父组件更新
|
||||||
emit('update:items', [...tableData.value]);
|
emit('update:items', [...tableData.value]);
|
||||||
|
|
@ -105,6 +106,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockInApi.StockInItem) {
|
function handleDelete(row: ErpStockInApi.StockInItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockMoveApi.StockMoveItem) {
|
function handleDelete(row: ErpStockMoveApi.StockMoveItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockOutApi.StockOutItem) {
|
function handleDelete(row: ErpStockOutApi.StockOutItem) {
|
||||||
|
// TODO 芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const { status, data, send, close, open } = useWebSocket(server.value, {
|
||||||
const messageList = ref(
|
const messageList = ref(
|
||||||
[] as { text: string; time: number; type?: string; userId?: string }[],
|
[] as { text: string; time: number; type?: string; userId?: string }[],
|
||||||
); // 消息列表
|
); // 消息列表
|
||||||
const messageReverseList = computed(() => [...messageList.value].reverse());
|
const messageReverseList = computed(() => [...messageList.value].toReversed());
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (!data.value) {
|
if (!data.value) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -553,17 +553,17 @@ defineExpose({ open }); // 提供 open 方法,用于打开弹窗
|
||||||
|
|
||||||
.toolbar-wrapper {
|
.toolbar-wrapper {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background-color: hsl(var(--card) / 0.9);
|
background-color: hsl(var(--card) / 90%);
|
||||||
|
border: 1px solid hsl(var(--border) / 60%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid hsl(var(--border) / 0.6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container,
|
.chart-container,
|
||||||
.table-container {
|
.table-container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background-color: hsl(var(--card));
|
background-color: hsl(var(--card));
|
||||||
|
border: 1px solid hsl(var(--border) / 60%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid hsl(var(--border) / 0.6);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ import {
|
||||||
|
|
||||||
import { getLatestDeviceProperties } from '#/api/iot/device/device';
|
import { getLatestDeviceProperties } from '#/api/iot/device/device';
|
||||||
|
|
||||||
import DeviceDetailsThingModelPropertyHistory
|
import DeviceDetailsThingModelPropertyHistory from './device-details-thing-model-property-history.vue';
|
||||||
from './device-details-thing-model-property-history.vue';
|
|
||||||
|
|
||||||
const props = defineProps<{ deviceId: number }>();
|
const props = defineProps<{ deviceId: number }>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -176,7 +176,7 @@ function getDeviceTypeColor(deviceType: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取设备状态信息
|
// 获取设备状态信息
|
||||||
function getStatusInfo(state: number | string | null | undefined) {
|
function getStatusInfo(state: null | number | string | undefined) {
|
||||||
const parsedState = Number(state);
|
const parsedState = Number(state);
|
||||||
const hasNumericState = Number.isFinite(parsedState);
|
const hasNumericState = Number.isFinite(parsedState);
|
||||||
const fallback = hasNumericState
|
const fallback = hasNumericState
|
||||||
|
|
@ -396,21 +396,21 @@ defineExpose({
|
||||||
.device-card {
|
.device-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: hsl(var(--card) / 0.95);
|
background: hsl(var(--card) / 95%);
|
||||||
border: 1px solid hsl(var(--border) / 0.6);
|
border: 1px solid hsl(var(--border) / 60%);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 1px 2px 0 hsl(var(--foreground) / 0.04),
|
0 1px 2px 0 hsl(var(--foreground) / 4%),
|
||||||
0 1px 6px -1px hsl(var(--foreground) / 0.05),
|
0 1px 6px -1px hsl(var(--foreground) / 5%),
|
||||||
0 2px 4px 0 hsl(var(--foreground) / 0.05);
|
0 2px 4px 0 hsl(var(--foreground) / 5%);
|
||||||
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: hsl(var(--border));
|
border-color: hsl(var(--border));
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 1px 2px -2px hsl(var(--foreground) / 0.12),
|
0 1px 2px -2px hsl(var(--foreground) / 12%),
|
||||||
0 3px 6px 0 hsl(var(--foreground) / 0.1),
|
0 3px 6px 0 hsl(var(--foreground) / 10%),
|
||||||
0 5px 12px 4px hsl(var(--foreground) / 0.08);
|
0 5px 12px 4px hsl(var(--foreground) / 8%);
|
||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -473,7 +473,7 @@ defineExpose({
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
color: hsl(var(--foreground) / 0.9);
|
color: hsl(var(--foreground) / 90%);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,7 +496,7 @@ defineExpose({
|
||||||
.label {
|
.label {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: hsl(var(--foreground) / 0.6);
|
color: hsl(var(--foreground) / 60%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
|
|
@ -505,7 +505,7 @@ defineExpose({
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: hsl(var(--foreground) / 0.85);
|
color: hsl(var(--foreground) / 85%);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
|
|
@ -515,7 +515,7 @@ defineExpose({
|
||||||
transition: color 0.2s;
|
transition: color 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: hsl(var(--primary) / 0.85);
|
color: hsl(var(--primary) / 85%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -524,7 +524,7 @@ defineExpose({
|
||||||
'SF Mono', Monaco, Inconsolata, 'Fira Code', Consolas, monospace;
|
'SF Mono', Monaco, Inconsolata, 'Fira Code', Consolas, monospace;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: hsl(var(--foreground) / 0.6);
|
color: hsl(var(--foreground) / 60%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -537,7 +537,7 @@ defineExpose({
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid hsl(var(--border) / 0.4);
|
border-top: 1px solid hsl(var(--border) / 40%);
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -561,8 +561,8 @@ defineExpose({
|
||||||
|
|
||||||
&.btn-edit {
|
&.btn-edit {
|
||||||
color: hsl(var(--primary));
|
color: hsl(var(--primary));
|
||||||
background: hsl(var(--primary) / 0.12);
|
background: hsl(var(--primary) / 12%);
|
||||||
border-color: hsl(var(--primary) / 0.25);
|
border-color: hsl(var(--primary) / 25%);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: hsl(var(--primary-foreground));
|
color: hsl(var(--primary-foreground));
|
||||||
|
|
@ -573,8 +573,8 @@ defineExpose({
|
||||||
|
|
||||||
&.btn-view {
|
&.btn-view {
|
||||||
color: hsl(var(--warning));
|
color: hsl(var(--warning));
|
||||||
background: hsl(var(--warning) / 0.12);
|
background: hsl(var(--warning) / 12%);
|
||||||
border-color: hsl(var(--warning) / 0.25);
|
border-color: hsl(var(--warning) / 25%);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
@ -590,11 +590,7 @@ defineExpose({
|
||||||
hsl(var(--accent)) 40%,
|
hsl(var(--accent)) 40%,
|
||||||
hsl(var(--card)) 60%
|
hsl(var(--card)) 60%
|
||||||
);
|
);
|
||||||
border-color: color-mix(
|
border-color: color-mix(in srgb, hsl(var(--accent)) 55%, transparent);
|
||||||
in srgb,
|
|
||||||
hsl(var(--accent)) 55%,
|
|
||||||
transparent
|
|
||||||
);
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: hsl(var(--accent-foreground));
|
color: hsl(var(--accent-foreground));
|
||||||
|
|
@ -607,8 +603,8 @@ defineExpose({
|
||||||
flex: 0 0 32px;
|
flex: 0 0 32px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
color: hsl(var(--destructive));
|
color: hsl(var(--destructive));
|
||||||
background: hsl(var(--destructive) / 0.12);
|
background: hsl(var(--destructive) / 12%);
|
||||||
border-color: hsl(var(--destructive) / 0.3);
|
border-color: hsl(var(--destructive) / 30%);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: hsl(var(--destructive-foreground));
|
color: hsl(var(--destructive-foreground));
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ComparisonCard, Page} from '@vben/common-ui';
|
// TODO @芋艿
|
||||||
|
import type { StatsData } from './data';
|
||||||
|
|
||||||
import {Col, Row} from 'ant-design-vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import {onMounted, ref} from 'vue';
|
|
||||||
|
|
||||||
import {getStatisticsSummary} from '#/api/iot/statistics';
|
import { ComparisonCard, Page } from '@vben/common-ui';
|
||||||
|
|
||||||
import {defaultStatsData, type StatsData} from './data';
|
import { Col, Row } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { getStatisticsSummary } from '#/api/iot/statistics';
|
||||||
|
|
||||||
|
import { defaultStatsData } from './data';
|
||||||
import DeviceCountCard from './modules/device-count-card.vue';
|
import DeviceCountCard from './modules/device-count-card.vue';
|
||||||
import DeviceStateCountCard from './modules/device-state-count-card.vue';
|
import DeviceStateCountCard from './modules/device-state-count-card.vue';
|
||||||
import MessageTrendCard from './modules/message-trend-card.vue';
|
import MessageTrendCard from './modules/message-trend-card.vue';
|
||||||
|
|
|
||||||
|
|
@ -140,9 +140,9 @@ onMounted(() => {
|
||||||
<span class="text-base font-medium text-gray-600">消息量统计</span>
|
<span class="text-base font-medium text-gray-600">消息量统计</span>
|
||||||
<div class="flex flex-wrap items-center gap-4">
|
<div class="flex flex-wrap items-center gap-4">
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<span class="whitespace-nowrap text-sm text-gray-500"
|
<span class="whitespace-nowrap text-sm text-gray-500">
|
||||||
>时间范围</span
|
时间范围
|
||||||
>
|
</span>
|
||||||
<ShortcutDateRangePicker @change="handleDateRangeChange" />
|
<ShortcutDateRangePicker @change="handleDateRangeChange" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
|
|
@ -178,4 +178,4 @@ onMounted(() => {
|
||||||
<EchartsUI ref="messageChartRef" class="h-[300px] w-full" />
|
<EchartsUI ref="messageChartRef" class="h-[300px] w-full" />
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
export {default as HttpConfigForm} from './http-config-form.vue';
|
export { default as HttpConfigForm } from './http-config-form.vue';
|
||||||
export {default as KafkaMqConfigForm} from './kafka-mq-config-form.vue';
|
export { default as KafkaMqConfigForm } from './kafka-mq-config-form.vue';
|
||||||
export {default as MqttConfigForm} from './mqtt-config-form.vue';
|
export { default as MqttConfigForm } from './mqtt-config-form.vue';
|
||||||
export {default as RabbitMqConfigForm} from './rabbit-mq-config-form.vue';
|
export { default as RabbitMqConfigForm } from './rabbit-mq-config-form.vue';
|
||||||
export {default as RedisStreamConfigForm} from './redis-stream-config-form.vue';
|
export { default as RedisStreamConfigForm } from './redis-stream-config-form.vue';
|
||||||
export {default as RocketMqConfigForm} from './rocket-mq-config-form.vue';
|
export { default as RocketMqConfigForm } from './rocket-mq-config-form.vue';
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,8 @@ function handleDeviceChange(_: any) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理属性变化事件
|
* 处理属性变化事件
|
||||||
* @param propertyInfo 属性信息对象
|
* @param propertyInfo.config 属性配置
|
||||||
|
* @param propertyInfo.type 属性类型
|
||||||
*/
|
*/
|
||||||
function handlePropertyChange(propertyInfo: { config: any; type: string }) {
|
function handlePropertyChange(propertyInfo: { config: any; type: string }) {
|
||||||
propertyType.value = propertyInfo.type;
|
propertyType.value = propertyInfo.type;
|
||||||
|
|
|
||||||
|
|
@ -108,10 +108,10 @@ function updateCondition(index: number, condition: TriggerCondition) {
|
||||||
>
|
>
|
||||||
<!-- 条件配置 -->
|
<!-- 条件配置 -->
|
||||||
<div
|
<div
|
||||||
class="rounded-3px border-border bg-fill-color-blank border shadow-sm"
|
class="rounded-3px bg-fill-color-blank border-border border shadow-sm"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="rounded-t-1 border-border bg-fill-color-blank flex items-center justify-between border-b p-3"
|
class="rounded-t-1 bg-fill-color-blank border-border flex items-center justify-between border-b p-3"
|
||||||
>
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ watch(
|
||||||
{{ JSON_PARAMS_INPUT_CONSTANTS.COMPLETE_JSON_FORMAT }}
|
{{ JSON_PARAMS_INPUT_CONSTANTS.COMPLETE_JSON_FORMAT }}
|
||||||
</div>
|
</div>
|
||||||
<pre
|
<pre
|
||||||
class="bg-card border-l-3px border-primary text-primary overflow-x-auto rounded-lg p-3 text-sm"
|
class="border-l-3px border-primary bg-card text-primary overflow-x-auto rounded-lg p-3 text-sm"
|
||||||
>
|
>
|
||||||
<code>{{ generateExampleJson() }}</code>
|
<code>{{ generateExampleJson() }}</code>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,7 @@ function onActionTypeChange(action: Action, type: any) {
|
||||||
action.type ===
|
action.type ===
|
||||||
IotRuleSceneActionTypeEnum.ALERT_TRIGGER.toString()
|
IotRuleSceneActionTypeEnum.ALERT_TRIGGER.toString()
|
||||||
"
|
"
|
||||||
class="border-border bg-fill-color-blank rounded-lg border p-4"
|
class="bg-fill-color-blank border-border rounded-lg border p-4"
|
||||||
>
|
>
|
||||||
<div class="mb-2 flex items-center gap-2">
|
<div class="mb-2 flex items-center gap-2">
|
||||||
<IconifyIcon icon="ep:warning" class="text-warning text-base" />
|
<IconifyIcon icon="ep:warning" class="text-warning text-base" />
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
import { Card, Col, Form, Input, Radio, Row } from 'ant-design-vue';
|
import { Card, Col, Form, Input, Radio, Row } from 'ant-design-vue';
|
||||||
import { DictTag } from "#/components/dict-tag";
|
|
||||||
|
import { DictTag } from '#/components/dict-tag';
|
||||||
|
|
||||||
/** 基础信息配置组件 */
|
/** 基础信息配置组件 */
|
||||||
defineOptions({ name: 'BasicInfoSection' });
|
defineOptions({ name: 'BasicInfoSection' });
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { DICT_TYPE } from '@vben/constants';
|
||||||
import { Select } from 'ant-design-vue';
|
import { Select } from 'ant-design-vue';
|
||||||
|
|
||||||
import { getSimpleProductList } from '#/api/iot/product/product';
|
import { getSimpleProductList } from '#/api/iot/product/product';
|
||||||
import { DictTag } from "#/components/dict-tag";
|
import { DictTag } from '#/components/dict-tag';
|
||||||
|
|
||||||
/** 产品选择器组件 */
|
/** 产品选择器组件 */
|
||||||
defineOptions({ name: 'ProductSelector' });
|
defineOptions({ name: 'ProductSelector' });
|
||||||
|
|
@ -78,7 +78,7 @@ onMounted(() => {
|
||||||
{{ product.productKey }}
|
{{ product.productKey }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
|
<DictTag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
|
||||||
</div>
|
</div>
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ const emit = defineEmits<{
|
||||||
(e: 'change', value: { config: any; type: string }): void;
|
(e: 'change', value: { config: any; type: string }): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
// TODO 芋艿
|
||||||
/** 属性选择器内部使用的统一数据结构 */
|
/** 属性选择器内部使用的统一数据结构 */
|
||||||
interface PropertySelectorItem {
|
interface PropertySelectorItem {
|
||||||
identifier: string;
|
identifier: string;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export {default as ThingModelArrayDataSpecs} from './thing-model-array-data-specs.vue';
|
export { default as ThingModelArrayDataSpecs } from './thing-model-array-data-specs.vue';
|
||||||
export {default as ThingModelEnumDataSpecs} from './thing-model-enum-data-specs.vue';
|
export { default as ThingModelEnumDataSpecs } from './thing-model-enum-data-specs.vue';
|
||||||
export {default as ThingModelNumberDataSpecs} from './thing-model-number-data-specs.vue';
|
export { default as ThingModelNumberDataSpecs } from './thing-model-number-data-specs.vue';
|
||||||
export {default as ThingModelStructDataSpecs} from './thing-model-struct-data-specs.vue';
|
export { default as ThingModelStructDataSpecs } from './thing-model-struct-data-specs.vue';
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,8 @@ function validateSku() {
|
||||||
/**
|
/**
|
||||||
* 选择时触发
|
* 选择时触发
|
||||||
*
|
*
|
||||||
* @param records 传递过来的选中的 sku 是一个数组
|
* @param {object} param0 参数对象
|
||||||
|
* @param {MallSpuApi.Sku[]} param0.records 传递过来的选中的 sku 是一个数组
|
||||||
*/
|
*/
|
||||||
function handleSelectionChange({ records }: { records: MallSpuApi.Sku[] }) {
|
function handleSelectionChange({ records }: { records: MallSpuApi.Sku[] }) {
|
||||||
emit('selectionChange', records);
|
emit('selectionChange', records);
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ function emitActivityChange() {
|
||||||
>
|
>
|
||||||
<Tooltip :title="activity.name">
|
<Tooltip :title="activity.name">
|
||||||
<div class="relative h-full w-full">
|
<div class="relative h-full w-full">
|
||||||
|
<!-- TODO @芋艿 -->
|
||||||
<Image
|
<Image
|
||||||
:src="activity.picUrl"
|
:src="activity.picUrl"
|
||||||
class="h-full w-full rounded-lg object-cover"
|
class="h-full w-full rounded-lg object-cover"
|
||||||
|
|
|
||||||
|
|
@ -99,8 +99,8 @@ function handleAppLinkSelected(appLink: AppLink) {
|
||||||
/**
|
/**
|
||||||
* 处理右侧链接列表滚动
|
* 处理右侧链接列表滚动
|
||||||
*
|
*
|
||||||
* @param {object} param0 滚动事件参数
|
* @param {Event} event 滚动事件
|
||||||
* @param {number} param0.scrollTop 滚动条的位置
|
* @param {number} event.target.scrollTop 滚动条的位置
|
||||||
*/
|
*/
|
||||||
function handleScroll(event: Event) {
|
function handleScroll(event: Event) {
|
||||||
const scrollTop = (event.target as HTMLDivElement).scrollTop;
|
const scrollTop = (event.target as HTMLDivElement).scrollTop;
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ function eachCube(callback: (x: number, y: number, cube: Cube) => void) {
|
||||||
<td
|
<td
|
||||||
v-for="(cube, col) in rowCubes"
|
v-for="(cube, col) in rowCubes"
|
||||||
:key="col"
|
:key="col"
|
||||||
class="active:bg-primary-200 hover:bg-primary-100 box-border cursor-pointer border text-center align-middle"
|
class="hover:bg-primary-100 active:bg-primary-200 box-border cursor-pointer border text-center align-middle"
|
||||||
:class="[{ active: cube.active }]"
|
:class="[{ active: cube.active }]"
|
||||||
:style="{
|
:style="{
|
||||||
width: `${cubeSize}px`,
|
width: `${cubeSize}px`,
|
||||||
|
|
@ -219,7 +219,7 @@ function eachCube(callback: (x: number, y: number, cube: Cube) => void) {
|
||||||
<div
|
<div
|
||||||
v-for="(hotArea, index) in hotAreas"
|
v-for="(hotArea, index) in hotAreas"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="bg-primary-200 border-primary absolute box-border flex items-center justify-center border"
|
class="border-primary bg-primary-200 absolute box-border flex items-center justify-center border"
|
||||||
:style="{
|
:style="{
|
||||||
top: `${cubeSize * hotArea.top}px`,
|
top: `${cubeSize * hotArea.top}px`,
|
||||||
left: `${cubeSize * hotArea.left}px`,
|
left: `${cubeSize * hotArea.left}px`,
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ export function isContains(hotArea: Rect, point: Point): boolean {
|
||||||
*/
|
*/
|
||||||
export function createRect(a: Point, b: Point): Rect {
|
export function createRect(a: Point, b: Point): Rect {
|
||||||
// 计算矩形的范围
|
// 计算矩形的范围
|
||||||
let [left, left2] = [a.x, b.x].sort();
|
let [left, left2] = [a.x, b.x].toSorted();
|
||||||
left = left ?? 0;
|
left = left ?? 0;
|
||||||
left2 = left2 ?? 0;
|
left2 = left2 ?? 0;
|
||||||
let [top, top2] = [a.y, b.y].sort();
|
let [top, top2] = [a.y, b.y].toSorted();
|
||||||
top = top ?? 0;
|
top = top ?? 0;
|
||||||
top2 = top2 ?? 0;
|
top2 = top2 ?? 0;
|
||||||
const right = left2 + 1;
|
const right = left2 + 1;
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ function pushMessage(message: any) {
|
||||||
/** 按照时间倒序,获取消息列表 */
|
/** 按照时间倒序,获取消息列表 */
|
||||||
const getMessageList0 = computed(() => {
|
const getMessageList0 = computed(() => {
|
||||||
// 使用展开运算符创建新数组,避免直接修改原数组
|
// 使用展开运算符创建新数组,避免直接修改原数组
|
||||||
return [...messageList.value].sort(
|
return [...messageList.value].toSorted(
|
||||||
(a: any, b: any) => a.createTime - b.createTime,
|
(a: any, b: any) => a.createTime - b.createTime,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
/** 关联数据 */
|
/** 关联数据 */
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.DeliveryPickUpStore[]>([]);
|
const pickUpStoreList = ref<MallDeliveryPickUpStoreApi.DeliveryPickUpStore[]>(
|
||||||
|
[],
|
||||||
|
);
|
||||||
getSimpleDeliveryPickUpStoreList().then((res) => {
|
getSimpleDeliveryPickUpStoreList().then((res) => {
|
||||||
pickUpStoreList.value = res;
|
pickUpStoreList.value = res;
|
||||||
// 移除自己无法核销的门店
|
// 移除自己无法核销的门店
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,8 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const data = modalApi.getData<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>();
|
const data =
|
||||||
|
modalApi.getData<MallDeliveryPickUpStoreApi.DeliveryPickUpStore>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
// 初始化地图
|
// 初始化地图
|
||||||
await initTencentLbsMap();
|
await initTencentLbsMap();
|
||||||
|
|
|
||||||
|
|
@ -111,20 +111,22 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
if (data.row?.id) {
|
if (data.row?.id) {
|
||||||
// 编辑:加载数据
|
// 编辑:加载数据
|
||||||
const rowData = data.row;
|
const rowData = data.row;
|
||||||
const formValues: any = { ...rowData };
|
const formValues: any = {
|
||||||
formValues.reply = {
|
...rowData,
|
||||||
type: rowData.responseMessageType,
|
reply: {
|
||||||
accountId: data.accountId || -1,
|
type: rowData.responseMessageType,
|
||||||
content: rowData.responseContent,
|
accountId: data.accountId || -1,
|
||||||
mediaId: rowData.responseMediaId,
|
content: rowData.responseContent,
|
||||||
url: rowData.responseMediaUrl,
|
mediaId: rowData.responseMediaId,
|
||||||
title: rowData.responseTitle,
|
url: rowData.responseMediaUrl,
|
||||||
description: rowData.responseDescription,
|
title: rowData.responseTitle,
|
||||||
thumbMediaId: rowData.responseThumbMediaId,
|
description: rowData.responseDescription,
|
||||||
thumbMediaUrl: rowData.responseThumbMediaUrl,
|
thumbMediaId: rowData.responseThumbMediaId,
|
||||||
articles: rowData.responseArticles,
|
thumbMediaUrl: rowData.responseThumbMediaUrl,
|
||||||
musicUrl: rowData.responseMusicUrl,
|
articles: rowData.responseArticles,
|
||||||
hqMusicUrl: rowData.responseHqMusicUrl,
|
musicUrl: rowData.responseMusicUrl,
|
||||||
|
hqMusicUrl: rowData.responseHqMusicUrl,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
await formApi.setValues(formValues);
|
await formApi.setValues(formValues);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ async function getPage(page: any, params: any = null) {
|
||||||
|
|
||||||
const scrollHeight = msgDivRef.value?.scrollHeight ?? 0;
|
const scrollHeight = msgDivRef.value?.scrollHeight ?? 0;
|
||||||
// 处理数据
|
// 处理数据
|
||||||
const data = dataTemp.list.reverse();
|
const data = dataTemp.list.toReversed();
|
||||||
list.value = [...data, ...list.value];
|
list.value = [...data, ...list.value];
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (data.length < queryParams.pageSize || data.length === 0) {
|
if (data.length < queryParams.pageSize || data.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,12 @@ async function handleDelete(row: MpDraftApi.DraftArticle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const hideLoading = message.loading({
|
const hideLoading = message.loading({
|
||||||
content: '删除中...',
|
content: $t('ui.actionMessage.deleting'),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDraft(accountId, row.mediaId);
|
await deleteDraft(accountId, row.mediaId);
|
||||||
message.success('删除成功');
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
handleRefresh();
|
handleRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
hideLoading();
|
hideLoading();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
import type { VxeGridPropTypes } from '#/adapter/vxe-table';
|
||||||
|
import type { MpAccountApi } from '#/api/mp/account';
|
||||||
|
|
||||||
|
import { formatDateTime } from '@vben/utils';
|
||||||
|
|
||||||
|
import { getSimpleAccountList } from '#/api/mp/account';
|
||||||
|
|
||||||
|
let accountList: MpAccountApi.AccountSimple[] = [];
|
||||||
|
getSimpleAccountList().then((data) => (accountList = data));
|
||||||
|
|
||||||
|
/** 搜索表单配置 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'accountId',
|
||||||
|
label: '公众号',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: accountList.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
})),
|
||||||
|
placeholder: '请选择公众号',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表格列配置 */
|
||||||
|
export function useGridColumns(): VxeGridPropTypes.Columns {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'cover',
|
||||||
|
title: '图片',
|
||||||
|
width: 360,
|
||||||
|
slots: { default: 'cover' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
title: '标题',
|
||||||
|
slots: { default: 'title' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'updateTime',
|
||||||
|
title: '修改时间',
|
||||||
|
formatter: ({ row }) => {
|
||||||
|
return formatDateTime(row.updateTime * 1000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 120,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -1,29 +1,173 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
|
import type { MpFreePublishApi } from '#/api/mp/freePublish';
|
||||||
|
|
||||||
import { DocAlert, Page } from '@vben/common-ui';
|
import { DocAlert, Page } from '@vben/common-ui';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Image, message, Typography } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
|
import { deleteFreePublish, getFreePublishPage } from '#/api/mp/freePublish';
|
||||||
|
import { $t } from '#/locales';
|
||||||
|
import { WxAccountSelect } from '#/views/mp/components';
|
||||||
|
|
||||||
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
||||||
|
/** 刷新表格 */
|
||||||
|
function handleRefresh() {
|
||||||
|
gridApi.query();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 公众号变化时查询数据 */
|
||||||
|
function handleAccountChange(accountId: number) {
|
||||||
|
gridApi.formApi.setValues({ accountId });
|
||||||
|
gridApi.formApi.submitForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除文章 */
|
||||||
|
async function handleDelete(row: MpFreePublishApi.FreePublish) {
|
||||||
|
const formValues = await gridApi.formApi.getValues();
|
||||||
|
const accountId = formValues.accountId;
|
||||||
|
if (!accountId) {
|
||||||
|
message.warning('请先选择公众号');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hideLoading = message.loading({
|
||||||
|
content: $t('ui.actionMessage.deleting'),
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await deleteFreePublish(accountId, row.articleId!);
|
||||||
|
message.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
|
handleRefresh();
|
||||||
|
} finally {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
|
formOptions: {
|
||||||
|
schema: useGridFormSchema(),
|
||||||
|
submitOnChange: true,
|
||||||
|
},
|
||||||
|
gridOptions: {
|
||||||
|
columns: useGridColumns(),
|
||||||
|
height: 'auto',
|
||||||
|
keepSource: true,
|
||||||
|
proxyConfig: {
|
||||||
|
ajax: {
|
||||||
|
query: async ({ page }, formValues) => {
|
||||||
|
if (!formValues.accountId) {
|
||||||
|
return {
|
||||||
|
list: [],
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const res = await getFreePublishPage({
|
||||||
|
pageNo: page.currentPage,
|
||||||
|
pageSize: page.pageSize,
|
||||||
|
...formValues,
|
||||||
|
});
|
||||||
|
// 将 thumbUrl 转成 picUrl,保证 wx-news 组件可以预览封面
|
||||||
|
res.list.forEach((record: any) => {
|
||||||
|
const newsList = record.content?.newsItem;
|
||||||
|
if (newsList) {
|
||||||
|
newsList.forEach((item: any) => {
|
||||||
|
item.picUrl = item.thumbUrl || item.picUrl;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// TODO @jawe:Article 类型,报错;
|
||||||
|
return {
|
||||||
|
list: res.list as unknown as Article[],
|
||||||
|
total: res.total,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rowConfig: {
|
||||||
|
keyField: 'articleId',
|
||||||
|
isHover: true,
|
||||||
|
},
|
||||||
|
toolbarConfig: {
|
||||||
|
refresh: true,
|
||||||
|
search: true,
|
||||||
|
},
|
||||||
|
} as VxeTableGridOptions<Article>,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Page>
|
<Page auto-content-height>
|
||||||
<DocAlert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" />
|
<template #doc>
|
||||||
<Button
|
<DocAlert title="公众号图文" url="https://doc.iocoder.cn/mp/article/" />
|
||||||
danger
|
</template>
|
||||||
type="link"
|
<Grid table-title="发表记录">
|
||||||
target="_blank"
|
<template #form-accountId>
|
||||||
href="https://github.com/yudaocode/yudao-ui-admin-vue3"
|
<WxAccountSelect @change="handleAccountChange" />
|
||||||
>
|
</template>
|
||||||
该功能支持 Vue3 + element-plus 版本!
|
<template #cover="{ row }">
|
||||||
</Button>
|
<div
|
||||||
<br />
|
v-if="row.content?.newsItem && row.content.newsItem.length > 0"
|
||||||
<Button
|
class="flex flex-col items-center justify-center gap-1"
|
||||||
type="link"
|
>
|
||||||
target="_blank"
|
<Image
|
||||||
href="https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/mp/freePublish/index"
|
v-for="(item, index) in row.content.newsItem"
|
||||||
>
|
:key="index"
|
||||||
可参考
|
:src="item.picUrl || item.thumbUrl"
|
||||||
https://github.com/yudaocode/yudao-ui-admin-vue3/blob/master/src/views/mp/freePublish/index
|
class="h-36 !w-[300px] rounded object-cover"
|
||||||
代码,pull request 贡献给我们!
|
:alt="`文章 ${index + 1} 封面图`"
|
||||||
</Button>
|
/>
|
||||||
|
</div>
|
||||||
|
<span v-else class="text-gray-400">-</span>
|
||||||
|
</template>
|
||||||
|
<template #title="{ row }">
|
||||||
|
<div
|
||||||
|
v-if="row.content?.newsItem && row.content.newsItem.length > 0"
|
||||||
|
class="space-y-1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in row.content.newsItem"
|
||||||
|
:key="index"
|
||||||
|
class="flex h-36 items-center justify-center"
|
||||||
|
>
|
||||||
|
<Typography.Link :href="(item as any).url" target="_blank">
|
||||||
|
{{ item.title }}
|
||||||
|
</Typography.Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span v-else class="text-gray-400">-</span>
|
||||||
|
</template>
|
||||||
|
<template #actions="{ row }">
|
||||||
|
<TableAction
|
||||||
|
:actions="[
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'link',
|
||||||
|
danger: true,
|
||||||
|
icon: ACTION_ICON.DELETE,
|
||||||
|
auth: ['mp:free-publish:delete'],
|
||||||
|
popConfirm: {
|
||||||
|
title: '是否确认删除此数据?',
|
||||||
|
confirm: handleDelete.bind(null, row),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</Grid>
|
||||||
</Page>
|
</Page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.vxe-table--body-wrapper) {
|
||||||
|
.vxe-table--body {
|
||||||
|
.vxe-body--column {
|
||||||
|
.vxe-cell {
|
||||||
|
height: auto !important;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -134,20 +134,20 @@ function menuListToFrontend(list: any[]) {
|
||||||
list.forEach((item: RawMenu) => {
|
list.forEach((item: RawMenu) => {
|
||||||
const menu: any = {
|
const menu: any = {
|
||||||
...item,
|
...item,
|
||||||
};
|
reply: {
|
||||||
menu.reply = {
|
type: item.replyMessageType,
|
||||||
type: item.replyMessageType,
|
accountId: item.accountId,
|
||||||
accountId: item.accountId,
|
content: item.replyContent,
|
||||||
content: item.replyContent,
|
mediaId: item.replyMediaId,
|
||||||
mediaId: item.replyMediaId,
|
url: item.replyMediaUrl,
|
||||||
url: item.replyMediaUrl,
|
title: item.replyTitle,
|
||||||
title: item.replyTitle,
|
description: item.replyDescription,
|
||||||
description: item.replyDescription,
|
thumbMediaId: item.replyThumbMediaId,
|
||||||
thumbMediaId: item.replyThumbMediaId,
|
thumbMediaUrl: item.replyThumbMediaUrl,
|
||||||
thumbMediaUrl: item.replyThumbMediaUrl,
|
articles: item.replyArticles,
|
||||||
articles: item.replyArticles,
|
musicUrl: item.replyMusicUrl,
|
||||||
musicUrl: item.replyMusicUrl,
|
hqMusicUrl: item.replyHqMusicUrl,
|
||||||
hqMusicUrl: item.replyHqMusicUrl,
|
},
|
||||||
};
|
};
|
||||||
result.push(menu as RawMenu);
|
result.push(menu as RawMenu);
|
||||||
});
|
});
|
||||||
|
|
@ -275,23 +275,22 @@ function menuListToBackend() {
|
||||||
/** 将前端的 menu,转换成后端接收的 menu */
|
/** 将前端的 menu,转换成后端接收的 menu */
|
||||||
// TODO: @芋艿,需要根据后台 API 删除不需要的字段
|
// TODO: @芋艿,需要根据后台 API 删除不需要的字段
|
||||||
function menuToBackend(menu: any) {
|
function menuToBackend(menu: any) {
|
||||||
const result = {
|
return {
|
||||||
...menu,
|
...menu,
|
||||||
children: undefined, // 不处理子节点
|
children: undefined, // 不处理子节点
|
||||||
reply: undefined, // 稍后复制
|
reply: undefined, // 稍后复制
|
||||||
|
replyMessageType: menu.reply.type,
|
||||||
|
replyContent: menu.reply.content,
|
||||||
|
replyMediaId: menu.reply.mediaId,
|
||||||
|
replyMediaUrl: menu.reply.url,
|
||||||
|
replyTitle: menu.reply.title,
|
||||||
|
replyDescription: menu.reply.description,
|
||||||
|
replyThumbMediaId: menu.reply.thumbMediaId,
|
||||||
|
replyThumbMediaUrl: menu.reply.thumbMediaUrl,
|
||||||
|
replyArticles: menu.reply.articles,
|
||||||
|
replyMusicUrl: menu.reply.musicUrl,
|
||||||
|
replyHqMusicUrl: menu.reply.hqMusicUrl,
|
||||||
};
|
};
|
||||||
result.replyMessageType = menu.reply.type;
|
|
||||||
result.replyContent = menu.reply.content;
|
|
||||||
result.replyMediaId = menu.reply.mediaId;
|
|
||||||
result.replyMediaUrl = menu.reply.url;
|
|
||||||
result.replyTitle = menu.reply.title;
|
|
||||||
result.replyDescription = menu.reply.description;
|
|
||||||
result.replyThumbMediaId = menu.reply.thumbMediaId;
|
|
||||||
result.replyThumbMediaUrl = menu.reply.thumbMediaUrl;
|
|
||||||
result.replyArticles = menu.reply.articles;
|
|
||||||
result.replyMusicUrl = menu.reply.musicUrl;
|
|
||||||
result.replyHqMusicUrl = menu.reply.hqMusicUrl;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,9 +258,7 @@ export function useAppFormSchema(): VbenFormSchema[] {
|
||||||
|
|
||||||
/** 渠道新增/修改的表单 */
|
/** 渠道新增/修改的表单 */
|
||||||
export function useChannelFormSchema(formType: string = ''): VbenFormSchema[] {
|
export function useChannelFormSchema(formType: string = ''): VbenFormSchema[] {
|
||||||
const schema: VbenFormSchema[] = [];
|
const schema: VbenFormSchema[] = [
|
||||||
// 添加通用字段
|
|
||||||
schema.push(
|
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
fieldName: 'id',
|
fieldName: 'id',
|
||||||
|
|
@ -309,7 +307,8 @@ export function useChannelFormSchema(formType: string = ''): VbenFormSchema[] {
|
||||||
optionType: 'button',
|
optionType: 'button',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
];
|
||||||
|
// 添加通用字段
|
||||||
// 根据类型添加特定字段
|
// 根据类型添加特定字段
|
||||||
if (formType.includes('alipay_')) {
|
if (formType.includes('alipay_')) {
|
||||||
schema.push(
|
schema.push(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
"register": "Register",
|
"register": "Register",
|
||||||
"codeLogin": "Code Login",
|
"codeLogin": "Code Login",
|
||||||
"qrcodeLogin": "Qr Code Login",
|
"qrcodeLogin": "Qr Code Login",
|
||||||
"forgetPassword": "Forget Password"
|
"forgetPassword": "Forget Password",
|
||||||
|
"profile": "Profile"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"title": "Dashboard",
|
"title": "Dashboard",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@
|
||||||
"register": "注册",
|
"register": "注册",
|
||||||
"codeLogin": "验证码登录",
|
"codeLogin": "验证码登录",
|
||||||
"qrcodeLogin": "二维码登录",
|
"qrcodeLogin": "二维码登录",
|
||||||
"forgetPassword": "忘记密码"
|
"forgetPassword": "忘记密码",
|
||||||
|
"profile": "个人中心"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"title": "概览",
|
"title": "概览",
|
||||||
|
|
|
||||||
|
|
@ -90,8 +90,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
title: '客户统计',
|
title: '客户统计',
|
||||||
activePath: '/crm/statistics/customer',
|
activePath: '/crm/statistics/customer',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () => import('#/views/crm/statistics/customer/index.vue'),
|
||||||
import('#/views/crm/statistics/customer/index.vue'),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'statistics/funnel',
|
path: 'statistics/funnel',
|
||||||
|
|
@ -109,8 +108,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
title: '员工业绩',
|
title: '员工业绩',
|
||||||
activePath: '/crm/statistics/performance',
|
activePath: '/crm/statistics/performance',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () => import('#/views/crm/statistics/performance/index.vue'),
|
||||||
import('#/views/crm/statistics/performance/index.vue'),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'statistics/portrait',
|
path: 'statistics/portrait',
|
||||||
|
|
@ -119,8 +117,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
title: '客户画像',
|
title: '客户画像',
|
||||||
activePath: '/crm/statistics/portrait',
|
activePath: '/crm/statistics/portrait',
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () => import('#/views/crm/statistics/portrait/index.vue'),
|
||||||
import('#/views/crm/statistics/portrait/index.vue'),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'statistics/rank',
|
path: 'statistics/rank',
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export const useMallKefuStore = defineStore('mall-kefu', {
|
||||||
},
|
},
|
||||||
conversationSort() {
|
conversationSort() {
|
||||||
// 按置顶属性和最后消息时间排序
|
// 按置顶属性和最后消息时间排序
|
||||||
this.conversationList.sort((a, b) => {
|
this.conversationList.toSorted((a, b) => {
|
||||||
// 按照置顶排序,置顶的会在前面
|
// 按照置顶排序,置顶的会在前面
|
||||||
if (a.adminPinned !== b.adminPinned) {
|
if (a.adminPinned !== b.adminPinned) {
|
||||||
return a.adminPinned ? -1 : 1;
|
return a.adminPinned ? -1 : 1;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { BasicOption } from '@vben/types';
|
||||||
|
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
|
||||||
|
import { computed, onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileBaseSetting } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { getUserInfoApi } from '#/api';
|
||||||
|
|
||||||
|
const profileBaseSettingRef = ref();
|
||||||
|
|
||||||
|
const MOCK_ROLES_OPTIONS: BasicOption[] = [
|
||||||
|
{
|
||||||
|
label: '管理员',
|
||||||
|
value: 'super',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '用户',
|
||||||
|
value: 'user',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '测试',
|
||||||
|
value: 'test',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'realName',
|
||||||
|
component: 'Input',
|
||||||
|
label: '姓名',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'username',
|
||||||
|
component: 'Input',
|
||||||
|
label: '用户名',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'roles',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
mode: 'tags',
|
||||||
|
options: MOCK_ROLES_OPTIONS,
|
||||||
|
},
|
||||||
|
label: '角色',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'introduction',
|
||||||
|
component: 'Textarea',
|
||||||
|
label: '个人简介',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const data = await getUserInfoApi();
|
||||||
|
profileBaseSettingRef.value.getFormApi().setValues(data);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileBaseSetting ref="profileBaseSettingRef" :form-schema="formSchema" />
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileNotificationSetting } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const formSchema = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'accountPassword',
|
||||||
|
label: '账户密码',
|
||||||
|
description: '其他用户的消息将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'systemMessage',
|
||||||
|
label: '系统消息',
|
||||||
|
description: '系统消息将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'todoTask',
|
||||||
|
label: '待办任务',
|
||||||
|
description: '待办任务将以站内信的形式通知',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileNotificationSetting :form-schema="formSchema" />
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
import { ProfilePasswordSetting, z } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const profilePasswordSettingRef = ref();
|
||||||
|
|
||||||
|
const formSchema = computed((): VbenFormSchema[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'oldPassword',
|
||||||
|
label: '旧密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入旧密码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'newPassword',
|
||||||
|
label: '新密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
passwordStrength: true,
|
||||||
|
placeholder: '请输入新密码',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'confirmPassword',
|
||||||
|
label: '确认密码',
|
||||||
|
component: 'VbenInputPassword',
|
||||||
|
componentProps: {
|
||||||
|
passwordStrength: true,
|
||||||
|
placeholder: '请再次输入新密码',
|
||||||
|
},
|
||||||
|
dependencies: {
|
||||||
|
rules(values) {
|
||||||
|
const { newPassword } = values;
|
||||||
|
return z
|
||||||
|
.string({ required_error: '请再次输入新密码' })
|
||||||
|
.min(1, { message: '请再次输入新密码' })
|
||||||
|
.refine((value) => value === newPassword, {
|
||||||
|
message: '两次输入的密码不一致',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
triggerFields: ['newPassword'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
ElMessage.success('密码修改成功');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfilePasswordSetting
|
||||||
|
ref="profilePasswordSettingRef"
|
||||||
|
class="w-1/3"
|
||||||
|
:form-schema="formSchema"
|
||||||
|
@submit="handleSubmit"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { ProfileSecuritySetting } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const formSchema = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'accountPassword',
|
||||||
|
label: '账户密码',
|
||||||
|
description: '当前密码强度:强',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityPhone',
|
||||||
|
label: '密保手机',
|
||||||
|
description: '已绑定手机:138****8293',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityQuestion',
|
||||||
|
label: '密保问题',
|
||||||
|
description: '未设置密保问题,密保问题可有效保护账户安全',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
fieldName: 'securityEmail',
|
||||||
|
label: '备用邮箱',
|
||||||
|
description: '已绑定邮箱:ant***sign.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
fieldName: 'securityMfa',
|
||||||
|
label: 'MFA 设备',
|
||||||
|
description: '未绑定 MFA 设备,绑定后,可以进行二次确认',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ProfileSecuritySetting :form-schema="formSchema" />
|
||||||
|
</template>
|
||||||
|
|
@ -411,8 +411,8 @@ async function doSendMessageStream(userMessage: AiChatMessageApi.ChatMessage) {
|
||||||
const lastMessage =
|
const lastMessage =
|
||||||
activeMessageList.value[activeMessageList.value.length - 1];
|
activeMessageList.value[activeMessageList.value.length - 1];
|
||||||
// 累加推理内容
|
// 累加推理内容
|
||||||
lastMessage.reasoningContent =
|
lastMessage!.reasoningContent =
|
||||||
(lastMessage.reasoningContent || '') +
|
(lastMessage!.reasoningContent || '') +
|
||||||
data.receive.reasoningContent;
|
data.receive.reasoningContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,7 +565,7 @@ onMounted(async () => {
|
||||||
<!-- 右侧:详情部分 -->
|
<!-- 右侧:详情部分 -->
|
||||||
<ElContainer direction="vertical" class="bg-card mx-4 flex-1">
|
<ElContainer direction="vertical" class="bg-card mx-4 flex-1">
|
||||||
<ElHeader
|
<ElHeader
|
||||||
class="!bg-card border-border flex !h-12 items-center justify-between border-b !px-4"
|
class="border-border !bg-card flex !h-12 items-center justify-between border-b !px-4"
|
||||||
>
|
>
|
||||||
<div class="text-lg font-bold">
|
<div class="text-lg font-bold">
|
||||||
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
{{ activeConversation?.title ? activeConversation?.title : '对话' }}
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ async function getChatConversationList() {
|
||||||
// 1.1 获取 对话数据
|
// 1.1 获取 对话数据
|
||||||
conversationList.value = await getChatConversationMyList();
|
conversationList.value = await getChatConversationMyList();
|
||||||
// 1.2 排序
|
// 1.2 排序
|
||||||
conversationList.value.sort((a, b) => {
|
conversationList.value.toSorted((a, b) => {
|
||||||
return Number(b.createTime) - Number(a.createTime);
|
return Number(b.createTime) - Number(a.createTime);
|
||||||
});
|
});
|
||||||
// 1.3 没有任何对话情况
|
// 1.3 没有任何对话情况
|
||||||
|
|
|
||||||
|
|
@ -138,14 +138,14 @@ async function uploadFile(fileItem: FileItem) {
|
||||||
fileItem.progress = 100;
|
fileItem.progress = 100;
|
||||||
|
|
||||||
// 调试日志
|
// 调试日志
|
||||||
console.log('上传响应:', response);
|
console.warn('上传响应:', response);
|
||||||
|
|
||||||
// 兼容不同的返回格式:{ url: '...' } 或 { data: '...' } 或直接是字符串
|
// 兼容不同的返回格式:{ url: '...' } 或 { data: '...' } 或直接是字符串
|
||||||
const fileUrl =
|
const fileUrl =
|
||||||
(response as any)?.url || (response as any)?.data || response;
|
(response as any)?.url || (response as any)?.data || response;
|
||||||
fileItem.url = fileUrl;
|
fileItem.url = fileUrl;
|
||||||
|
|
||||||
console.log('提取的文件 URL:', fileUrl);
|
console.warn('提取的文件 URL:', fileUrl);
|
||||||
|
|
||||||
// 只有当 URL 有效时才添加到列表
|
// 只有当 URL 有效时才添加到列表
|
||||||
if (fileUrl && typeof fileUrl === 'string') {
|
if (fileUrl && typeof fileUrl === 'string') {
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ async function handleImageMidjourneyButtonClick(
|
||||||
const data = {
|
const data = {
|
||||||
id: imageDetail.id,
|
id: imageDetail.id,
|
||||||
customId: button.customId,
|
customId: button.customId,
|
||||||
} as AiImageApi.ImageMidjourneyActionVO;
|
} as AiImageApi.ImageMidjourneyAction;
|
||||||
// 2. 发送 action
|
// 2. 发送 action
|
||||||
await midjourneyAction(data);
|
await midjourneyAction(data);
|
||||||
// 3. 刷新列表
|
// 3. 刷新列表
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ import {
|
||||||
getChatRole,
|
getChatRole,
|
||||||
updateChatRole,
|
updateChatRole,
|
||||||
} from '#/api/ai/model/chatRole';
|
} from '#/api/ai/model/chatRole';
|
||||||
import {} from '#/api/bpm/model';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import { createModel, getModel, updateModel } from '#/api/ai/model/model';
|
import { createModel, getModel, updateModel } from '#/api/ai/model/model';
|
||||||
import {} from '#/api/bpm/model';
|
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import { useFormSchema } from '../data';
|
import { useFormSchema } from '../data';
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const currentSong = ref({}); // 当前音乐
|
||||||
const mySongList = ref<Recordable<any>[]>([]);
|
const mySongList = ref<Recordable<any>[]>([]);
|
||||||
const squareSongList = ref<Recordable<any>[]>([]);
|
const squareSongList = ref<Recordable<any>[]>([]);
|
||||||
|
|
||||||
function generateMusic(formData: Recordable<any>) {
|
function generateMusic(_formData: Recordable<any>) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
mySongList.value = Array.from({ length: 20 }, (_, index) => {
|
mySongList.value = Array.from({ length: 20 }, (_, index) => {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ const emits = defineEmits<{
|
||||||
<span
|
<span
|
||||||
v-for="tag in props.tags"
|
v-for="tag in props.tags"
|
||||||
:key="tag.value"
|
:key="tag.value"
|
||||||
class="bg-card border-card-100 mb-2 cursor-pointer rounded border-2 border-solid px-1 text-xs leading-6"
|
class="border-card-100 bg-card mb-2 cursor-pointer rounded border-2 border-solid px-1 text-xs leading-6"
|
||||||
:class="
|
:class="
|
||||||
modelValue === tag.value && '!border-primary-500 !text-primary-500'
|
modelValue === tag.value && '!border-primary-500 !text-primary-500'
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -54,7 +54,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -102,7 +102,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -150,7 +150,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -198,7 +198,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -246,7 +246,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -294,7 +294,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
@ -342,7 +342,7 @@ export function getChartOptions(activeTabName: any, res: any): any {
|
||||||
return {
|
return {
|
||||||
dataset: {
|
dataset: {
|
||||||
dimensions: ['nickname', 'count'],
|
dimensions: ['nickname', 'count'],
|
||||||
source: cloneDeep(res).reverse(),
|
source: cloneDeep(res).toReversed(),
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: 20,
|
left: 20,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ onMounted(() => {
|
||||||
{ name: '定制', value: 310 },
|
{ name: '定制', value: 310 },
|
||||||
{ name: '技术支持', value: 274 },
|
{ name: '技术支持', value: 274 },
|
||||||
{ name: '远程', value: 400 },
|
{ name: '远程', value: 400 },
|
||||||
].sort((a, b) => {
|
].toSorted((a, b) => {
|
||||||
return a.value - b.value;
|
return a.value - b.value;
|
||||||
}),
|
}),
|
||||||
name: '商业占比',
|
name: '商业占比',
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ const handleOpenPurchaseIn = () => {
|
||||||
|
|
||||||
const handleAddPurchaseIn = (rows: ErpPurchaseInApi.PurchaseIn[]) => {
|
const handleAddPurchaseIn = (rows: ErpPurchaseInApi.PurchaseIn[]) => {
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
|
// TODO @芋艿
|
||||||
const newItem: ErpFinancePaymentApi.FinancePaymentItem = {
|
const newItem: ErpFinancePaymentApi.FinancePaymentItem = {
|
||||||
bizId: row.id,
|
bizId: row.id,
|
||||||
bizType: ErpBizType.PURCHASE_IN,
|
bizType: ErpBizType.PURCHASE_IN,
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ function handleOpenSaleOut() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAddSaleOut(rows: ErpSaleOutApi.SaleOut[]) {
|
function handleAddSaleOut(rows: ErpSaleOutApi.SaleOut[]) {
|
||||||
|
// TODO @芋艿
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
const newItem: ErpFinanceReceiptApi.FinanceReceiptItem = {
|
||||||
bizId: row.id,
|
bizId: row.id,
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpPurchaseInApi.PurchaseInItem) {
|
function handleDelete(row: ErpPurchaseInApi.PurchaseInItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
|
function handleDelete(row: ErpPurchaseOrderApi.PurchaseOrderItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
@ -169,6 +170,7 @@ async function handleProductChange(productId: any, row: any) {
|
||||||
|
|
||||||
/** 处理行数据变更 */
|
/** 处理行数据变更 */
|
||||||
function handleRowChange(row: any) {
|
function handleRowChange(row: any) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
tableData.value.push(row);
|
tableData.value.push(row);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
|
function handleDelete(row: ErpPurchaseReturnApi.PurchaseReturnItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
function handleDelete(row: ErpSaleOrderApi.SaleOrderItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleOutApi.SaleOutItem) {
|
function handleDelete(row: ErpSaleOutApi.SaleOutItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ watch(
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpSaleReturnApi.SaleReturnItem) {
|
function handleDelete(row: ErpSaleReturnApi.SaleReturnItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockCheckApi.StockCheckItem) {
|
function handleDelete(row: ErpStockCheckApi.StockCheckItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ watch(
|
||||||
|
|
||||||
/** 处理新增 */
|
/** 处理新增 */
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
|
// TODO @芋艿
|
||||||
const newRow = {
|
const newRow = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
warehouseId: undefined,
|
warehouseId: undefined,
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ function handleAdd() {
|
||||||
|
|
||||||
/** 处理删除 */
|
/** 处理删除 */
|
||||||
function handleDelete(row: ErpStockOutApi.StockOutItem) {
|
function handleDelete(row: ErpStockOutApi.StockOutItem) {
|
||||||
|
// TODO @芋艿
|
||||||
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
const index = tableData.value.findIndex((item) => item.seq === row.seq);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
tableData.value.splice(index, 1);
|
tableData.value.splice(index, 1);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ const { status, data, send, close, open } = useWebSocket(server.value, {
|
||||||
const messageList = ref(
|
const messageList = ref(
|
||||||
[] as { text: string; time: number; type?: string; userId?: string }[],
|
[] as { text: string; time: number; type?: string; userId?: string }[],
|
||||||
); // 消息列表
|
); // 消息列表
|
||||||
const messageReverseList = computed(() => [...messageList.value].reverse());
|
const messageReverseList = computed(() => [...messageList.value].toReversed());
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (!data.value) {
|
if (!data.value) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ function emitActivityChange() {
|
||||||
>
|
>
|
||||||
<ElTooltip :content="activity.name">
|
<ElTooltip :content="activity.name">
|
||||||
<div class="relative h-full w-full">
|
<div class="relative h-full w-full">
|
||||||
|
<!-- TODO @芋艿 -->
|
||||||
<ElImage
|
<ElImage
|
||||||
:src="activity.picUrl"
|
:src="activity.picUrl"
|
||||||
class="h-full w-full rounded-lg object-cover"
|
class="h-full w-full rounded-lg object-cover"
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,10 @@ export function isContains(hotArea: Rect, point: Point): boolean {
|
||||||
*/
|
*/
|
||||||
export function createRect(a: Point, b: Point): Rect {
|
export function createRect(a: Point, b: Point): Rect {
|
||||||
// 计算矩形的范围
|
// 计算矩形的范围
|
||||||
let [left, left2] = [a.x, b.x].sort();
|
let [left, left2] = [a.x, b.x].toSorted();
|
||||||
left = left ?? 0;
|
left = left ?? 0;
|
||||||
left2 = left2 ?? 0;
|
left2 = left2 ?? 0;
|
||||||
let [top, top2] = [a.y, b.y].sort();
|
let [top, top2] = [a.y, b.y].toSorted();
|
||||||
top = top ?? 0;
|
top = top ?? 0;
|
||||||
top2 = top2 ?? 0;
|
top2 = top2 ?? 0;
|
||||||
const right = left2 + 1;
|
const right = left2 + 1;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ function pushMessage(message: any) {
|
||||||
/** 按照时间倒序,获取消息列表 */
|
/** 按照时间倒序,获取消息列表 */
|
||||||
const getMessageList0 = computed(() => {
|
const getMessageList0 = computed(() => {
|
||||||
// 使用展开运算符创建新数组,避免直接修改原数组
|
// 使用展开运算符创建新数组,避免直接修改原数组
|
||||||
return [...messageList.value].sort(
|
return [...messageList.value].toSorted(
|
||||||
(a: any, b: any) => a.createTime - b.createTime,
|
(a: any, b: any) => a.createTime - b.createTime,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ function emitActivityChange() {
|
||||||
>
|
>
|
||||||
<ElTooltip :content="activity.name">
|
<ElTooltip :content="activity.name">
|
||||||
<div class="relative h-full w-full">
|
<div class="relative h-full w-full">
|
||||||
|
<!-- TODO @芋艿 -->
|
||||||
<ElImage
|
<ElImage
|
||||||
:src="activity.picUrl"
|
:src="activity.picUrl"
|
||||||
class="h-full w-full rounded-lg object-cover"
|
class="h-full w-full rounded-lg object-cover"
|
||||||
|
|
|
||||||
|
|
@ -111,20 +111,22 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
if (data.row?.id) {
|
if (data.row?.id) {
|
||||||
// 编辑:加载数据
|
// 编辑:加载数据
|
||||||
const rowData = data.row;
|
const rowData = data.row;
|
||||||
const formValues: any = { ...rowData };
|
const formValues: any = {
|
||||||
formValues.reply = {
|
...rowData,
|
||||||
type: rowData.responseMessageType,
|
reply: {
|
||||||
accountId: data.accountId || -1,
|
type: rowData.responseMessageType,
|
||||||
content: rowData.responseContent,
|
accountId: data.accountId || -1,
|
||||||
mediaId: rowData.responseMediaId,
|
content: rowData.responseContent,
|
||||||
url: rowData.responseMediaUrl,
|
mediaId: rowData.responseMediaId,
|
||||||
title: rowData.responseTitle,
|
url: rowData.responseMediaUrl,
|
||||||
description: rowData.responseDescription,
|
title: rowData.responseTitle,
|
||||||
thumbMediaId: rowData.responseThumbMediaId,
|
description: rowData.responseDescription,
|
||||||
thumbMediaUrl: rowData.responseThumbMediaUrl,
|
thumbMediaId: rowData.responseThumbMediaId,
|
||||||
articles: rowData.responseArticles,
|
thumbMediaUrl: rowData.responseThumbMediaUrl,
|
||||||
musicUrl: rowData.responseMusicUrl,
|
articles: rowData.responseArticles,
|
||||||
hqMusicUrl: rowData.responseHqMusicUrl,
|
musicUrl: rowData.responseMusicUrl,
|
||||||
|
hqMusicUrl: rowData.responseHqMusicUrl,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
await formApi.setValues(formValues);
|
await formApi.setValues(formValues);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ async function getPage(page: any, params: any = null) {
|
||||||
|
|
||||||
const scrollHeight = msgDivRef.value?.scrollHeight ?? 0;
|
const scrollHeight = msgDivRef.value?.scrollHeight ?? 0;
|
||||||
// 处理数据
|
// 处理数据
|
||||||
const data = dataTemp.list.reverse();
|
const data = dataTemp.list.toReversed();
|
||||||
list.value = [...data, ...list.value];
|
list.value = [...data, ...list.value];
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (data.length < queryParams.pageSize || data.length === 0) {
|
if (data.length < queryParams.pageSize || data.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,11 @@ async function handleDelete(row: MpDraftApi.DraftArticle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const hideLoading = ElLoading.service({
|
const hideLoading = ElLoading.service({
|
||||||
text: '删除中...',
|
text: $t('ui.actionMessage.deleting'),
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
await deleteDraft(accountId, row.mediaId);
|
await deleteDraft(accountId, row.mediaId);
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success($t('ui.actionMessage.deleteSuccess'));
|
||||||
handleRefresh();
|
handleRefresh();
|
||||||
} finally {
|
} finally {
|
||||||
hideLoading.close();
|
hideLoading.close();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import type { VbenFormSchema } from '#/adapter/form';
|
||||||
|
import type { VxeGridPropTypes } from '#/adapter/vxe-table';
|
||||||
|
import type { MpAccountApi } from '#/api/mp/account';
|
||||||
|
|
||||||
|
import { formatDateTime } from '@vben/utils';
|
||||||
|
|
||||||
|
import { getSimpleAccountList } from '#/api/mp/account';
|
||||||
|
|
||||||
|
let accountList: MpAccountApi.AccountSimple[] = [];
|
||||||
|
getSimpleAccountList().then((data) => (accountList = data));
|
||||||
|
|
||||||
|
/** 搜索表单配置 */
|
||||||
|
export function useGridFormSchema(): VbenFormSchema[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
fieldName: 'accountId',
|
||||||
|
label: '公众号',
|
||||||
|
component: 'Select',
|
||||||
|
componentProps: {
|
||||||
|
options: accountList.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
})),
|
||||||
|
placeholder: '请选择公众号',
|
||||||
|
clearable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表格列配置 */
|
||||||
|
export function useGridColumns(): VxeGridPropTypes.Columns {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
field: 'cover',
|
||||||
|
title: '图片',
|
||||||
|
width: 360,
|
||||||
|
slots: { default: 'cover' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
title: '标题',
|
||||||
|
slots: { default: 'title' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'updateTime',
|
||||||
|
title: '修改时间',
|
||||||
|
formatter: ({ row }) => {
|
||||||
|
return formatDateTime(row.updateTime * 1000);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
width: 120,
|
||||||
|
fixed: 'right',
|
||||||
|
slots: { default: 'actions' },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue