From 3cac94ef8ce5688b46e7b297165b96125ac7a334 Mon Sep 17 00:00:00 2001
From: panda <1565636758@qq.com>
Date: Mon, 24 Mar 2025 15:47:48 +0800
Subject: [PATCH 001/161] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=B4=E9=83=A8?=
=?UTF-8?q?=E4=B8=BB=E9=A2=98=E6=B7=B1=E8=89=B2=E6=A8=A1=E5=BC=8F=E4=B8=8B?=
=?UTF-8?q?=EF=BC=8C=E9=A1=B6=E9=83=A8=E5=B7=A5=E5=85=B7=E6=A0=8F=E7=9A=84?=
=?UTF-8?q?=E6=90=9C=E7=B4=A2=E3=80=81=E6=B6=88=E6=81=AF=E6=B2=A1=E6=9C=89?=
=?UTF-8?q?=E4=BC=A0=E4=B8=BB=E9=A2=98=E8=89=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/RouterSearch/index.vue | 6 ++++--
src/layout/components/Message/src/Message.vue | 7 ++++++-
src/layout/components/ToolHeader.vue | 2 +-
3 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/components/RouterSearch/index.vue b/src/components/RouterSearch/index.vue
index 42a41744d..52425ec99 100644
--- a/src/components/RouterSearch/index.vue
+++ b/src/components/RouterSearch/index.vue
@@ -18,7 +18,7 @@
-
+
\ No newline at end of file
diff --git a/src/components/Verifition/src/Verify/index.ts b/src/components/Verifition/src/Verify/index.ts
index 0daa63a56..e027ab3fd 100644
--- a/src/components/Verifition/src/Verify/index.ts
+++ b/src/components/Verifition/src/Verify/index.ts
@@ -1,4 +1,5 @@
import VerifySlide from './VerifySlide.vue'
import VerifyPoints from './VerifyPoints.vue'
+import VerifyPictureWord from './VerifyPictureWord.vue'
-export { VerifySlide, VerifyPoints }
+export { VerifySlide, VerifyPoints, VerifyPictureWord }
\ No newline at end of file
diff --git a/src/locales/en.ts b/src/locales/en.ts
index 505cfd80d..bd4c0b42c 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -146,9 +146,11 @@ export default {
invalidTenantName:"Invalid Tenant Name"
},
captcha: {
+ verify: 'Verify',
verification: 'Please complete security verification',
slide: 'Swipe right to complete verification',
point: 'Please click',
+ code: 'Please enter the verification code',
success: 'Verification succeeded',
fail: 'verification failed'
},
@@ -457,4 +459,4 @@ export default {
btn_zoom_out: 'Zoom out',
preview: 'Preivew'
}
-}
+}
\ No newline at end of file
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index 768b5879a..3b6c2e904 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -147,9 +147,11 @@ export default {
invalidTenantName: '无效的租户名称'
},
captcha: {
+ verify: '验证',
verification: '请完成安全验证',
slide: '向右滑动完成验证',
point: '请依次点击',
+ code: '请输入验证码',
success: '验证成功',
fail: '验证失败'
},
@@ -453,4 +455,4 @@ export default {
preview: '预览'
},
'OAuth 2.0': 'OAuth 2.0' // 避免菜单名是 OAuth 2.0 时,一直 warn 报错
-}
+}
\ No newline at end of file
From dd5bfbc8591813fdcf10821545e998c997509d3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B1=B1=E9=87=8E=E7=BE=A1=E6=B0=91?=
Date: Mon, 28 Jul 2025 07:15:32 +0000
Subject: [PATCH 005/161] =?UTF-8?q?fix:=20=E6=B3=A8=E5=86=8C=E8=A1=A8?=
=?UTF-8?q?=E5=8D=95=E6=A0=A1=E9=AA=8C=E6=9C=AA=E5=A4=B1=E6=95=88=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: 山野羡民
---
src/views/Login/components/RegisterForm.vue | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/views/Login/components/RegisterForm.vue b/src/views/Login/components/RegisterForm.vue
index 0636a1c82..6a77cfbfc 100644
--- a/src/views/Login/components/RegisterForm.vue
+++ b/src/views/Login/components/RegisterForm.vue
@@ -38,7 +38,7 @@
-
+
{
loading.value = true
@@ -183,6 +185,11 @@ const handleRegister = async (params: any) => {
registerData.registerForm.captchaVerification = params.captchaVerification
}
+ const data = await validForm()
+ if (!data) {
+ return
+ }
+
const res = await LoginApi.register(registerData.registerForm)
if (!res) {
return
@@ -242,7 +249,6 @@ const getTenantByWebsite = async () => {
}
}
}
-const loading = ref() // ElLoading.service 返回的实例
watch(
() => currentRoute.value,
From a164509565a72d310520bc8bcb2b3c435a439a53 Mon Sep 17 00:00:00 2001
From: LesanOuO <1960681385@qq.com>
Date: Sat, 2 Aug 2025 14:15:34 +0800
Subject: [PATCH 006/161] =?UTF-8?q?feat:=20=E5=B7=A5=E4=BD=9C=E6=B5=81?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AE=A1=E6=89=B9=E4=BA=BA=E6=92=A4=E5=9B=9E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/bpm/task/index.ts | 5 ++++
src/views/bpm/model/form/ExtraSettings.vue | 29 ++++++++++++++++------
src/views/bpm/model/form/index.vue | 10 +++++---
src/views/bpm/task/done/index.vue | 12 ++++++++-
4 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/src/api/bpm/task/index.ts b/src/api/bpm/task/index.ts
index a818ae5aa..713400fc4 100644
--- a/src/api/bpm/task/index.ts
+++ b/src/api/bpm/task/index.ts
@@ -106,6 +106,11 @@ export const copyTask = async (data: any) => {
return await request.put({ url: '/bpm/task/copy', data })
}
+// 撤回
+export const withdrawTask = async (taskId: string) => {
+ return await request.put({ url: '/bpm/task/withdraw', params: { taskId } })
+}
+
// 获取我的待办任务
export const myTodoTask = async (processInstanceId: string) => {
return await request.get({ url: '/bpm/task/my-todo?processInstanceId=' + processInstanceId })
diff --git a/src/views/bpm/model/form/ExtraSettings.vue b/src/views/bpm/model/form/ExtraSettings.vue
index 9c5beaf60..b6536d16d 100644
--- a/src/views/bpm/model/form/ExtraSettings.vue
+++ b/src/views/bpm/model/form/ExtraSettings.vue
@@ -11,6 +11,17 @@
+
+
+ 审批人权限
+
+
+
+
+ 审批人可撤回正在审批节点的前一节点
+
+
+
流程编码
@@ -233,31 +244,30 @@ import HttpRequestSetting from '@/components/SimpleProcessDesignerV2/src/nodes-c
const modelData = defineModel()
const formFields = ref([])
-
+
const props = defineProps({
// 流程表单 ID
modelFormId: {
type: Number,
required: false,
- default: undefined,
+ default: undefined
}
})
-
// 监听 modelFormId 变化
watch(
() => props.modelFormId,
async (newVal) => {
if (newVal) {
- const form = await FormApi.getForm(newVal);
- formFields.value = form?.fields;
+ const form = await FormApi.getForm(newVal)
+ formFields.value = form?.fields
} else {
// 如果 modelFormId 为空,清空表单字段
- formFields.value = [];
+ formFields.value = []
}
},
- { immediate: true },
-);
+ { immediate: true }
+)
// 暴露给子组件使用
provide('formFields', formFields)
@@ -445,6 +455,9 @@ const initData = () => {
if (modelData.value.taskAfterTriggerSetting) {
taskAfterTriggerEnable.value = true
}
+ if (modelData.value.allowWithdrawTask) {
+ modelData.value.allowWithdrawTask = false
+ }
}
defineExpose({ initData })
diff --git a/src/views/bpm/model/form/index.vue b/src/views/bpm/model/form/index.vue
index 341d95684..b77ea62e3 100644
--- a/src/views/bpm/model/form/index.vue
+++ b/src/views/bpm/model/form/index.vue
@@ -78,9 +78,10 @@
+ ref="extraSettingsRef"
+ v-model="formData"
+ :model-form-id="formData.formId"
+ />
@@ -176,7 +177,8 @@ const formData: any = ref({
summarySetting: {
enable: false,
summary: []
- }
+ },
+ allowWithdrawTask: false
})
// 流程数据
diff --git a/src/views/bpm/task/done/index.vue b/src/views/bpm/task/done/index.vue
index 2f91e69a1..29c4d7558 100644
--- a/src/views/bpm/task/done/index.vue
+++ b/src/views/bpm/task/done/index.vue
@@ -184,8 +184,9 @@
:show-overflow-tooltip="true"
/>
-
+
+ 撤回
历史
@@ -209,6 +210,7 @@ import * as DefinitionApi from '@/api/bpm/definition'
defineOptions({ name: 'BpmDoneTask' })
const { push } = useRouter() // 路由
+const message = useMessage()
const loading = ref(true) // 列表的加载中
const total = ref(0) // 列表的总页数
@@ -262,6 +264,14 @@ const handleAudit = (row: any) => {
})
}
+/** 测回按钮 */
+const handleWithdraw = (row: any) => {
+ TaskApi.withdrawTask(row.id).then(() => {
+ message.success('撤回成功')
+ getList()
+ })
+}
+
/** 初始化 **/
onMounted(async () => {
await getList()
From 5a87a41812b10af09ea92797d3a32bc5da361f6c Mon Sep 17 00:00:00 2001
From: tsui <1146818706@qq.com>
Date: Sat, 2 Aug 2025 18:59:54 +0800
Subject: [PATCH 007/161] =?UTF-8?q?fix:=E6=98=8E=E7=A1=AE=E6=96=87?=
=?UTF-8?q?=E5=AD=97=E9=AA=8C=E8=AF=81=E7=A0=81=E6=8C=89=E9=92=AE=E7=B1=BB?=
=?UTF-8?q?=E5=9E=8B=EF=BC=8C=E7=99=BB=E5=BD=95=E8=A1=A8=E5=8D=95=E7=BB=84?=
=?UTF-8?q?=E4=BB=B6=E6=B7=BB=E5=8A=A0=20=E6=96=87=E5=AD=97=E9=AA=8C?=
=?UTF-8?q?=E8=AF=81=E7=A0=81=20=E7=B1=BB=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/Verifition/src/Verify.vue | 4 ++++
src/components/Verifition/src/Verify/VerifyPictureWord.vue | 4 ++--
src/views/Login/components/LoginForm.vue | 5 +++--
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/components/Verifition/src/Verify.vue b/src/components/Verifition/src/Verify.vue
index f9dea4ffc..930d0e721 100644
--- a/src/components/Verifition/src/Verify.vue
+++ b/src/components/Verifition/src/Verify.vue
@@ -119,6 +119,10 @@ export default {
}
watchEffect(() => {
switch (captchaType.value) {
+ case 'pictureWord':
+ verifyType.value = '3'
+ componentType.value = 'VerifyPictureWord'
+ break
case 'blockPuzzle':
verifyType.value = '2'
componentType.value = 'VerifySlide'
diff --git a/src/components/Verifition/src/Verify/VerifyPictureWord.vue b/src/components/Verifition/src/Verify/VerifyPictureWord.vue
index 4fa26c377..f996f648c 100644
--- a/src/components/Verifition/src/Verify/VerifyPictureWord.vue
+++ b/src/components/Verifition/src/Verify/VerifyPictureWord.vue
@@ -37,7 +37,7 @@
}">
-
+
@@ -48,7 +48,7 @@
* */
import { resetSize } from '../utils/util';
import { aesEncrypt } from '../utils/ase';
-import { getCode, reqCheck } from 'src/api/login';
+import { getCode, reqCheck } from '@/api/login';
import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue';
const props = defineProps({
diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue
index 3c4e1d1a9..cb4dd429a 100644
--- a/src/views/Login/components/LoginForm.vue
+++ b/src/views/Login/components/LoginForm.vue
@@ -177,7 +177,8 @@ const permissionStore = usePermissionStore()
const redirect = ref('')
const loginLoading = ref(false)
const verify = ref()
-const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+const captchaType = ref('pictureWord') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
+// const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
@@ -360,4 +361,4 @@ onMounted(() => {
cursor: pointer;
}
}
-
+
\ No newline at end of file
From ca17d5ac219ada85c89eaf2b561a3a643c51dd50 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 2 Aug 2025 22:08:32 +0800
Subject: [PATCH 008/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90bpm=20=E5=B7=A5?=
=?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=AE=A1=E6=89=B9=E4=BA=BA=E8=87=AA?=
=?UTF-8?q?=E9=80=89=E6=97=B6=EF=BC=8C=E7=9B=B8=E5=90=8C=E8=8A=82=E7=82=B9?=
=?UTF-8?q?=E5=85=B1=E4=BA=AB=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../detail/ProcessInstanceOperationButton.vue | 23 ++++++++++++
.../detail/ProcessInstanceTimeline.vue | 35 ++++++++++++++-----
2 files changed, 49 insertions(+), 9 deletions(-)
diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue b/src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue
index 7a5559386..1b7d5c73d 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceOperationButton.vue
@@ -51,8 +51,10 @@
>
@@ -571,6 +573,7 @@ const approveFormRef = ref()
const signRef = ref()
const approveSignFormRef = ref()
const nextAssigneesActivityNode = ref([]) // 下一个审批节点信息
+const nextAssigneesTimelineRef = ref() // 下一个节点审批人时间线组件的引用
const approveReasonForm = reactive({
reason: '',
signPicUrl: '',
@@ -717,6 +720,10 @@ const closePopover = (type: string, formRef: FormInstance | undefined) => {
}
popOverVisible.value[type] = false
nextAssigneesActivityNode.value = []
+ // 清理 Timeline 组件中的自定义审批人数据
+ if (nextAssigneesTimelineRef.value) {
+ nextAssigneesTimelineRef.value.batchSetCustomApproveUsers({})
+ }
}
/** 流程通过时,根据表单变量查询新的流程节点,判断下一个节点类型是否为自选审批人 */
@@ -729,6 +736,7 @@ const initNextAssigneesFormField = async () => {
processVariablesStr: JSON.stringify(variables)
})
if (data && data.length > 0) {
+ const customApproveUsersData: Record = {} // 用于收集需要设置到 Timeline 组件的自定义审批人数据
data.forEach((node: any) => {
if (
// 情况一:当前节点没有审批人,并且是发起人自选
@@ -740,7 +748,18 @@ const initNextAssigneesFormField = async () => {
) {
nextAssigneesActivityNode.value.push(node)
}
+
+ // 如果节点有 candidateUsers,设置到 customApproveUsers 中
+ if (node.candidateUsers && node.candidateUsers.length > 0) {
+ customApproveUsersData[node.id] = node.candidateUsers
+ }
})
+
+ // 将 candidateUsers 设置到 Timeline 组件中
+ await nextTick() // 等待下一个 tick,确保 Timeline 组件已经渲染
+ if (nextAssigneesTimelineRef.value && Object.keys(customApproveUsersData).length > 0) {
+ nextAssigneesTimelineRef.value.batchSetCustomApproveUsers(customApproveUsersData)
+ }
}
}
@@ -803,6 +822,10 @@ const handleAudit = async (pass: boolean, formRef: FormInstance | undefined) =>
await TaskApi.approveTask(data)
popOverVisible.value.approve = false
nextAssigneesActivityNode.value = []
+ // 清理 Timeline 组件中的自定义审批人数据
+ if (nextAssigneesTimelineRef.value) {
+ nextAssigneesTimelineRef.value.batchSetCustomApproveUsers({})
+ }
message.success('审批通过成功')
} else {
// 审批不通过数据
diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
index 8f55c6c4b..91f333e8e 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceTimeline.vue
@@ -15,7 +15,7 @@
>
@@ -55,13 +55,13 @@
class="flex flex-wrap gap2 items-center"
v-if="
isEmpty(activity.tasks) &&
- isEmpty(activity.candidateUsers) &&
- (CandidateStrategy.START_USER_SELECT === activity.candidateStrategy ||
- CandidateStrategy.APPROVE_USER_SELECT === activity.candidateStrategy)
+ ((CandidateStrategy.START_USER_SELECT === activity.candidateStrategy &&
+ isEmpty(activity.candidateUsers)) ||
+ (props.enableApproveUserSelect &&
+ CandidateStrategy.APPROVE_USER_SELECT === activity.candidateStrategy))
"
>
-
@@ -165,7 +165,7 @@
@@ -198,13 +198,15 @@ import transactorSvg from '@/assets/svgs/bpm/transactor.svg'
import childProcessSvg from '@/assets/svgs/bpm/child-process.svg'
defineOptions({ name: 'BpmProcessInstanceTimeline' })
-withDefaults(
+const props = withDefaults(
defineProps<{
activityNodes: ProcessInstanceApi.ApprovalNodeInfo[] // 审批节点信息
showStatusIcon?: boolean // 是否显示头像右下角状态图标
+ enableApproveUserSelect?: boolean // 是否开启审批人自选功能
}>(),
{
- showStatusIcon: true // 默认值为 true
+ showStatusIcon: true, // 默认值为 true
+ enableApproveUserSelect: false // 默认值为 false
}
)
const { push } = useRouter() // 路由
@@ -341,4 +343,19 @@ const handleChildProcess = (activity: any) => {
}
})
}
+
+/** 设置自定义审批人 */
+const setCustomApproveUsers = (activityId: string, users: any[]) => {
+ customApproveUsers.value[activityId] = users || []
+}
+
+/** 批量设置多个节点的自定义审批人 */
+const batchSetCustomApproveUsers = (data: Record
) => {
+ Object.keys(data).forEach((activityId) => {
+ customApproveUsers.value[activityId] = data[activityId] || []
+ })
+}
+
+// 暴露方法给父组件
+defineExpose({ setCustomApproveUsers, batchSetCustomApproveUsers })
From dd6c7481f8a16d71cece00f6679eb3722ec752d0 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 3 Aug 2025 15:29:04 +0800
Subject: [PATCH 009/161] =?UTF-8?q?fix=EF=BC=9A=E3=80=90mall=20=E5=95=86?=
=?UTF-8?q?=E5=9F=8E=E3=80=91=E5=BA=97=E9=93=BA=E8=A3=85=E4=BF=AE=E6=97=B6?=
=?UTF-8?q?=EF=BC=8Cforce-fallback=20=E6=8B=96=E6=8B=BD=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=EF=BC=8Chttps://t.zsxq.com/ue8Qv?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/DiyEditor/components/ComponentLibrary.vue | 2 +-
src/components/DiyEditor/index.vue | 2 +-
src/components/Draggable/index.vue | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue
index fdb0b1de3..06f231285 100644
--- a/src/components/DiyEditor/components/ComponentLibrary.vue
+++ b/src/components/DiyEditor/components/ComponentLibrary.vue
@@ -17,7 +17,7 @@
:group="{ name: 'component', pull: 'clone', put: false }"
:clone="handleCloneComponent"
:animation="200"
- :force-fallback="true"
+ :force-fallback="false"
>
diff --git a/src/components/DiyEditor/index.vue b/src/components/DiyEditor/index.vue
index 940ad664b..fa23a4d0f 100644
--- a/src/components/DiyEditor/index.vue
+++ b/src/components/DiyEditor/index.vue
@@ -73,7 +73,7 @@
拖动左上角的小圆点可对其排序
Date: Mon, 4 Aug 2025 12:53:45 +0800
Subject: [PATCH 010/161] =?UTF-8?q?feat:=E3=80=90system=20=E7=B3=BB?=
=?UTF-8?q?=E7=BB=9F=E5=8A=9F=E8=83=BD=E3=80=91=E4=BC=98=E5=8C=96=E9=AA=8C?=
=?UTF-8?q?=E8=AF=81=E7=A0=81=E7=9A=84=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/Verify/VerifyPictureWord.vue | 166 +++++++++---------
src/views/Login/SocialLogin.vue | 2 +-
.../Login/components/ForgetPasswordForm.vue | 2 +-
src/views/Login/components/LoginForm.vue | 10 +-
src/views/Login/components/RegisterForm.vue | 2 +-
5 files changed, 90 insertions(+), 92 deletions(-)
diff --git a/src/components/Verifition/src/Verify/VerifyPictureWord.vue b/src/components/Verifition/src/Verify/VerifyPictureWord.vue
index f996f648c..e1725f894 100644
--- a/src/components/Verifition/src/Verify/VerifyPictureWord.vue
+++ b/src/components/Verifition/src/Verify/VerifyPictureWord.vue
@@ -26,18 +26,22 @@
:style="{
width: setSize.imgWidth,
color: barAreaColor,
- 'border-color': barAreaBorderColor,
+ 'border-color': barAreaBorderColor
// 'line-height': barSize.height
}"
class="verify-bar-area"
>
{{ text }}
-
+
-
+
@@ -46,13 +50,13 @@
* VerifyPictureWord
* @description 输入文字
* */
-import { resetSize } from '../utils/util';
-import { aesEncrypt } from '../utils/ase';
-import { getCode, reqCheck } from '@/api/login';
-import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue';
+import { resetSize } from '../utils/util'
+import { aesEncrypt } from '../utils/ase'
+import { getCode, reqCheck } from '@/api/login'
+import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue'
const props = defineProps({
- //弹出式pop,固定fixed
+ // 弹出式 pop,固定 fixed
mode: {
type: String,
default: 'fixed'
@@ -60,7 +64,7 @@ const props = defineProps({
captchaType: {
type: String
},
- //间隔
+ // 间隔
vSpace: {
type: Number,
default: 5
@@ -71,7 +75,7 @@ const props = defineProps({
return {
width: '310px',
height: '155px'
- };
+ }
}
},
barSize: {
@@ -80,20 +84,18 @@ const props = defineProps({
return {
width: '310px',
height: '40px'
- };
+ }
}
}
-});
-
-const { t } = useI18n();
-const { mode, captchaType } = toRefs(props);
-const { proxy } = getCurrentInstance();
-let secretKey = ref(''), //后端返回的ase加密秘钥
+})
+const { t } = useI18n()
+const { mode, captchaType } = toRefs(props)
+const { proxy } = getCurrentInstance()
+let secretKey = ref(''), // 后端返回的ase加密秘钥
userCode = ref(''), // 用户输入的验证码 暂存至pointJson,无需加密
-
- verificationCodeImg = ref(''), //后端获取到的背景图片
- backToken = ref(''), //后端返回的token值
+ verificationCodeImg = ref(''), // 后端获取到的背景图片
+ backToken = ref(''), // 后端返回的token值
setSize = reactive({
imgHeight: 0,
imgWidth: 0,
@@ -104,91 +106,91 @@ let secretKey = ref(''), //后端返回的ase加密秘钥
barAreaColor = ref('#000'),
barAreaBorderColor = ref('#ddd'),
showRefresh = ref(true),
-// bindingClick = ref(true)
- checking = ref(false);
+ // bindingClick = ref(true)
+ checking = ref(false)
const init = () => {
- //加载页面
- getPicture();
+ // 加载页面
+ getPicture()
nextTick(() => {
- let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy);
- setSize.imgHeight = imgHeight;
- setSize.imgWidth = imgWidth;
- setSize.barHeight = barHeight;
- setSize.barWidth = barWidth;
- proxy.$parent.$emit('ready', proxy);
- });
-};
+ let { imgHeight, imgWidth, barHeight, barWidth } = resetSize(proxy)
+ setSize.imgHeight = imgHeight
+ setSize.imgWidth = imgWidth
+ setSize.barHeight = barHeight
+ setSize.barWidth = barWidth
+ proxy.$parent.$emit('ready', proxy)
+ })
+}
onMounted(() => {
// 禁止拖拽
- init();
- proxy.$el.onselectstart = function() {
- return false;
- };
-});
-const canvas = ref(null);
+ init()
+ proxy.$el.onselectstart = function () {
+ return false
+ }
+})
+const canvas = ref(null)
const submit = () => {
- checking.value = true;
- //发送后端请求
- var captchaVerification = secretKey.value
+ checking.value = true
+ // 发送后端请求
+ const captchaVerification = secretKey.value
? aesEncrypt(backToken.value + '---' + userCode.value, secretKey.value)
- : backToken.value + '---' + userCode.value;
+ : backToken.value + '---' + userCode.value
let data = {
captchaType: captchaType.value,
pointJson: userCode.value,
token: backToken.value
- };
+ }
reqCheck(data).then((res) => {
- if (res.repCode == '0000') {
- barAreaColor.value = '#4cae4c';
- barAreaBorderColor.value = '#5cb85c';
- text.value = t('captcha.success');
+ if (res.repCode === '0000') {
+ barAreaColor.value = '#4cae4c'
+ barAreaBorderColor.value = '#5cb85c'
+ text.value = t('captcha.success')
// bindingClick.value = false
- if (mode.value == 'pop') {
+ if (mode.value === 'pop') {
setTimeout(() => {
- proxy.$parent.clickShow = false;
- refresh();
- }, 1500);
+ proxy.$parent.clickShow = false
+ refresh()
+ }, 1500)
}
- proxy.$parent.$emit('success', { captchaVerification });
+ proxy.$parent.$emit('success', { captchaVerification })
} else {
- proxy.$parent.$emit('error', proxy);
- barAreaColor.value = '#d9534f';
- barAreaBorderColor.value = '#d9534f';
- text.value = t('captcha.fail');
+ proxy.$parent.$emit('error', proxy)
+ barAreaColor.value = '#d9534f'
+ barAreaBorderColor.value = '#d9534f'
+ text.value = t('captcha.fail')
setTimeout(() => {
- refresh();
- }, 700);
+ refresh()
+ }, 700)
}
- checking.value = false;
- });
-};
+ checking.value = false
+ })
+}
-const refresh = async function() {
- barAreaColor.value = '#000';
- barAreaBorderColor.value = '#ddd';
- checking.value = false;
+const refresh = async function () {
+ barAreaColor.value = '#000'
+ barAreaBorderColor.value = '#ddd'
+ checking.value = false
- userCode.value = '';
+ userCode.value = ''
- await getPicture();
- showRefresh.value = true;
-};
+ await getPicture()
+ showRefresh.value = true
+}
// 请求背景图片和验证图片
const getPicture = async () => {
let data = {
captchaType: captchaType.value
- };
- const res = await getCode(data);
- if (res.repCode == '0000') {
- verificationCodeImg.value = res.repData.originalImageBase64;
- backToken.value = res.repData.token;
- secretKey.value = res.repData.secretKey;
- text.value = t('captcha.code');
- } else {
- text.value = res.repMsg;
}
-};
-
\ No newline at end of file
+ const res = await getCode(data)
+ if (res.repCode === '0000') {
+ verificationCodeImg.value = res.repData.originalImageBase64
+ backToken.value = res.repData.token
+ secretKey.value = res.repData.secretKey
+ text.value = t('captcha.code')
+ } else {
+ text.value = res.repMsg
+ }
+}
+
diff --git a/src/views/Login/SocialLogin.vue b/src/views/Login/SocialLogin.vue
index e0caace83..961f4ddb1 100644
--- a/src/views/Login/SocialLogin.vue
+++ b/src/views/Login/SocialLogin.vue
@@ -185,7 +185,7 @@ const { push } = useRouter()
const permissionStore = usePermissionStore()
const loginLoading = ref(false)
const verify = ref()
-const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
diff --git a/src/views/Login/components/ForgetPasswordForm.vue b/src/views/Login/components/ForgetPasswordForm.vue
index 0c3b2e04f..f47b2299a 100644
--- a/src/views/Login/components/ForgetPasswordForm.vue
+++ b/src/views/Login/components/ForgetPasswordForm.vue
@@ -143,7 +143,7 @@ const iconCircleCheck = useIcon({ icon: 'ep:circle-check' })
const { validForm } = useFormValid(formSmsResetPassword)
const { handleBackLogin, getLoginState, setLoginState } = useLoginState()
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.RESET_PASSWORD)
-const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
const validatePass2 = (_rule, value, callback) => {
if (value === '') {
diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue
index cb4dd429a..1bb5173d8 100644
--- a/src/views/Login/components/LoginForm.vue
+++ b/src/views/Login/components/LoginForm.vue
@@ -47,10 +47,7 @@
/>
-
+
@@ -177,8 +174,7 @@ const permissionStore = usePermissionStore()
const redirect = ref('')
const loginLoading = ref(false)
const verify = ref()
-const captchaType = ref('pictureWord') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
-// const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.LOGIN)
@@ -361,4 +357,4 @@ onMounted(() => {
cursor: pointer;
}
}
-
\ No newline at end of file
+
diff --git a/src/views/Login/components/RegisterForm.vue b/src/views/Login/components/RegisterForm.vue
index 0636a1c82..eb1f75b69 100644
--- a/src/views/Login/components/RegisterForm.vue
+++ b/src/views/Login/components/RegisterForm.vue
@@ -119,7 +119,7 @@ const permissionStore = usePermissionStore()
const redirect = ref('')
const loginLoading = ref(false)
const verify = ref()
-const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字
+const captchaType = ref('blockPuzzle') // blockPuzzle 滑块 clickWord 点击文字 pictureWord 文字验证码
const getShow = computed(() => unref(getLoginState) === LoginStateEnum.REGISTER)
From ff7beb6db2ce31dcccb0cdff4b508d679d63ec58 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Tue, 5 Aug 2025 21:12:33 +0800
Subject: [PATCH 011/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90system=20?=
=?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=8A=9F=E8=83=BD=E3=80=91=E9=82=AE=E7=AE=B1?=
=?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8A=84=E9=80=81=E3=80=81=E5=AF=86=E9=80=81?=
=?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E5=A4=9A=E4=B8=AA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/system/mail/log/index.ts | 4 +-
src/api/system/mail/template/index.ts | 9 +++-
src/views/system/mail/log/MailLogDetail.vue | 28 +++++++++++--
src/views/system/mail/log/index.vue | 42 +++++++++++++++----
.../mail/template/MailTemplateSendForm.vue | 31 +++++++++++---
5 files changed, 94 insertions(+), 20 deletions(-)
diff --git a/src/api/system/mail/log/index.ts b/src/api/system/mail/log/index.ts
index d891db07c..409ced631 100644
--- a/src/api/system/mail/log/index.ts
+++ b/src/api/system/mail/log/index.ts
@@ -4,7 +4,9 @@ export interface MailLogVO {
id: number
userId: number
userType: number
- toMail: string
+ toMails: string[]
+ ccMails?: string[]
+ bccMails?: string[]
accountId: number
fromMail: string
templateId: number
diff --git a/src/api/system/mail/template/index.ts b/src/api/system/mail/template/index.ts
index c6dae688a..6e1d083f2 100644
--- a/src/api/system/mail/template/index.ts
+++ b/src/api/system/mail/template/index.ts
@@ -14,7 +14,9 @@ export interface MailTemplateVO {
}
export interface MailSendReqVO {
- mail: string
+ toMails: string[]
+ ccMails?: string[]
+ bccMails?: string[]
templateCode: string
templateParams: Map
}
@@ -46,7 +48,10 @@ export const deleteMailTemplate = async (id: number) => {
// 批量删除邮件模版
export const deleteMailTemplateList = async (ids: number[]) => {
- return await request.delete({ url: '/system/mail-template/delete-list', params: { ids: ids.join(',') } })
+ return await request.delete({
+ url: '/system/mail-template/delete-list',
+ params: { ids: ids.join(',') }
+ })
}
// 发送邮件
diff --git a/src/views/system/mail/log/MailLogDetail.vue b/src/views/system/mail/log/MailLogDetail.vue
index a7ec449bb..37d757a3d 100644
--- a/src/views/system/mail/log/MailLogDetail.vue
+++ b/src/views/system/mail/log/MailLogDetail.vue
@@ -13,12 +13,34 @@
{{ detailData.templateNickname }}
-
- {{ detailData.toMail }}
+
({{ detailData.userId }})
+ 无
+
+
+
+
+ 收件:
+
+ {{ mail }}、
+
+
+
+ 抄送:
+
+ {{ mail }}、
+
+
+
+ 密送:
+
+ {{ mail }}、
+
+
+
{{ detailData.templateTitle }}
@@ -58,7 +80,7 @@ defineOptions({ name: 'SystemMailLogDetail' })
const dialogVisible = ref(false) // 弹窗的是否展示
const detailLoading = ref(false) // 表单的加载中
const detailData = ref() // 详情数据
-const accountList = ref([]) // 邮箱账号列表
+const accountList = ref([]) // 邮箱账号列表
/** 打开弹窗 */
const open = async (data: MailLogApi.MailLogVO) => {
diff --git a/src/views/system/mail/log/index.vue b/src/views/system/mail/log/index.vue
index dd915e52f..1bd794f59 100644
--- a/src/views/system/mail/log/index.vue
+++ b/src/views/system/mail/log/index.vue
@@ -119,12 +119,36 @@
width="180"
:formatter="dateFormatter"
/>
-
+
- {{ scope.row.toMail }}
- {{ '(' + scope.row.userId + ')' }}
+
{{ '(' + scope.row.userId + ')' }}
+
+ -
+
+
+
+
+
+
+ 收件:
+
+ {{ mail }}、
+
+
+
+ 抄送:
+
+ {{ mail }}、
+
+
+
+ 密送:
+
+ {{ mail }}、
+
+
@@ -185,15 +209,15 @@ const queryParams = reactive({
pageNo: 1,
pageSize: 10,
toMail: '',
- accountId: null,
- templateId: null,
- sendStatus: null,
- userId: null,
- userType: null,
+ accountId: undefined,
+ templateId: undefined,
+ sendStatus: undefined,
+ userId: undefined,
+ userType: undefined,
sendTime: []
})
const exportLoading = ref(false) // 导出的加载中
-const accountList = ref([]) // 邮箱账号列表
+const accountList = ref([]) // 邮箱账号列表
/** 查询列表 */
const getList = async () => {
diff --git a/src/views/system/mail/template/MailTemplateSendForm.vue b/src/views/system/mail/template/MailTemplateSendForm.vue
index 6e4c918e6..3decb448c 100644
--- a/src/views/system/mail/template/MailTemplateSendForm.vue
+++ b/src/views/system/mail/template/MailTemplateSendForm.vue
@@ -10,8 +10,26 @@
-
-
+
+
+
+
+
+
+
+
{
formData.value = {
content: '',
params: {},
- mail: '',
+ toMails: [],
+ ccMails: [],
+ bccMails: [],
templateCode: '',
templateParams: new Map()
}
From 47863e8d22d6a8193089d10cb18cb6f99dbc504f Mon Sep 17 00:00:00 2001
From: LesanOuO <1960681385@qq.com>
Date: Wed, 6 Aug 2025 19:25:12 +0800
Subject: [PATCH 012/161] =?UTF-8?q?fix:=20=E4=BD=BF=E7=94=A8form-create?=
=?UTF-8?q?=E5=86=85=E7=BD=AE=E6=96=B9=E6=B3=95=E4=BF=AE=E5=A4=8D=E5=87=BD?=
=?UTF-8?q?=E6=95=B0=E6=96=B9=E6=B3=95JSON=E8=A7=A3=E6=9E=90=E5=A4=B1?=
=?UTF-8?q?=E8=B4=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/utils/formCreate.ts | 153 ++--------------------------------------
1 file changed, 5 insertions(+), 148 deletions(-)
diff --git a/src/utils/formCreate.ts b/src/utils/formCreate.ts
index 19862f571..f3f005ea9 100644
--- a/src/utils/formCreate.ts
+++ b/src/utils/formCreate.ts
@@ -2,6 +2,7 @@
* 针对 https://github.com/xaboy/form-create-designer 封装的工具类
*/
import { isRef } from 'vue'
+import formCreate from '@form-create/element-ui'
// 编码表单 Conf
export const encodeConf = (designerRef: object) => {
@@ -24,7 +25,7 @@ export const encodeFields = (designerRef: object) => {
export const decodeFields = (fields: string[]) => {
const rule: object[] = []
fields.forEach((item) => {
- rule.push(JSON.parse(item))
+ rule.push(formCreate.parseJson(item))
})
return rule
}
@@ -32,7 +33,7 @@ export const decodeFields = (fields: string[]) => {
// 设置表单的 Conf 和 Fields,适用 FcDesigner 场景
export const setConfAndFields = (designerRef: object, conf: string, fields: string) => {
// @ts-ignore
- designerRef.value.setOption(JSON.parse(conf))
+ designerRef.value.setOption(formCreate.parseJson(conf))
// @ts-ignore
designerRef.value.setRule(decodeFields(fields))
}
@@ -49,154 +50,10 @@ export const setConfAndFields2 = (
detailPreview = detailPreview.value
}
- // 修复所有函数类型(解决设计器保存后函数变成字符串的问题)。例如说:
- // https://t.zsxq.com/rADff
- // https://t.zsxq.com/ZfbGt
- // https://t.zsxq.com/mHOoj
- // https://t.zsxq.com/BSylB
- const option = JSON.parse(conf)
- const rule = decodeFields(fields)
- // 🔧 修复所有函数类型 - 解决设计器保存后函数变成字符串的问题
- const fixFunctions = (obj: any) => {
- if (obj && typeof obj === 'object') {
- Object.keys(obj).forEach((key) => {
- // 检查是否是函数相关的属性
- if (isFunctionProperty(key)) {
- // 如果不是函数类型,重新构建为函数
- if (typeof obj[key] !== 'function') {
- obj[key] = createDefaultFunction(key)
- }
- } else if (typeof obj[key] === 'object' && obj[key] !== null) {
- // 递归处理嵌套对象
- fixFunctions(obj[key])
- }
- })
- }
- }
- // 判断是否是函数属性
- const isFunctionProperty = (key: string): boolean => {
- const functionKeys = [
- 'beforeFetch', // 请求前处理
- 'afterFetch', // 请求后处理
- 'onSubmit', // 表单提交
- 'onReset', // 表单重置
- 'onChange', // 值变化
- 'onInput', // 输入事件
- 'onClick', // 点击事件
- 'onFocus', // 获取焦点
- 'onBlur', // 失去焦点
- 'onMounted', // 组件挂载
- 'onCreated', // 组件创建
- 'onReload', // 重新加载
- 'remoteMethod', // 远程搜索方法
- 'parseFunc', // 解析函数
- 'validator', // 验证器
- 'asyncValidator', // 异步验证器
- 'formatter', // 格式化函数
- 'parser', // 解析函数
- 'beforeUpload', // 上传前处理
- 'onSuccess', // 成功回调
- 'onError', // 错误回调
- 'onProgress', // 进度回调
- 'onPreview', // 预览回调
- 'onRemove', // 移除回调
- 'onExceed', // 超出限制回调
- 'filterMethod', // 过滤方法
- 'sortMethod', // 排序方法
- 'loadData', // 加载数据
- 'renderContent', // 渲染内容
- 'render' // 渲染函数
- ]
- // 检查是否以函数相关前缀开头
- const functionPrefixes = ['on', 'before', 'after', 'handle']
- return functionKeys.includes(key) || functionPrefixes.some((prefix) => key.startsWith(prefix))
- }
- // 根据函数名创建默认函数
- const createDefaultFunction = (key: string): Function => {
- switch (key) {
- case 'beforeFetch':
- return (config: any) => {
- // 添加 Token 认证头。例如说:
- // https://t.zsxq.com/hK3FO
- const token = localStorage.getItem('token')
- if (token) {
- config.headers = {
- ...config.headers,
- Authorization: 'Bearer ' + token
- }
- }
- // 添加通用请求头
- config.headers = {
- ...config.headers,
- 'Content-Type': 'application/json',
- 'X-Requested-With': 'XMLHttpRequest'
- }
- // 添加时间戳防止缓存
- config.params = {
- ...config.params,
- _t: Date.now()
- }
- return config
- }
- case 'afterFetch':
- return (data: any) => {
- return data
- }
- case 'onSubmit':
- return (_formData: any) => {
- return true
- }
- case 'onReset':
- return () => {
- return true
- }
- case 'onChange':
- return (_value: any, _oldValue: any) => {}
- case 'remoteMethod':
- return (query: string) => {
- console.log('remoteMethod被调用:', query)
- }
- case 'parseFunc':
- return (data: any) => {
- // 默认解析逻辑:如果是数组直接返回,否则尝试获取list属性
- if (Array.isArray(data)) {
- return data
- }
- return data?.list || data?.data || []
- }
- case 'validator':
- return (_rule: any, _value: any, callback: Function) => {
- callback()
- }
- case 'beforeUpload':
- return (_file: any) => {
- return true
- }
- default:
- // 通用默认函数
- return (...args: any[]) => {
- // 对于事件处理函数,返回true表示继续执行
- if (key.startsWith('on') || key.startsWith('handle')) {
- return true
- }
- // 对于其他函数,返回第一个参数(通常是数据传递)
- return args[0]
- }
- }
- }
- // 修复 option 中的所有函数
- fixFunctions(option)
- // 修复 rule 中的所有函数(包括组件的 props)
- if (Array.isArray(rule)) {
- rule.forEach((item: any) => {
- fixFunctions(item)
- })
- }
-
// @ts-ignore
- detailPreview.option = option
+ detailPreview.option = formCreate.parseJson(conf)
// @ts-ignore
- detailPreview.rule = rule
+ detailPreview.rule = decodeFields(fields)
if (value) {
// @ts-ignore
From 9908adbed9a277c3b3de22cdfc8f998e58dbd02e Mon Sep 17 00:00:00 2001
From: wuKong
Date: Sat, 9 Aug 2025 00:45:13 +0800
Subject: [PATCH 013/161] =?UTF-8?q?fix(mp):=20=E4=BF=AE=E5=A4=8D=E7=94=A8?=
=?UTF-8?q?=E6=88=B7=E5=A4=B4=E5=83=8F=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 将用户头像获取逻辑从 avatar 字段改为 headImageUrl 字段
-确保在获取到的用户信息中,如果有头像图片链接,则使用该链接
- 如果没有头像图片链接,则保留原有的头像
---
src/views/mp/components/wx-msg/main.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/views/mp/components/wx-msg/main.vue b/src/views/mp/components/wx-msg/main.vue
index 8b7cc3a2b..333541076 100644
--- a/src/views/mp/components/wx-msg/main.vue
+++ b/src/views/mp/components/wx-msg/main.vue
@@ -82,7 +82,7 @@ const msgDivRef = ref(null) // 消息显示窗口ref,
onMounted(async () => {
const data = await getUser(props.userId)
user.nickname = data.nickname?.length > 0 ? data.nickname : user.nickname
- user.avatar = user.avatar?.length > 0 ? data.avatar : user.avatar
+ user.avatar = data.headImageUrl?.length > 0 ? data.headImageUrl : user.avatar
accountId.value = data.accountId
reply.value.accountId = data.accountId
From 72d6fb587606fc838582f8c6e3a0d45677c63fc5 Mon Sep 17 00:00:00 2001
From: wuKong
Date: Sat, 9 Aug 2025 00:47:59 +0800
Subject: [PATCH 014/161] =?UTF-8?q?feat(mp):=20=E6=B7=BB=E5=8A=A0=E6=89=AB?=
=?UTF-8?q?=E7=A0=81=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86-=20=E5=9C=A8=20Me?=
=?UTF-8?q?ssageTable=20=E7=BB=84=E4=BB=B6=E4=B8=AD=E5=A2=9E=E5=8A=A0?=
=?UTF-8?q?=E4=BA=86=E5=AF=B9=E6=89=AB=E7=A0=81=E4=BA=8B=E4=BB=B6=E7=9A=84?=
=?UTF-8?q?=E5=A4=84=E7=90=86=20-=20=E5=BD=93=E6=B6=88=E6=81=AF=E7=B1=BB?=
=?UTF-8?q?=E5=9E=8B=E4=B8=BA=20Event=20=E4=B8=94=E4=BA=8B=E4=BB=B6?=
=?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=BA=20SCAN=20=E6=97=B6=EF=BC=8C?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E7=BB=BF=E8=89=B2=E7=9A=84"=E6=89=AB?=
=?UTF-8?q?=E7=A0=81"=E6=A0=87=E7=AD=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/mp/message/MessageTable.vue | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/views/mp/message/MessageTable.vue b/src/views/mp/message/MessageTable.vue
index ebc3d749e..185bdec58 100644
--- a/src/views/mp/message/MessageTable.vue
+++ b/src/views/mp/message/MessageTable.vue
@@ -59,6 +59,9 @@
>
选择地理位置
+
+ 扫码
+
未知事件类型
From 5745cb6f331cd9699cc39c1e8fac1f8bb69c7259 Mon Sep 17 00:00:00 2001
From: wuKong
Date: Sat, 9 Aug 2025 00:48:50 +0800
Subject: [PATCH 015/161] =?UTF-8?q?feat(mp/user):=20=E6=B7=BB=E5=8A=A0?=
=?UTF-8?q?=E7=94=A8=E6=88=B7=E5=A4=B4=E5=83=8F=E5=88=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在用户列表中增加用户头像列
- 使用 el-avatar 组件显示用户头像- 调整表格列的宽度以适应新内容
---
src/views/mp/user/index.vue | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/views/mp/user/index.vue b/src/views/mp/user/index.vue
index 6147351aa..c70761f2c 100644
--- a/src/views/mp/user/index.vue
+++ b/src/views/mp/user/index.vue
@@ -52,6 +52,11 @@
+
+
+
+
+
From 544fc8127d86e9b56891da6a15b023907408a2c0 Mon Sep 17 00:00:00 2001
From: wuKong
Date: Sat, 9 Aug 2025 00:49:37 +0800
Subject: [PATCH 016/161] =?UTF-8?q?feat(mp):=20=E6=B7=BB=E5=8A=A0=20SCAN?=
=?UTF-8?q?=20=E4=BA=8B=E4=BB=B6=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 MsgEvent 组件中增加了对 SCAN 事件的处理- 添加了显示"扫码"标签的功能
---
src/views/mp/components/wx-msg/components/MsgEvent.vue | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/views/mp/components/wx-msg/components/MsgEvent.vue b/src/views/mp/components/wx-msg/components/MsgEvent.vue
index 77beda48a..32eaa09f3 100644
--- a/src/views/mp/components/wx-msg/components/MsgEvent.vue
+++ b/src/views/mp/components/wx-msg/components/MsgEvent.vue
@@ -34,6 +34,9 @@
选择地理位置
+
+ 扫码
+
未知事件类型
From 8deb5b417f4ce33e7efd4e9cf8267f5820678f8c Mon Sep 17 00:00:00 2001
From: wuKong
Date: Sat, 9 Aug 2025 00:50:47 +0800
Subject: [PATCH 017/161] =?UTF-8?q?fix(mp):=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?=
=?UTF-8?q?=E4=BF=A1=E5=9B=BE=E6=96=87=E6=B6=88=E6=81=AF=E5=9B=BE=E7=89=87?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 在 wx-news 组件中,为 el-image 和 img 标签添加了备用图片属性
- 使用 article.thumbUrl作为 article.picUrl 的备用值,确保在 picUrl 为空时仍能显示图片
---
src/views/mp/components/wx-news/main.vue | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/views/mp/components/wx-news/main.vue b/src/views/mp/components/wx-news/main.vue
index 154291b3d..53b99bb18 100644
--- a/src/views/mp/components/wx-news/main.vue
+++ b/src/views/mp/components/wx-news/main.vue
@@ -13,7 +13,7 @@
@@ -29,7 +29,7 @@
{{ article.title }}
-
![]()
+
From 3f43475c34f5b58d4242ce3a1ad1a5d91531a38d Mon Sep 17 00:00:00 2001
From: puhui999
Date: Sat, 9 Aug 2025 12:43:45 +0800
Subject: [PATCH 018/161] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=89=B9?=
=?UTF-8?q?=E9=87=8F=E5=88=A0=E9=99=A4=E5=90=8E=20checkedIds=20=E6=9C=AA?=
=?UTF-8?q?=E9=87=8D=E7=BD=AE=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/infra/codegen/index.vue | 1 +
src/views/infra/config/index.vue | 1 +
src/views/infra/dataSourceConfig/index.vue | 1 +
src/views/infra/demo/demo01/index.vue | 3 ++-
.../infra/demo/demo03/erp/components/Demo03CourseList.vue | 3 ++-
src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue | 3 ++-
src/views/infra/demo/demo03/erp/index.vue | 3 ++-
src/views/infra/demo/demo03/inner/index.vue | 1 +
src/views/infra/demo/demo03/normal/index.vue | 3 ++-
src/views/infra/file/index.vue | 1 +
src/views/infra/fileConfig/index.vue | 1 +
src/views/infra/job/index.vue | 1 +
src/views/system/dept/index.vue | 1 +
src/views/system/dict/data/index.vue | 1 +
src/views/system/dict/index.vue | 1 +
src/views/system/mail/account/index.vue | 1 +
src/views/system/mail/template/index.vue | 1 +
src/views/system/notice/index.vue | 1 +
src/views/system/notify/template/index.vue | 1 +
src/views/system/oauth2/client/index.vue | 1 +
src/views/system/post/index.vue | 1 +
src/views/system/role/index.vue | 1 +
src/views/system/sms/channel/index.vue | 1 +
src/views/system/sms/template/index.vue | 1 +
src/views/system/tenant/index.vue | 1 +
src/views/system/tenantPackage/index.vue | 1 +
src/views/system/user/index.vue | 1 +
27 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/src/views/infra/codegen/index.vue b/src/views/infra/codegen/index.vue
index ca68c457a..893eba969 100644
--- a/src/views/infra/codegen/index.vue
+++ b/src/views/infra/codegen/index.vue
@@ -254,6 +254,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await CodegenApi.deleteCodegenTableList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/infra/config/index.vue b/src/views/infra/config/index.vue
index de0deb897..eecc94790 100644
--- a/src/views/infra/config/index.vue
+++ b/src/views/infra/config/index.vue
@@ -228,6 +228,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await ConfigApi.deleteConfigList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/infra/dataSourceConfig/index.vue b/src/views/infra/dataSourceConfig/index.vue
index 9bde09e5f..2076d6376 100644
--- a/src/views/infra/dataSourceConfig/index.vue
+++ b/src/views/infra/dataSourceConfig/index.vue
@@ -122,6 +122,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await DataSourceConfigApi.deleteDataSourceConfigList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/infra/demo/demo01/index.vue b/src/views/infra/demo/demo01/index.vue
index fc0122320..82adc2843 100644
--- a/src/views/infra/demo/demo01/index.vue
+++ b/src/views/infra/demo/demo01/index.vue
@@ -219,7 +219,8 @@ const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
- await Demo01ContactApi.deleteDemo01ContactList(checkedIds.value);
+ await Demo01ContactApi.deleteDemo01ContactList(checkedIds.value)
+ checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch {}
diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue
index d0c6b66f4..4d45bac9f 100644
--- a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue
+++ b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue
@@ -149,7 +149,8 @@ const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
- await Demo03StudentApi.deleteDemo03CourseList(checkedIds.value);
+ await Demo03StudentApi.deleteDemo03CourseList(checkedIds.value)
+ checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch {}
diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue
index 3fed91f15..cb516f43a 100644
--- a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue
+++ b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue
@@ -149,7 +149,8 @@ const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
- await Demo03StudentApi.deleteDemo03GradeList(checkedIds.value);
+ await Demo03StudentApi.deleteDemo03GradeList(checkedIds.value)
+ checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch {}
diff --git a/src/views/infra/demo/demo03/erp/index.vue b/src/views/infra/demo/demo03/erp/index.vue
index 77dff0925..e5649d0a3 100644
--- a/src/views/infra/demo/demo03/erp/index.vue
+++ b/src/views/infra/demo/demo03/erp/index.vue
@@ -234,7 +234,8 @@ const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
- await Demo03StudentApi.deleteDemo03StudentList(checkedIds.value);
+ await Demo03StudentApi.deleteDemo03StudentList(checkedIds.value)
+ checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch {}
diff --git a/src/views/infra/demo/demo03/inner/index.vue b/src/views/infra/demo/demo03/inner/index.vue
index c58ec39d4..30ddc764f 100644
--- a/src/views/infra/demo/demo03/inner/index.vue
+++ b/src/views/infra/demo/demo03/inner/index.vue
@@ -230,6 +230,7 @@ const handleDeleteBatch = async () => {
// 删除的二次确认
await message.delConfirm()
await Demo03StudentApi.deleteDemo03StudentList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
await getList()
} catch {}
diff --git a/src/views/infra/demo/demo03/normal/index.vue b/src/views/infra/demo/demo03/normal/index.vue
index 5c3ebf4da..f64e21ca3 100644
--- a/src/views/infra/demo/demo03/normal/index.vue
+++ b/src/views/infra/demo/demo03/normal/index.vue
@@ -219,7 +219,8 @@ const handleDeleteBatch = async () => {
try {
// 删除的二次确认
await message.delConfirm()
- await Demo03StudentApi.deleteDemo03StudentList(checkedIds.value);
+ await Demo03StudentApi.deleteDemo03StudentList(checkedIds.value)
+ checkedIds.value = [];
message.success(t('common.delSuccess'))
await getList();
} catch {}
diff --git a/src/views/infra/file/index.vue b/src/views/infra/file/index.vue
index 20c2fed5d..901139180 100644
--- a/src/views/infra/file/index.vue
+++ b/src/views/infra/file/index.vue
@@ -217,6 +217,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await FileApi.deleteFileList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/infra/fileConfig/index.vue b/src/views/infra/fileConfig/index.vue
index 056b41f99..ab9979067 100644
--- a/src/views/infra/fileConfig/index.vue
+++ b/src/views/infra/fileConfig/index.vue
@@ -214,6 +214,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await FileConfigApi.deleteFileConfigList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/infra/job/index.vue b/src/views/infra/job/index.vue
index 9eaedc651..2090b9d83 100644
--- a/src/views/infra/job/index.vue
+++ b/src/views/infra/job/index.vue
@@ -273,6 +273,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await JobApi.deleteJobList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/dept/index.vue b/src/views/system/dept/index.vue
index c09fb85e4..3dc2ec580 100644
--- a/src/views/system/dept/index.vue
+++ b/src/views/system/dept/index.vue
@@ -204,6 +204,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await DeptApi.deleteDeptList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/dict/data/index.vue b/src/views/system/dict/data/index.vue
index 13c2af082..e84636f7d 100644
--- a/src/views/system/dict/data/index.vue
+++ b/src/views/system/dict/data/index.vue
@@ -208,6 +208,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await DictDataApi.deleteDictDataList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/dict/index.vue b/src/views/system/dict/index.vue
index ab0bd77bf..c66a1a8af 100644
--- a/src/views/system/dict/index.vue
+++ b/src/views/system/dict/index.vue
@@ -232,6 +232,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await DictTypeApi.deleteDictTypeList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/mail/account/index.vue b/src/views/system/mail/account/index.vue
index d03c270f6..51c07ed72 100644
--- a/src/views/system/mail/account/index.vue
+++ b/src/views/system/mail/account/index.vue
@@ -199,6 +199,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await MailAccountApi.deleteMailAccountList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/mail/template/index.vue b/src/views/system/mail/template/index.vue
index 71bed39c1..03ea34ede 100644
--- a/src/views/system/mail/template/index.vue
+++ b/src/views/system/mail/template/index.vue
@@ -281,6 +281,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await MailTemplateApi.deleteMailTemplateList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/notice/index.vue b/src/views/system/notice/index.vue
index 9c298dbaf..5fecbbd6e 100644
--- a/src/views/system/notice/index.vue
+++ b/src/views/system/notice/index.vue
@@ -193,6 +193,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await NoticeApi.deleteNoticeList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/notify/template/index.vue b/src/views/system/notify/template/index.vue
index 375ad14a3..086be9c95 100644
--- a/src/views/system/notify/template/index.vue
+++ b/src/views/system/notify/template/index.vue
@@ -245,6 +245,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await NotifyTemplateApi.deleteNotifyTemplateList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/oauth2/client/index.vue b/src/views/system/oauth2/client/index.vue
index 0e7168ef1..c75475b25 100644
--- a/src/views/system/oauth2/client/index.vue
+++ b/src/views/system/oauth2/client/index.vue
@@ -206,6 +206,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await ClientApi.deleteOAuth2ClientList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/post/index.vue b/src/views/system/post/index.vue
index 8ca41ab44..291d21eff 100644
--- a/src/views/system/post/index.vue
+++ b/src/views/system/post/index.vue
@@ -203,6 +203,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await PostApi.deletePostList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue
index 07ada23b1..91c68e3b1 100644
--- a/src/views/system/role/index.vue
+++ b/src/views/system/role/index.vue
@@ -270,6 +270,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await RoleApi.deleteRoleList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/sms/channel/index.vue b/src/views/system/sms/channel/index.vue
index a59b1a77e..929c3a7ce 100644
--- a/src/views/system/sms/channel/index.vue
+++ b/src/views/system/sms/channel/index.vue
@@ -224,6 +224,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await SmsChannelApi.deleteSmsChannelList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/sms/template/index.vue b/src/views/system/sms/template/index.vue
index 5f9928178..b582ed8dd 100644
--- a/src/views/system/sms/template/index.vue
+++ b/src/views/system/sms/template/index.vue
@@ -314,6 +314,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await SmsTemplateApi.deleteSmsTemplateList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/tenant/index.vue b/src/views/system/tenant/index.vue
index 8a3b86b02..295b68640 100644
--- a/src/views/system/tenant/index.vue
+++ b/src/views/system/tenant/index.vue
@@ -266,6 +266,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await TenantApi.deleteTenantList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/tenantPackage/index.vue b/src/views/system/tenantPackage/index.vue
index a031e4fea..5691bd346 100644
--- a/src/views/system/tenantPackage/index.vue
+++ b/src/views/system/tenantPackage/index.vue
@@ -196,6 +196,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await TenantPackageApi.deleteTenantPackageList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue
index d594f253b..566451728 100644
--- a/src/views/system/user/index.vue
+++ b/src/views/system/user/index.vue
@@ -362,6 +362,7 @@ const handleDeleteBatch = async () => {
await message.delConfirm()
// 发起批量删除
await UserApi.deleteUserList(checkedIds.value)
+ checkedIds.value = []
message.success(t('common.delSuccess'))
// 刷新列表
await getList()
From 2b48d60735cb6de837b90888ec362b831f54019f Mon Sep 17 00:00:00 2001
From: jason <2667446@qq.com>
Date: Sun, 10 Aug 2025 22:26:35 +0800
Subject: [PATCH 019/161] =?UTF-8?q?fix:=20[BPM=20=E5=B7=A5=E4=BD=9C?=
=?UTF-8?q?=E6=B5=81]=20=E8=A7=A6=E5=8F=91=E5=99=A8=E9=85=8D=E7=BD=AE?=
=?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../src/nodes-config/TriggerNodeConfig.vue | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue
index 2baac8d2e..c4fa63ccc 100644
--- a/src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue
+++ b/src/components/SimpleProcessDesignerV2/src/nodes-config/TriggerNodeConfig.vue
@@ -236,7 +236,7 @@
确 定
- 取 消
+ 取 消
@@ -467,6 +467,13 @@ const saveConfig = async () => {
return true
}
+/** 取消配置 */
+const cancelConfig = () => {
+ // 恢复原来的配置
+ currentNode.value.triggerSetting = originalSetting
+ closeDrawer()
+}
+
/** 获取节点展示内容 */
const getShowText = (): string => {
let showText = ''
@@ -498,7 +505,7 @@ const getShowText = (): string => {
/** 显示触发器节点配置, 由父组件传过来 */
const showTriggerNodeConfig = (node: SimpleFlowNode) => {
nodeName.value = node.name
- originalSetting = node.triggerSetting ? JSON.parse(JSON.stringify(node.triggerSetting)) : {}
+ originalSetting = cloneDeep(node.triggerSetting)
if (node.triggerSetting) {
configForm.value = {
type: node.triggerSetting.type,
From e1151738f5adfe22093e0eb6a90aa7481c4a396a Mon Sep 17 00:00:00 2001
From: jason <2667446@qq.com>
Date: Sun, 10 Aug 2025 22:47:47 +0800
Subject: [PATCH 020/161] =?UTF-8?q?perf:=20=20[BPM=20=E5=B7=A5=E4=BD=9C?=
=?UTF-8?q?=E6=B5=81]=20=E6=9B=B4=E5=A4=9A=E8=AE=BE=E7=BD=AE=EF=BC=8C?=
=?UTF-8?q?=E7=9B=91=E5=90=AC=E6=B5=81=E7=A8=8B=E8=A1=A8=E5=8D=95=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/bpm/model/form/ExtraSettings.vue | 47 ++++++----------------
src/views/bpm/model/form/index.vue | 5 +--
2 files changed, 14 insertions(+), 38 deletions(-)
diff --git a/src/views/bpm/model/form/ExtraSettings.vue b/src/views/bpm/model/form/ExtraSettings.vue
index 9c5beaf60..0f40ad66b 100644
--- a/src/views/bpm/model/form/ExtraSettings.vue
+++ b/src/views/bpm/model/form/ExtraSettings.vue
@@ -232,34 +232,6 @@ import { ProcessVariableEnum } from '@/components/SimpleProcessDesignerV2/src/co
import HttpRequestSetting from '@/components/SimpleProcessDesignerV2/src/nodes-config/components/HttpRequestSetting.vue'
const modelData = defineModel()
-const formFields = ref([])
-
-const props = defineProps({
- // 流程表单 ID
- modelFormId: {
- type: Number,
- required: false,
- default: undefined,
- }
-})
-
-
-// 监听 modelFormId 变化
-watch(
- () => props.modelFormId,
- async (newVal) => {
- if (newVal) {
- const form = await FormApi.getForm(newVal);
- formFields.value = form?.fields;
- } else {
- // 如果 modelFormId 为空,清空表单字段
- formFields.value = [];
- }
- },
- { immediate: true },
-);
-// 暴露给子组件使用
-provide('formFields', formFields)
/** 自定义 ID 流程编码 */
const timeOptions = ref([
@@ -374,10 +346,10 @@ const handleTaskAfterTriggerEnableChange = (val: boolean | string | number) => {
}
}
-/** 表单选项 */
-const formField = ref>([])
+/** 已解析表单字段 */
+const formFields = ref>([])
const formFieldOptions4Title = computed(() => {
- let cloneFormField = formField.value.map((item) => {
+ let cloneFormField = formFields.value.map((item) => {
return {
label: item.title,
value: item.field
@@ -399,7 +371,7 @@ const formFieldOptions4Title = computed(() => {
return cloneFormField
})
const formFieldOptions4Summary = computed(() => {
- return formField.value.map((item) => {
+ return formFields.value.map((item) => {
return {
label: item.title,
value: item.field
@@ -407,6 +379,11 @@ const formFieldOptions4Summary = computed(() => {
})
})
+/** 未解析的表单字段 */
+const unParsedFormFields = ref([])
+/** 暴露给子组件 HttpRequestSetting 使用 */
+provide('formFields', unParsedFormFields)
+
/** 兼容以前未配置更多设置的流程 */
const initData = () => {
if (!modelData.value.processIdRule) {
@@ -456,13 +433,15 @@ watch(
const data = await FormApi.getForm(newFormId)
const result: Array<{ field: string; title: string }> = []
if (data.fields) {
+ unParsedFormFields.value = data.fields
data.fields.forEach((fieldStr: string) => {
parseFormFields(JSON.parse(fieldStr), result)
})
}
- formField.value = result
+ formFields.value = result
} else {
- formField.value = []
+ formFields.value = []
+ unParsedFormFields.value = []
}
},
{ immediate: true }
diff --git a/src/views/bpm/model/form/index.vue b/src/views/bpm/model/form/index.vue
index 341d95684..ec8efa287 100644
--- a/src/views/bpm/model/form/index.vue
+++ b/src/views/bpm/model/form/index.vue
@@ -77,10 +77,7 @@
-
+
From 2e796b8fc730d17d11bb780979917ba33c03a5c1 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 16 Aug 2025 15:54:23 +0800
Subject: [PATCH 021/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90framework=20?=
=?UTF-8?q?=E6=A1=86=E6=9E=B6=E3=80=91=E5=A2=9E=E5=8A=A0=20api=20=E5=8A=A0?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E8=83=BD=E5=8A=9B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.env | 9 ++
src/api/login/index.ts | 8 +-
src/config/axios/service.ts | 31 +++++
src/utils/encrypt.ts | 231 ++++++++++++++++++++++++++++++++++++
types/env.d.ts | 6 +
5 files changed, 284 insertions(+), 1 deletion(-)
create mode 100644 src/utils/encrypt.ts
diff --git a/.env b/.env
index 4b0f5bf6a..791102202 100644
--- a/.env
+++ b/.env
@@ -23,3 +23,12 @@ VITE_APP_BAIDU_CODE = a1ff8825baa73c3a78eb96aa40325abc
VITE_APP_DEFAULT_LOGIN_TENANT = 芋道源码
VITE_APP_DEFAULT_LOGIN_USERNAME = admin
VITE_APP_DEFAULT_LOGIN_PASSWORD = admin123
+
+# API 加解密
+VITE_APP_API_ENCRYPT_ENABLE = true
+VITE_APP_API_ENCRYPT_HEADER = X-Api-Encrypt
+VITE_APP_API_ENCRYPT_ALGORITHM = AES
+VITE_APP_API_ENCRYPT_REQUEST_KEY = 52549111389893486934626385991395
+VITE_APP_API_ENCRYPT_RESPONSE_KEY = 96103715984234343991809655248883
+# VITE_APP_API_ENCRYPT_REQUEST_KEY = MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCls2rIpnGdYnLFgz1XU13GbNQ5DloyPpvW00FPGjqn5Z6JpK+kDtVlnkhwR87iRrE5Vf2WNqRX6vzbLSgveIQY8e8oqGCb829myjf1MuI+ZzN4ghf/7tEYhZJGPI9AbfxFqBUzm+kR3/HByAI22GLT96WM26QiMK8n3tIP/yiLswIDAQAB
+# VITE_APP_API_ENCRYPT_RESPONSE_KEY = MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOH8IfIFxL/MR9XIg1UDv5z1fGXQI93E8wrU4iPFovL/sEt9uSgSkjyidC2O7N+m7EKtoN6b1u7cEwXSkwf3kfK0jdWLSQaNpX5YshqXCBzbDfugDaxuyYrNA4/tIMs7mzZAk0APuRXB35Dmupou7Yw7TFW/7QhQmGfzeEKULQvnAgMBAAECgYAw8LqlQGyQoPv5p3gRxEMOCfgL0JzD3XBJKztiRd35RDh40Nx1ejgjW4dPioFwGiVWd2W8cAGHLzALdcQT2KDJh+T/tsd4SPmI6uSBBK6Ff2DkO+kFFcuYvfclQQKqxma5CaZOSqhgenacmgTMFeg2eKlY3symV6JlFNu/IKU42QJBAOhxAK/Eq3e61aYQV2JSguhMR3b8NXJJRroRs/QHEanksJtl+M+2qhkC9nQVXBmBkndnkU/l2tYcHfSBlAyFySMCQQD445tgm/J2b6qMQmuUGQAYDN8FIkHjeKmha+l/fv0igWm8NDlBAem91lNDIPBUzHL1X1+pcts5bjmq99YdOnhtAkAg2J8dN3B3idpZDiQbC8fd5bGPmdI/pSUudAP27uzLEjr2qrE/QPPGdwm2m7IZFJtK7kK1hKio6u48t/bg0iL7AkEAuUUs94h+v702Fnym+jJ2CHEkXvz2US8UDs52nWrZYiM1o1y4tfSHm8H8bv8JCAa9GHyriEawfBraILOmllFdLQJAQSRZy4wmlaG48MhVXodB85X+VZ9krGXZ2TLhz7kz9iuToy53l9jTkESt6L5BfBDCVdIwcXLYgK+8KFdHN5W7HQ==
\ No newline at end of file
diff --git a/src/api/login/index.ts b/src/api/login/index.ts
index 7d7d407b4..cd5986a0f 100644
--- a/src/api/login/index.ts
+++ b/src/api/login/index.ts
@@ -13,7 +13,13 @@ export interface SmsLoginVO {
// 登录
export const login = (data: UserLoginVO) => {
- return request.post({ url: '/system/auth/login', data })
+ return request.post({
+ url: '/system/auth/login',
+ data,
+ headers: {
+ isEncrypt: true
+ }
+ })
}
// 注册
diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts
index 74280a925..9214bf8ea 100644
--- a/src/config/axios/service.ts
+++ b/src/config/axios/service.ts
@@ -15,6 +15,7 @@ import errorCode from './errorCode'
import { resetRouter } from '@/router'
import { deleteUserCache } from '@/hooks/web/useCache'
+import { ApiEncrypt } from '@/utils/encrypt'
const tenantEnable = import.meta.env.VITE_APP_TENANT_ENABLE
const { result_code, base_url, request_timeout } = config
@@ -83,6 +84,20 @@ service.interceptors.request.use(
}
}
}
+ // 是否 API 加密
+ if ((config!.headers || {}).isEncrypt) {
+ try {
+ // 加密请求数据
+ if (config.data) {
+ config.data = ApiEncrypt.encryptRequest(config.data)
+ // 设置加密标识头
+ config.headers[ApiEncrypt.getEncryptHeader()] = 'true'
+ }
+ } catch (error) {
+ console.error('请求数据加密失败:', error)
+ throw error
+ }
+ }
return config
},
(error: AxiosError) => {
@@ -101,6 +116,22 @@ service.interceptors.response.use(
// 返回“[HTTP]请求没有返回值”;
throw new Error()
}
+
+ // 检查是否需要解密响应数据
+ const encryptHeader = ApiEncrypt.getEncryptHeader()
+ const isEncryptResponse =
+ response.headers[encryptHeader] === 'true' ||
+ response.headers[encryptHeader.toLowerCase()] === 'true'
+ if (isEncryptResponse && typeof data === 'string') {
+ try {
+ // 解密响应数据
+ data = ApiEncrypt.decryptResponse(data)
+ } catch (error) {
+ console.error('响应数据解密失败:', error)
+ throw new Error('响应数据解密失败: ' + (error as Error).message)
+ }
+ }
+
const { t } = useI18n()
// 未设置状态码则默认成功状态
// 二进制数据则直接返回,例如说 Excel 导出
diff --git a/src/utils/encrypt.ts b/src/utils/encrypt.ts
new file mode 100644
index 000000000..aee289e30
--- /dev/null
+++ b/src/utils/encrypt.ts
@@ -0,0 +1,231 @@
+import CryptoJS from 'crypto-js'
+import { JSEncrypt } from 'jsencrypt'
+
+/**
+ * API 加解密工具类
+ * 支持 AES 和 RSA 加密算法
+ */
+
+// 从环境变量获取配置
+const API_ENCRYPT_ENABLE = import.meta.env.VITE_APP_API_ENCRYPT_ENABLE === 'true'
+const API_ENCRYPT_HEADER = import.meta.env.VITE_APP_API_ENCRYPT_HEADER || 'X-Api-Encrypt'
+const API_ENCRYPT_ALGORITHM = import.meta.env.VITE_APP_API_ENCRYPT_ALGORITHM || 'AES'
+const API_ENCRYPT_REQUEST_KEY = import.meta.env.VITE_APP_API_ENCRYPT_REQUEST_KEY || '' // AES密钥 或 RSA公钥
+const API_ENCRYPT_RESPONSE_KEY = import.meta.env.VITE_APP_API_ENCRYPT_RESPONSE_KEY || '' // AES密钥 或 RSA私钥
+
+/**
+ * AES 加密工具类
+ */
+export class AES {
+ /**
+ * AES 加密
+ * @param data 要加密的数据
+ * @param key 加密密钥
+ * @returns 加密后的字符串
+ */
+ static encrypt(data: string, key: string): string {
+ try {
+ if (!key) {
+ throw new Error('AES 加密密钥不能为空')
+ }
+ if (key.length !== 32) {
+ throw new Error(`AES 加密密钥长度必须为 32 位,当前长度: ${key.length}`)
+ }
+
+ const keyUtf8 = CryptoJS.enc.Utf8.parse(key)
+ const encrypted = CryptoJS.AES.encrypt(data, keyUtf8, {
+ mode: CryptoJS.mode.ECB,
+ padding: CryptoJS.pad.Pkcs7
+ })
+ return encrypted.toString()
+ } catch (error) {
+ console.error('AES 加密失败:', error)
+ throw error
+ }
+ }
+
+ /**
+ * AES 解密
+ * @param encryptedData 加密的数据
+ * @param key 解密密钥
+ * @returns 解密后的字符串
+ */
+ static decrypt(encryptedData: string, key: string): string {
+ try {
+ if (!key) {
+ throw new Error('AES 解密密钥不能为空')
+ }
+ if (key.length !== 32) {
+ throw new Error(`AES 解密密钥长度必须为 32 位,当前长度: ${key.length}`)
+ }
+ if (!encryptedData) {
+ throw new Error('AES 解密数据不能为空')
+ }
+
+ const keyUtf8 = CryptoJS.enc.Utf8.parse(key)
+ const decrypted = CryptoJS.AES.decrypt(encryptedData, keyUtf8, {
+ mode: CryptoJS.mode.ECB,
+ padding: CryptoJS.pad.Pkcs7
+ })
+ const result = decrypted.toString(CryptoJS.enc.Utf8)
+ if (!result) {
+ throw new Error('AES 解密结果为空,可能是密钥错误或数据损坏')
+ }
+ return result
+ } catch (error) {
+ console.error('AES 解密失败:', error)
+ throw error
+ }
+ }
+}
+
+/**
+ * RSA 加密工具类
+ */
+export class RSA {
+ /**
+ * RSA 加密
+ * @param data 要加密的数据
+ * @param publicKey 公钥(必需)
+ * @returns 加密后的字符串
+ */
+ static encrypt(data: string, publicKey: string): string | false {
+ try {
+ if (!publicKey) {
+ throw new Error('RSA 公钥不能为空')
+ }
+
+ const encryptor = new JSEncrypt()
+ encryptor.setPublicKey(publicKey)
+ const result = encryptor.encrypt(data)
+ if (result === false) {
+ throw new Error('RSA 加密失败,可能是公钥格式错误或数据过长')
+ }
+ return result
+ } catch (error) {
+ console.error('RSA 加密失败:', error)
+ throw error
+ }
+ }
+
+ /**
+ * RSA 解密
+ * @param encryptedData 加密的数据
+ * @param privateKey 私钥(必需)
+ * @returns 解密后的字符串
+ */
+ static decrypt(encryptedData: string, privateKey: string): string | false {
+ try {
+ if (!privateKey) {
+ throw new Error('RSA 私钥不能为空')
+ }
+ if (!encryptedData) {
+ throw new Error('RSA 解密数据不能为空')
+ }
+
+ const encryptor = new JSEncrypt()
+ encryptor.setPrivateKey(privateKey)
+ const result = encryptor.decrypt(encryptedData)
+ if (result === false) {
+ throw new Error('RSA 解密失败,可能是私钥错误或数据损坏')
+ }
+ return result
+ } catch (error) {
+ console.error('RSA 解密失败:', error)
+ throw error
+ }
+ }
+}
+
+/**
+ * API 加解密主类
+ */
+export class ApiEncrypt {
+ /**
+ * 获取加密头名称
+ */
+ static getEncryptHeader(): string {
+ return API_ENCRYPT_HEADER
+ }
+
+ /**
+ * 加密请求数据
+ * @param data 要加密的数据
+ * @returns 加密后的数据
+ */
+ static encryptRequest(data: any): string {
+ if (!API_ENCRYPT_ENABLE) {
+ return data
+ }
+
+ try {
+ const jsonData = typeof data === 'string' ? data : JSON.stringify(data)
+
+ if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'AES') {
+ if (!API_ENCRYPT_REQUEST_KEY) {
+ throw new Error('AES 请求加密密钥未配置')
+ }
+ return AES.encrypt(jsonData, API_ENCRYPT_REQUEST_KEY)
+ } else if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'RSA') {
+ if (!API_ENCRYPT_REQUEST_KEY) {
+ throw new Error('RSA 公钥未配置')
+ }
+ const result = RSA.encrypt(jsonData, API_ENCRYPT_REQUEST_KEY)
+ if (result === false) {
+ throw new Error('RSA 加密失败')
+ }
+ return result
+ } else {
+ throw new Error(`不支持的加密算法: ${API_ENCRYPT_ALGORITHM}`)
+ }
+ } catch (error) {
+ console.error('请求数据加密失败:', error)
+ throw error
+ }
+ }
+
+ /**
+ * 解密响应数据
+ * @param encryptedData 加密的响应数据
+ * @returns 解密后的数据
+ */
+ static decryptResponse(encryptedData: string): any {
+ if (!API_ENCRYPT_ENABLE) {
+ return encryptedData
+ }
+
+ try {
+ let decryptedData: string | false = ''
+ if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'AES') {
+ if (!API_ENCRYPT_RESPONSE_KEY) {
+ throw new Error('AES 响应解密密钥未配置')
+ }
+ decryptedData = AES.decrypt(encryptedData, API_ENCRYPT_RESPONSE_KEY)
+ } else if (API_ENCRYPT_ALGORITHM.toUpperCase() === 'RSA') {
+ if (!API_ENCRYPT_RESPONSE_KEY) {
+ throw new Error('RSA 私钥未配置')
+ }
+ decryptedData = RSA.decrypt(encryptedData, API_ENCRYPT_RESPONSE_KEY)
+ if (decryptedData === false) {
+ throw new Error('RSA 解密失败')
+ }
+ } else {
+ throw new Error(`不支持的解密算法: ${API_ENCRYPT_ALGORITHM}`)
+ }
+
+ if (!decryptedData) {
+ throw new Error('解密结果为空')
+ }
+
+ // 尝试解析为 JSON,如果失败则返回原字符串
+ try {
+ return JSON.parse(decryptedData)
+ } catch {
+ return decryptedData
+ }
+ } catch (error) {
+ console.error('响应数据解密失败:', error)
+ throw error
+ }
+ }
+}
diff --git a/types/env.d.ts b/types/env.d.ts
index 124dd5656..17535eafc 100644
--- a/types/env.d.ts
+++ b/types/env.d.ts
@@ -26,6 +26,12 @@ interface ImportMetaEnv {
readonly VITE_SOURCEMAP: string
readonly VITE_OUT_DIR: string
readonly VITE_GOVIEW_URL: string
+ // API 加解密相关配置
+ readonly VITE_APP_API_ENCRYPT_ENABLE: string
+ readonly VITE_APP_API_ENCRYPT_HEADER: string
+ readonly VITE_APP_API_ENCRYPT_ALGORITHM: string
+ readonly VITE_APP_API_ENCRYPT_REQUEST_KEY: string
+ readonly VITE_APP_API_ENCRYPT_RESPONSE_KEY: string
}
declare global {
From e9d59f41f97fc8ab87c2efb63d26514e98529cd7 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 16 Aug 2025 17:08:09 +0800
Subject: [PATCH 022/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90framework=20?=
=?UTF-8?q?=E6=A1=86=E6=9E=B6=E3=80=91=E5=A2=9E=E5=8A=A0=20api=20=E5=8A=A0?=
=?UTF-8?q?=E8=A7=A3=E5=AF=86=E8=83=BD=E5=8A=9B=EF=BC=88=E9=BB=98=E8=AE=A4?=
=?UTF-8?q?=E7=99=BB=E5=BD=95=E5=85=88=E4=B8=8D=E5=8A=A0=E5=AF=86=EF=BC=8C?=
=?UTF-8?q?=E9=81=BF=E5=85=8D=E5=A4=A7=E5=AE=B6=E4=B8=8D=E7=90=86=E8=A7=A3?=
=?UTF-8?q?=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/login/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/api/login/index.ts b/src/api/login/index.ts
index cd5986a0f..37eb49112 100644
--- a/src/api/login/index.ts
+++ b/src/api/login/index.ts
@@ -17,7 +17,7 @@ export const login = (data: UserLoginVO) => {
url: '/system/auth/login',
data,
headers: {
- isEncrypt: true
+ isEncrypt: false
}
})
}
From 6ef3360e1c18fcb2966cdb1f2c2069af9b41211e Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 17 Aug 2025 23:57:56 +0800
Subject: [PATCH 023/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90infra=20=E5=9F=BA?=
=?UTF-8?q?=E7=A1=80=E8=AE=BE=E6=96=BD=E3=80=91=E6=96=87=E4=BB=B6=E9=85=8D?=
=?UTF-8?q?=E7=BD=AE=E6=97=B6=EF=BC=8C=E5=A2=9E=E5=8A=A0=E2=80=9C=E5=85=AC?=
=?UTF-8?q?=E5=BC=80=E8=AE=BF=E9=97=AE=E2=80=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/infra/fileConfig/index.ts | 1 +
src/views/infra/fileConfig/FileConfigForm.vue | 11 +++++++++++
2 files changed, 12 insertions(+)
diff --git a/src/api/infra/fileConfig/index.ts b/src/api/infra/fileConfig/index.ts
index 6a69a47ed..e88f825f1 100644
--- a/src/api/infra/fileConfig/index.ts
+++ b/src/api/infra/fileConfig/index.ts
@@ -12,6 +12,7 @@ export interface FileClientConfig {
accessKey?: string
accessSecret?: string
enablePathStyleAccess?: boolean
+ enablePublicAccess?: boolean
domain: string
}
diff --git a/src/views/infra/fileConfig/FileConfigForm.vue b/src/views/infra/fileConfig/FileConfigForm.vue
index 4f1cc2371..1b774ca65 100644
--- a/src/views/infra/fileConfig/FileConfigForm.vue
+++ b/src/views/infra/fileConfig/FileConfigForm.vue
@@ -93,6 +93,16 @@
禁用
+
+
+ 公开
+ 私有
+
+
@@ -146,6 +156,7 @@ const formRules = reactive({
enablePathStyleAccess: [
{ required: true, message: '是否 PathStyle 访问不能为空', trigger: 'change' }
],
+ enablePublicAccess: [{ required: true, message: '公开访问设置不能为空', trigger: 'change' }],
domain: [{ required: true, message: '自定义域名不能为空', trigger: 'blur' }]
} as FormRules
})
From 1a92b97797d048fc1d4fd33b14fa842c3af6e38a Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Tue, 19 Aug 2025 00:07:43 +0800
Subject: [PATCH 024/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90system=20?=
=?UTF-8?q?=E7=B3=BB=E7=BB=9F=E7=AE=A1=E7=90=86=E3=80=91=E7=A7=9F=E6=88=B7?=
=?UTF-8?q?=E7=AE=A1=E7=90=86=E6=97=B6=EF=BC=8C=E6=94=AF=E6=8C=81=E5=A1=AB?=
=?UTF-8?q?=E5=86=99=E5=A4=9A=E4=B8=AA=E5=9F=9F=E5=90=8D=20websites?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/system/tenant/index.ts | 1 +
src/views/system/tenant/TenantForm.vue | 15 +++++++++------
src/views/system/tenant/index.vue | 9 ++++++++-
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/src/api/system/tenant/index.ts b/src/api/system/tenant/index.ts
index c51ec7ee0..cd6e5db33 100644
--- a/src/api/system/tenant/index.ts
+++ b/src/api/system/tenant/index.ts
@@ -12,6 +12,7 @@ export interface TenantVO {
password: string
expireTime: Date
accountCount: number
+ websites: string[]
createTime: Date
}
diff --git a/src/views/system/tenant/TenantForm.vue b/src/views/system/tenant/TenantForm.vue
index 205a2cf0f..e37ab7155 100644
--- a/src/views/system/tenant/TenantForm.vue
+++ b/src/views/system/tenant/TenantForm.vue
@@ -54,8 +54,12 @@
value-format="x"
/>
-
-
+
+
@@ -97,7 +101,7 @@ const formData = ref({
contactMobile: undefined,
accountCount: undefined,
expireTime: undefined,
- website: undefined,
+ websites: [],
status: CommonStatusEnum.ENABLE,
// 新增专属
username: undefined,
@@ -105,12 +109,11 @@ const formData = ref({
})
const formRules = reactive({
name: [{ required: true, message: '租户名不能为空', trigger: 'blur' }],
- packageId: [{ required: true, message: '租户套餐不能为空', trigger: 'blur' }],
+ packageId: [{ required: true, message: '租户套���不能为空', trigger: 'blur' }],
contactName: [{ required: true, message: '联系人不能为空', trigger: 'blur' }],
status: [{ required: true, message: '租户状态不能为空', trigger: 'blur' }],
accountCount: [{ required: true, message: '账号额度不能为空', trigger: 'blur' }],
expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }],
- website: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }],
username: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }]
})
@@ -173,7 +176,7 @@ const resetForm = () => {
contactMobile: undefined,
accountCount: undefined,
expireTime: undefined,
- website: undefined,
+ websites: [],
status: CommonStatusEnum.ENABLE,
username: undefined,
password: undefined
diff --git a/src/views/system/tenant/index.vue b/src/views/system/tenant/index.vue
index 295b68640..59b38670b 100644
--- a/src/views/system/tenant/index.vue
+++ b/src/views/system/tenant/index.vue
@@ -136,7 +136,14 @@
width="180"
:formatter="dateFormatter"
/>
-
+
+
+
+ {{ website }}
+
+ -
+
+
From c93c70a3cb65015281924a5c65dfd3d07b91ed87 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Tue, 19 Aug 2025 09:16:46 +0800
Subject: [PATCH 025/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90mall=20=E5=95=86?=
=?UTF-8?q?=E5=9F=8E=E3=80=91=E5=BA=97=E9=93=BA=E9=A2=84=E8=A7=88=E6=97=B6?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20tenantId?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/mall/promotion/diy/template/decorate.vue | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/views/mall/promotion/diy/template/decorate.vue b/src/views/mall/promotion/diy/template/decorate.vue
index 85799e31a..6ebacdd34 100644
--- a/src/views/mall/promotion/diy/template/decorate.vue
+++ b/src/views/mall/promotion/diy/template/decorate.vue
@@ -34,6 +34,7 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
import { DiyComponentLibrary, PAGE_LIBS } from '@/components/DiyEditor/util' // 商城的 DIY 组件,在 DiyEditor 目录下
import { toNumber } from 'lodash-es'
import { isEmpty } from '@/utils/is'
+import { getTenantId } from '@/utils/auth'
/** 装修模板表单 */
defineOptions({ name: 'DiyTemplateDecorate' })
@@ -69,7 +70,7 @@ const getPageDetail = async (id: any) => {
formData.value = await DiyTemplateApi.getDiyTemplateProperty(id)
// 拼接手机预览链接
const domain = import.meta.env.VITE_MALL_H5_DOMAIN
- previewUrl.value = `${domain}/#/pages/index/index?templateId=${formData.value.id}`
+ previewUrl.value = `${domain}?templateId=${formData.value.id}&tenantId=${getTenantId()}`
} finally {
formLoading.value = false
}
From bd506fab0d24e565e3893f8ecb1bd089ebb77571 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8F=A3=E5=8F=A3=E5=8F=A3?= <17975121@qq.com>
Date: Wed, 20 Aug 2025 03:32:41 +0000
Subject: [PATCH 026/161] =?UTF-8?q?update=20src/store/modules/tagsView.ts.?=
=?UTF-8?q?=20=E5=BD=93=E5=AD=98=E5=9C=A8=E5=A4=9A=E4=B8=AA=E7=9B=B8?=
=?UTF-8?q?=E5=90=8C=E5=90=8D=E7=A7=B0=E7=9A=84=E6=A0=87=E7=AD=BE=E6=97=B6?=
=?UTF-8?q?=EF=BC=8C=E5=88=A0=E9=99=A4=E7=BC=93=E5=AD=98=E5=BA=94=E8=AF=A5?=
=?UTF-8?q?=E6=8E=92=E9=99=A4=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8=E7=9B=B8?=
=?UTF-8?q?=E5=90=8C=E7=9A=84=E5=90=8D=E7=A7=B0=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: 口口口 <17975121@qq.com>
---
src/store/modules/tagsView.ts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/store/modules/tagsView.ts b/src/store/modules/tagsView.ts
index 2b2d817f1..6dd509358 100644
--- a/src/store/modules/tagsView.ts
+++ b/src/store/modules/tagsView.ts
@@ -93,6 +93,11 @@ export const useTagsViewStore = defineStore('tagsView', {
delCachedView() {
const route = router.currentRoute.value
const index = findIndex(this.getCachedViews, (v) => v === route.name)
+ for (const v of this.visitedViews) {
+ if (v.name === route.name) {
+ return
+ }
+ }
if (index > -1) {
this.cachedViews.delete(this.getCachedViews[index])
}
From 6ef61b739db62a057035ab77fd49a520a398d9e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=A2=E7=A5=A5?=
Date: Thu, 21 Aug 2025 15:19:48 +0800
Subject: [PATCH 027/161] =?UTF-8?q?fix(processInstance):=20=E6=B5=81?=
=?UTF-8?q?=E7=A8=8B=E8=A1=A8=E5=8D=95=E5=AD=97=E6=AE=B5=E8=A7=A3=E6=9E=90?=
=?UTF-8?q?=E8=B0=83=E6=95=B4=E4=B8=BA=E4=BD=BF=E7=94=A8=E5=BA=93=E8=A7=A3?=
=?UTF-8?q?=E6=9E=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../bpm/processInstance/create/ProcessDefinitionDetail.vue | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
index 703b4888a..c1ad0171c 100644
--- a/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
+++ b/src/views/bpm/processInstance/create/ProcessDefinitionDetail.vue
@@ -88,6 +88,7 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
import * as DefinitionApi from '@/api/bpm/definition'
import { ApprovalNodeInfo } from '@/api/bpm/processInstance'
+import formCreate from '@form-create/element-ui'
defineOptions({ name: 'ProcessDefinitionDetail' })
const props = defineProps<{
@@ -127,7 +128,8 @@ const initProcessInfo = async (row: any, formVariables?: any) => {
// 注意:需要从 formVariables 中,移除不在 row.formFields 的值。
// 原因是:后端返回的 formVariables 里面,会有一些非表单的信息。例如说,某个流程节点的审批人。
// 这样,就可能导致一个流程被审批不通过后,重新发起时,会直接后端报错!!!
- const allowedFields = decodeFields(row.formFields).map((fieldObj: any) => fieldObj.field)
+ const formApi = formCreate.create(decodeFields(row.formFields))
+ const allowedFields = formApi.fields()
for (const key in formVariables) {
if (!allowedFields.includes(key)) {
delete formVariables[key]
From 24493843065df3c82c31c9d5150b1d81ddcb2e36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=8E=E8=B6=85=E6=9D=B0?=
Date: Thu, 21 Aug 2025 19:05:03 +0800
Subject: [PATCH 028/161] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E7=94=BB?=
=?UTF-8?q?=E5=B8=83=E7=9A=84=20CSS=20transition=20=E5=B1=9E=E6=80=A7?=
=?UTF-8?q?=E4=BB=A5=E8=A7=A3=E5=86=B3=E6=8B=96=E6=8B=BD=E5=8D=A1=E9=A1=BF?=
=?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../SimpleProcessDesignerV2/theme/simple-process-designer.scss | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss b/src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
index d0adbdbb9..33795639f 100644
--- a/src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
+++ b/src/components/SimpleProcessDesignerV2/theme/simple-process-designer.scss
@@ -212,7 +212,6 @@
transform-origin: 50% 0 0;
min-width: fit-content;
transform: scale(1);
- transition: transform 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
background: url(@/assets/svgs/bpm/simple-process-bg.svg) 0 0 repeat;
// 节点容器 定义节点宽度
.node-container {
From 561e5512f9be21e0f6c0634a6a3a430965683f07 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sat, 23 Aug 2025 22:52:43 +0800
Subject: [PATCH 029/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=20=E5=A4=A7?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E3=80=91=E5=A2=9E=E5=8A=A0=20thinking=20?=
=?UTF-8?q?=E6=B7=B1=E5=BA=A6=E6=80=9D=E8=80=83?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/ai/chat/message/index.ts | 1 +
.../index/components/message/MessageList.vue | 8 +-
.../components/message/MessageReasoning.vue | 89 +++++++++++++++++++
src/views/ai/chat/index/index.vue | 37 ++++++--
4 files changed, 126 insertions(+), 9 deletions(-)
create mode 100644 src/views/ai/chat/index/components/message/MessageReasoning.vue
diff --git a/src/api/ai/chat/message/index.ts b/src/api/ai/chat/message/index.ts
index 69d9f123e..023333665 100644
--- a/src/api/ai/chat/message/index.ts
+++ b/src/api/ai/chat/message/index.ts
@@ -13,6 +13,7 @@ export interface ChatMessageVO {
model: number // 模型标志
modelId: number // 模型编号
content: string // 聊天内容
+ reasoningContent?: string // 推理内容
tokens: number // 消耗 Token 数量
segmentIds?: number[] // 段落编号
segments?: {
diff --git a/src/views/ai/chat/index/components/message/MessageList.vue b/src/views/ai/chat/index/components/message/MessageList.vue
index 67c8bd766..5efd39c5f 100644
--- a/src/views/ai/chat/index/components/message/MessageList.vue
+++ b/src/views/ai/chat/index/components/message/MessageList.vue
@@ -14,6 +14,10 @@
class="relative flex flex-col break-words bg-[var(--el-fill-color-light)] shadow-[0_0_0_1px_var(--el-border-color-light)] rounded-10px pt-10px px-10px pb-5px"
ref="markdownViewRef"
>
+
{{ item.content }}
+ {{ item.content }}
+
+
+
+
+
+
+
+
+ {{ titleText }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/ai/chat/index/index.vue b/src/views/ai/chat/index/index.vue
index fdc466617..42126f115 100644
--- a/src/views/ai/chat/index/index.vue
+++ b/src/views/ai/chat/index/index.vue
@@ -2,7 +2,7 @@
{
return [
{
id: 0,
+ conversationId: activeConversation.value.id || 0,
type: 'system',
- content: activeConversation.value.systemMessage
- }
+ userId: '',
+ roleId: '',
+ model: 0,
+ modelId: 0,
+ content: activeConversation.value.systemMessage,
+ tokens: 0,
+ createTime: new Date(),
+ roleAvatar: '',
+ userAvatar: ''
+ } as ChatMessageVO
]
}
return []
@@ -427,6 +436,7 @@ const doSendMessageStream = async (userMessage: ChatMessageVO) => {
conversationId: activeConversationId.value,
type: 'assistant',
content: '思考中...',
+ reasoningContent: '',
createTime: new Date()
} as ChatMessageVO)
// 1.2 滚动到最下面
@@ -450,9 +460,10 @@ const doSendMessageStream = async (userMessage: ChatMessageVO) => {
}
// 如果内容为空,就不处理。
- if (data.receive.content === '') {
+ if (data.receive.content === '' && !data.receive.reasoningContent) {
return
}
+
// 首次返回需要添加一个 message 到页面,后面的都是更新
if (isFirstChunk) {
isFirstChunk = false
@@ -463,12 +474,22 @@ const doSendMessageStream = async (userMessage: ChatMessageVO) => {
activeMessageList.value.push(data.send)
activeMessageList.value.push(data.receive)
}
- // debugger
- receiveMessageFullText.value = receiveMessageFullText.value + data.receive.content
+
+ // 处理 reasoningContent
+ if (data.receive.reasoningContent) {
+ const lastMessage = activeMessageList.value[activeMessageList.value.length - 1]
+ lastMessage.reasoningContent =
+ lastMessage.reasoningContent + data.receive.reasoningContent
+ }
+
+ // 处理正常内容
+ if (data.receive.content !== '') {
+ receiveMessageFullText.value = receiveMessageFullText.value + data.receive.content
+ }
// 滚动到最下面
await scrollToBottom()
},
- (error) => {
+ (error: any) => {
message.alert(`对话异常! ${error}`)
stopStream()
// 需要抛出异常,禁止重试
From 84deeacd4d127ca6b009d51d0d802903167b8416 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 24 Aug 2025 21:30:39 +0800
Subject: [PATCH 030/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=20=E5=A4=A7?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E3=80=91=E5=AF=B9=E8=AF=9D=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20attachment-urls=20=E9=99=84?=
=?UTF-8?q?=E4=BB=B6=E7=9A=84=E5=B1=95=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/ai/chat/message/index.ts | 7 +-
src/utils/file.ts | 19 ++
src/utils/index.ts | 1 -
.../index/components/message/MessageFiles.vue | 165 ++++++++++++++++++
.../index/components/message/MessageList.vue | 8 +
5 files changed, 197 insertions(+), 3 deletions(-)
create mode 100644 src/utils/file.ts
create mode 100644 src/views/ai/chat/index/components/message/MessageFiles.vue
diff --git a/src/api/ai/chat/message/index.ts b/src/api/ai/chat/message/index.ts
index 023333665..193e87b79 100644
--- a/src/api/ai/chat/message/index.ts
+++ b/src/api/ai/chat/message/index.ts
@@ -14,6 +14,7 @@ export interface ChatMessageVO {
modelId: number // 模型编号
content: string // 聊天内容
reasoningContent?: string // 推理内容
+ attachmentUrls?: string[] // 附件 URL 数组
tokens: number // 消耗 Token 数量
segmentIds?: number[] // 段落编号
segments?: {
@@ -45,7 +46,8 @@ export const ChatMessageApi = {
enableContext: boolean,
onMessage,
onError,
- onClose
+ onClose,
+ attachmentUrls?: string[]
) => {
const token = getAccessToken()
return fetchEventSource(`${config.base_url}/ai/chat/message/send-stream`, {
@@ -58,7 +60,8 @@ export const ChatMessageApi = {
body: JSON.stringify({
conversationId,
content,
- useContext: enableContext
+ useContext: enableContext,
+ attachmentUrls: attachmentUrls || []
}),
onmessage: onMessage,
onerror: onError,
diff --git a/src/utils/file.ts b/src/utils/file.ts
new file mode 100644
index 000000000..c8bccbd30
--- /dev/null
+++ b/src/utils/file.ts
@@ -0,0 +1,19 @@
+/** 从 URL 中提取文件名 */
+export const getFileNameFromUrl = (url: string): string => {
+ try {
+ const urlObj = new URL(url)
+ const pathname = urlObj.pathname
+ const fileName = pathname.split('/').pop() || 'unknown'
+ return decodeURIComponent(fileName)
+ } catch {
+ // 如果 URL 解析失败,尝试从字符串中提取
+ const parts = url.split('/')
+ return parts[parts.length - 1] || 'unknown'
+ }
+}
+
+/** 判断是否为图片 */
+export const isImage = (filename: string): boolean => {
+ const ext = filename.split('.').pop()?.toLowerCase() || ''
+ return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
+}
diff --git a/src/utils/index.ts b/src/utils/index.ts
index f0b4faaef..0bcedb438 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -529,7 +529,6 @@ export function jsonParse(str: string) {
* @param start 开始位置
* @param end 结束位置
*/
-
export const subString = (str: string, start: number, end: number) => {
if (str.length > end) {
return str.slice(start, end)
diff --git a/src/views/ai/chat/index/components/message/MessageFiles.vue b/src/views/ai/chat/index/components/message/MessageFiles.vue
new file mode 100644
index 000000000..9362c994b
--- /dev/null
+++ b/src/views/ai/chat/index/components/message/MessageFiles.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+ {{ getFileNameFromUrl(url) }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/ai/chat/index/components/message/MessageList.vue b/src/views/ai/chat/index/components/message/MessageList.vue
index 5efd39c5f..12ce67101 100644
--- a/src/views/ai/chat/index/components/message/MessageList.vue
+++ b/src/views/ai/chat/index/components/message/MessageList.vue
@@ -22,6 +22,7 @@
class="text-[var(--el-text-color-primary)] text-[0.95rem]"
:content="item.content"
/>
+
@@ -52,8 +53,14 @@
{{ formatDate(item.createTime) }}
+
+
+
+
+
{{ item.content }}
@@ -104,6 +111,7 @@ import { formatDate } from '@/utils/formatTime'
import MarkdownView from '@/components/MarkdownView/index.vue'
import MessageKnowledge from './MessageKnowledge.vue'
import MessageReasoning from './MessageReasoning.vue'
+import MessageFiles from './MessageFiles.vue'
import { useClipboard } from '@vueuse/core'
import { ArrowDownBold, Edit, RefreshRight } from '@element-plus/icons-vue'
import { ChatMessageApi, ChatMessageVO } from '@/api/ai/chat/message'
From 61dad44cd98ea10a0f045bfd677266a71d1aaf65 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 24 Aug 2025 22:00:54 +0800
Subject: [PATCH 031/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=20=E5=A4=A7?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E3=80=91=E5=AF=B9=E8=AF=9D=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20attachment-urls=20=E5=8F=91?=
=?UTF-8?q?=E9=80=81=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/message/MessageFileUpload.vue | 424 ++++++++++++++++++
1 file changed, 424 insertions(+)
create mode 100644 src/views/ai/chat/index/components/message/MessageFileUpload.vue
diff --git a/src/views/ai/chat/index/components/message/MessageFileUpload.vue b/src/views/ai/chat/index/components/message/MessageFileUpload.vue
new file mode 100644
index 000000000..732529779
--- /dev/null
+++ b/src/views/ai/chat/index/components/message/MessageFileUpload.vue
@@ -0,0 +1,424 @@
+
+
+
+
+
+
+ {{ fileList.length }}
+
+
+
+
+
+
+
+
+
+
+
+
+
From b880ec22f200103e345e37f399f592da2738eef6 Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 24 Aug 2025 22:00:58 +0800
Subject: [PATCH 032/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=20=E5=A4=A7?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E3=80=91=E5=AF=B9=E8=AF=9D=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20attachment-urls=20=E5=8F=91?=
=?UTF-8?q?=E9=80=81=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/utils/file.ts | 18 +++++++++++++
.../index/components/message/MessageFiles.vue | 11 +-------
.../index/components/message/MessageList.vue | 5 +++-
src/views/ai/chat/index/index.vue | 27 +++++++++++++++----
4 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/src/utils/file.ts b/src/utils/file.ts
index c8bccbd30..e40651932 100644
--- a/src/utils/file.ts
+++ b/src/utils/file.ts
@@ -17,3 +17,21 @@ export const isImage = (filename: string): boolean => {
const ext = filename.split('.').pop()?.toLowerCase() || ''
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
}
+
+/** 格式化文件大小 */
+export const formatFileSize = (bytes: number): string => {
+ if (bytes === 0) return '0 B'
+ const k = 1024
+ const sizes = ['B', 'KB', 'MB', 'GB']
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
+}
+
+/** 获取文件图标 */
+export const getFileIcon = (filename: string): string => {
+ const ext = filename.split('.').pop()?.toLowerCase() || ''
+ if (isImage(ext)) {
+ return 'ep:picture'
+ }
+ return 'ep:document'
+}
diff --git a/src/views/ai/chat/index/components/message/MessageFiles.vue b/src/views/ai/chat/index/components/message/MessageFiles.vue
index 9362c994b..3a9982430 100644
--- a/src/views/ai/chat/index/components/message/MessageFiles.vue
+++ b/src/views/ai/chat/index/components/message/MessageFiles.vue
@@ -23,7 +23,7 @@
-
-
diff --git a/src/views/ai/chat/index/index.vue b/src/views/ai/chat/index/index.vue
index 4bcc24056..2b96010f8 100644
--- a/src/views/ai/chat/index/index.vue
+++ b/src/views/ai/chat/index/index.vue
@@ -488,6 +488,7 @@ const doSendMessageStream = async (userMessage: ChatMessageVO) => {
activeMessageList.value.pop()
// 更新返回的数据
activeMessageList.value.push(data.send)
+ data.send.attachmentUrls = userMessage.attachmentUrls
activeMessageList.value.push(data.receive)
}
From b8a1fbcb140053d35672ebf52cc036a1f1ca792c Mon Sep 17 00:00:00 2001
From: YunaiV
Date: Sun, 24 Aug 2025 22:27:39 +0800
Subject: [PATCH 034/161] =?UTF-8?q?feat=EF=BC=9A=E3=80=90ai=20=E5=A4=A7?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B=E3=80=91=E5=AF=B9=E8=AF=9D=E5=88=97=E8=A1=A8?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=20attachment-urls=20=E5=8F=91?=
=?UTF-8?q?=E9=80=81=E9=80=BB=E8=BE=91=EF=BC=88unocss=20=E6=A0=B7=E5=BC=8F?=
=?UTF-8?q?=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../components/message/MessageFileUpload.vue | 188 ++++++++----------
1 file changed, 79 insertions(+), 109 deletions(-)
diff --git a/src/views/ai/chat/index/components/message/MessageFileUpload.vue b/src/views/ai/chat/index/components/message/MessageFileUpload.vue
index 732529779..8d7dc0f3a 100644
--- a/src/views/ai/chat/index/components/message/MessageFileUpload.vue
+++ b/src/views/ai/chat/index/components/message/MessageFileUpload.vue
@@ -1,22 +1,27 @@
- {{ fileList.length }}
+
+ {{ fileList.length }}
+
@@ -33,29 +38,34 @@