From b93491579c8afb85852faf5649976e8dcbc48642 Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Fri, 14 Apr 2023 21:32:11 +0800
Subject: [PATCH 01/15] =?UTF-8?q?=E7=BB=99=E6=89=80=E6=9C=89=E7=BB=84?=
 =?UTF-8?q?=E4=BB=B6=E6=B7=BB=E5=8A=A0name=E5=B1=9E=E6=80=A7=E9=A2=84?=
 =?UTF-8?q?=E9=98=B2=E6=9C=AA=E7=9F=A5bug!!!?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/App.vue                                   |   4 +-
 src/components/Backtop/src/Backtop.vue        |   2 +-
 .../ConfigGlobal/src/ConfigGlobal.vue         |   4 +-
 .../src/ContentDetailWrap.vue                 |  10 +-
 .../ContentWrap/src/ContentWrap.vue           |   4 +-
 src/components/CountTo/src/CountTo.vue        |   2 +-
 src/components/Crontab/src/Crontab.vue        | 102 ++++++++--------
 src/components/Cropper/src/CopperModal.vue    |  51 ++++----
 src/components/Cropper/src/Cropper.vue        |   4 +-
 src/components/Cropper/src/CropperAvatar.vue  |  14 ++-
 .../Descriptions/src/Descriptions.vue         |  10 +-
 src/components/Dialog/src/Dialog.vue          |  18 +--
 src/components/Echart/src/Echart.vue          |   2 +-
 src/components/Editor/src/Editor.vue          |   6 +-
 src/components/Error/src/Error.vue            |   4 +-
 src/components/IFrame/src/IFrame.vue          |   6 +-
 src/components/Icon/src/Icon.vue              |   4 +-
 src/components/Icon/src/IconSelect.vue        |  22 ++--
 .../ImageViewer/src/ImageViewer.vue           |   2 +-
 src/components/Infotip/src/Infotip.vue        |   6 +-
 .../InputPassword/src/InputPassword.vue       |   8 +-
 src/components/Pagination/index.vue           |  10 +-
 src/components/Qrcode/src/Qrcode.vue          |   9 +-
 src/components/Search/src/Search.vue          |  24 ++--
 src/components/Sticky/src/Sticky.vue          |   5 +-
 src/components/Tooltip/src/Tooltip.vue        |   3 +-
 src/components/Verifition/src/Verify.vue      |  42 ++++---
 .../Verifition/src/Verify/VerifyPoints.vue    |  14 +--
 .../Verifition/src/Verify/VerifySlide.vue     |  22 ++--
 src/components/XButton/src/XButton.vue        |   7 +-
 src/components/XButton/src/XTextButton.vue    |   7 +-
 src/layout/components/AppView.vue             |   2 +-
 .../components/Collapse/src/Collapse.vue      |   6 +-
 .../ContextMenu/src/ContextMenu.vue           |  11 +-
 src/layout/components/Footer/src/Footer.vue   |   2 +-
 .../LocaleDropdown/src/LocaleDropdown.vue     |   8 +-
 src/layout/components/Logo/src/Logo.vue       |   6 +-
 src/layout/components/Message/src/Message.vue |  19 ++-
 .../components/Screenfull/src/Screenfull.vue  |   6 +-
 src/layout/components/Setting/src/Setting.vue |  16 +--
 .../src/components/ColorRadioPicker.vue       |   6 +-
 .../src/components/InterfaceDisplay.vue       |   2 +-
 .../src/components/LayoutRadioPicker.vue      |   2 +-
 .../SizeDropdown/src/SizeDropdown.vue         |   4 +-
 .../components/TagsView/src/TagsView.vue      |  39 ++++---
 .../ThemeSwitch/src/ThemeSwitch.vue           |  10 +-
 .../components/UserInfo/src/UserInfo.vue      |   2 +-
 src/views/Error/403.vue                       |   2 +-
 src/views/Error/404.vue                       |   2 +-
 src/views/Error/500.vue                       |   2 +-
 src/views/Home/Index2.vue                     | 109 +++++++++---------
 src/views/Login/Login.vue                     |   2 +-
 src/views/Login/components/LoginForm.vue      |  42 +++----
 src/views/Login/components/LoginFormTitle.vue |   2 +-
 src/views/Login/components/MobileForm.vue     |  30 ++---
 src/views/Login/components/QrCodeForm.vue     |   8 +-
 src/views/Login/components/RegisterForm.vue   |  20 ++--
 src/views/Profile/components/BasicInfo.vue    |   6 +-
 src/views/Profile/components/ProfileUser.vue  |  31 +++--
 src/views/Profile/components/ResetPwd.vue     |   8 +-
 src/views/Profile/components/UserAvatar.vue   |  11 +-
 src/views/bpm/form/editor/index.vue           |  11 +-
 src/views/bpm/group/UserGroupForm.vue         |  10 +-
 src/views/bpm/model/ModelForm.vue             |  33 +++---
 src/views/bpm/model/ModelImportForm.vue       |  29 ++---
 src/views/bpm/oa/leave/create.vue             |  21 ++--
 src/views/bpm/oa/leave/detail.vue             |   6 +-
 .../detail/ProcessInstanceBpmnViewer.vue      |  10 +-
 .../detail/ProcessInstanceTaskList.vue        |  10 +-
 .../detail/TaskUpdateAssigneeForm.vue         |   8 +-
 src/views/bpm/task/done/TaskDetail.vue        |   6 +-
 .../bpm/taskAssignRule/TaskAssignRuleForm.vue |  39 ++++---
 .../infra/apiAccessLog/ApiAccessLogDetail.vue |  10 +-
 .../infra/apiErrorLog/ApiErrorLogDetail.vue   |  18 +--
 src/views/infra/codegen/EditTable.vue         |   5 +-
 src/views/infra/codegen/ImportTable.vue       |  43 ++++---
 src/views/infra/codegen/PreviewCode.vue       |  29 ++---
 .../codegen/components/BasicInfoForm.vue      |  14 +--
 .../codegen/components/ColumInfoForm.vue      |  28 ++---
 .../codegen/components/GenerateInfoForm.vue   |  18 +--
 src/views/infra/config/ConfigForm.vue         |  10 +-
 .../dataSourceConfig/DataSourceConfigForm.vue |   8 +-
 src/views/infra/file/FileForm.vue             |  29 ++---
 src/views/infra/fileConfig/FileConfigForm.vue |  13 ++-
 src/views/infra/job/JobDetail.vue             |   6 +-
 src/views/infra/job/logger/JobLogDetail.vue   |   6 +-
 src/views/infra/webSocket/index.vue           |  14 +--
 .../mall/product/property/PropertyForm.vue    |  11 +-
 .../mall/product/property/value/ValueForm.vue |  11 +-
 src/views/mp/account/AccountForm.vue          |  11 +-
 .../mp/components/wx-editor/WxEditor.vue      |  22 ++--
 src/views/mp/components/wx-news/main.vue      |  18 ++-
 src/views/mp/tag/TagForm.vue                  |   9 +-
 src/views/mp/user/UserForm.vue                |  11 +-
 src/views/pay/app/AppForm.vue                 |   9 +-
 src/views/pay/merchant/MerchantForm.vue       |  11 +-
 src/views/pay/order/OrderDetail.vue           |   6 +-
 src/views/pay/refund/RefundDetail.vue         |   6 +-
 src/views/system/area/AreaForm.vue            |  11 +-
 src/views/system/dept/DeptForm.vue            |  23 ++--
 src/views/system/dict/DictTypeForm.vue        |  13 ++-
 src/views/system/dict/data/DictDataForm.vue   |  15 +--
 src/views/system/errorCode/ErrorCodeForm.vue  |  16 +--
 src/views/system/loginlog/LoginLogDetail.vue  |   6 +-
 .../system/mail/account/MailAccountDetail.vue |   6 +-
 .../system/mail/account/MailAccountForm.vue   |  11 +-
 src/views/system/mail/log/MailLogDetail.vue   |   6 +-
 .../system/mail/template/MailTemplateForm.vue |  13 ++-
 .../mail/template/MailTemplateSendForm.vue    |  11 +-
 src/views/system/menu/MenuForm.vue            |  67 +++++------
 src/views/system/notice/NoticeForm.vue        |  15 +--
 .../notify/message/NotifyMessageDetail.vue    |   6 +-
 .../notify/my/MyNotifyMessageDetail.vue       |   8 +-
 src/views/system/oauth2/client/ClientForm.vue |  33 +++---
 .../system/operatelog/OperateLogDetail.vue    |  14 +--
 src/views/system/post/PostForm.vue            |  12 +-
 src/views/system/role/RoleAssignMenuForm.vue  |  21 ++--
 .../system/role/RoleDataPermissionForm.vue    |  29 ++---
 src/views/system/role/RoleForm.vue            |  13 ++-
 src/views/system/role/index.vue               | 101 ++++++++--------
 .../sensitiveWord/SensitiveWordForm.vue       |  13 ++-
 .../sensitiveWord/SensitiveWordTestForm.vue   |  15 +--
 src/views/system/sensitiveWord/index.vue      |  90 ++++++++-------
 .../system/sms/channel/SmsChannelForm.vue     |  11 +-
 src/views/system/sms/log/SmsLogDetail.vue     |   6 +-
 .../system/sms/template/SmsTemplateForm.vue   |  15 +--
 .../sms/template/SmsTemplateSendForm.vue      |  11 +-
 src/views/system/tenant/TenantForm.vue        |  20 ++--
 .../tenantPackage/TenantPackageForm.vue       |  19 +--
 src/views/system/user/DeptTree.vue            |  10 +-
 src/views/system/user/UserAssignRoleForm.vue  |   9 +-
 src/views/system/user/UserForm.vue            |  19 +--
 src/views/system/user/UserImportForm.vue      |  28 ++---
 133 files changed, 1126 insertions(+), 993 deletions(-)

diff --git a/src/App.vue b/src/App.vue
index a7867a1c..75edd24f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="APP" setup>
 import { isDark } from '@/utils/is'
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -32,6 +32,7 @@ $prefix-cls: #{$namespace}-app;
   width: 100%;
   height: 100%;
 }
+
 html,
 body {
   padding: 0 !important;
@@ -43,6 +44,7 @@ body {
     @extend .size;
   }
 }
+
 .#{$prefix-cls}-grey-mode {
   filter: grayscale(100%);
 }
diff --git a/src/components/Backtop/src/Backtop.vue b/src/components/Backtop/src/Backtop.vue
index f5c2fc44..70cf78cd 100644
--- a/src/components/Backtop/src/Backtop.vue
+++ b/src/components/Backtop/src/Backtop.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="BackTop" setup>
 import { ElBacktop } from 'element-plus'
 import { useDesign } from '@/hooks/web/useDesign'
 
diff --git a/src/components/ConfigGlobal/src/ConfigGlobal.vue b/src/components/ConfigGlobal/src/ConfigGlobal.vue
index 10a0a9f2..20ff0357 100644
--- a/src/components/ConfigGlobal/src/ConfigGlobal.vue
+++ b/src/components/ConfigGlobal/src/ConfigGlobal.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ConfigGlobal" setup>
 import { propTypes } from '@/utils/propTypes'
 import { useLocaleStore } from '@/store/modules/locale'
 import { useAppStore } from '@/store/modules/app'
@@ -51,9 +51,9 @@ const currentLocale = computed(() => localeStore.currentLocale)
 
 <template>
   <ElConfigProvider
-    :namespace="variables.elNamespace"
     :locale="currentLocale.elLocale"
     :message="{ max: 1 }"
+    :namespace="variables.elNamespace"
     :size="size"
   >
     <slot></slot>
diff --git a/src/components/ContentDetailWrap/src/ContentDetailWrap.vue b/src/components/ContentDetailWrap/src/ContentDetailWrap.vue
index 697ea18a..9469a552 100644
--- a/src/components/ContentDetailWrap/src/ContentDetailWrap.vue
+++ b/src/components/ContentDetailWrap/src/ContentDetailWrap.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ContentDetailWrap" setup>
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
 
@@ -21,7 +21,7 @@ onMounted(() => {
 </script>
 
 <template>
-  <div :class="[`${prefixCls}-container`]" ref="contentDetailWrap">
+  <div ref="contentDetailWrap" :class="[`${prefixCls}-container`]">
     <Sticky :offset="offset">
       <div
         :class="[
@@ -31,7 +31,7 @@ onMounted(() => {
       >
         <div :class="[`${prefixCls}-header__back`, 'flex pl-10px pr-10px ']">
           <ElButton @click="emit('back')">
-            <Icon icon="ep:arrow-left" class="mr-5px" />
+            <Icon class="mr-5px" icon="ep:arrow-left" />
             {{ t('common.back') }}
           </ElButton>
         </div>
@@ -47,7 +47,9 @@ onMounted(() => {
     </Sticky>
     <div style="padding: var(--app-content-padding)">
       <ElCard :class="[`${prefixCls}-body`, 'mb-20px']" shadow="never">
-        <div> <slot></slot> </div>
+        <div>
+          <slot></slot>
+        </div>
       </ElCard>
     </div>
   </div>
diff --git a/src/components/ContentWrap/src/ContentWrap.vue b/src/components/ContentWrap/src/ContentWrap.vue
index 6890e214..0fcfb16f 100644
--- a/src/components/ContentWrap/src/ContentWrap.vue
+++ b/src/components/ContentWrap/src/ContentWrap.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ContentWrap" setup>
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
 
@@ -21,7 +21,7 @@ defineProps({
           <template #content>
             <div class="max-w-200px">{{ message }}</div>
           </template>
-          <Icon class="ml-5px" icon="ep:question-filled" :size="14" />
+          <Icon :size="14" class="ml-5px" icon="ep:question-filled" />
         </ElTooltip>
       </div>
     </template>
diff --git a/src/components/CountTo/src/CountTo.vue b/src/components/CountTo/src/CountTo.vue
index 8d2f1ade..c4fa7b56 100644
--- a/src/components/CountTo/src/CountTo.vue
+++ b/src/components/CountTo/src/CountTo.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="CountTo" setup>
 import { PropType } from 'vue'
 import { isNumber } from '@/utils/is'
 import { propTypes } from '@/utils/propTypes'
diff --git a/src/components/Crontab/src/Crontab.vue b/src/components/Crontab/src/Crontab.vue
index 0e474fb2..13096f75 100644
--- a/src/components/Crontab/src/Crontab.vue
+++ b/src/components/Crontab/src/Crontab.vue
@@ -1,10 +1,12 @@
-<script setup lang="ts">
+<script lang="ts" name="Crontab" setup>
 import { ElMessage } from 'element-plus'
 import { PropType } from 'vue'
+
 interface shortcutsType {
   text: string
   value: string
 }
+
 const props = defineProps({
   modelValue: {
     type: String,
@@ -501,7 +503,7 @@ const submit = () => {
 }
 </script>
 <template>
-  <el-input v-model="defaultValue" v-bind="$attrs" class="input-with-select">
+  <el-input v-model="defaultValue" class="input-with-select" v-bind="$attrs">
     <template #append>
       <el-select v-model="select" placeholder="生成器" style="width: 115px">
         <el-option label="每分钟" value="0 * * * * ?" />
@@ -522,11 +524,11 @@ const submit = () => {
   </el-input>
 
   <el-dialog
-    title="cron规则生成器"
     v-model="dialogVisible"
     :width="580"
-    destroy-on-close
     append-to-body
+    destroy-on-close
+    title="cron规则生成器"
   >
     <div class="sc-cron">
       <el-tabs>
@@ -546,38 +548,38 @@ const submit = () => {
                 <el-radio-button label="3">指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.second.type == '1'">
+            <el-form-item v-if="cronValue.second.type == '1'" label="范围">
               <el-input-number
                 v-model="cronValue.second.range.start"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               <span style="padding: 0 15px">-</span>
               <el-input-number
                 v-model="cronValue.second.range.end"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.second.type == '2'">
+            <el-form-item v-if="cronValue.second.type == '2'" label="间隔">
               <el-input-number
                 v-model="cronValue.second.loop.start"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               秒开始,每
               <el-input-number
                 v-model="cronValue.second.loop.end"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               秒执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.second.type == '3'">
+            <el-form-item v-if="cronValue.second.type == '3'" label="指定">
               <el-select v-model="cronValue.second.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.second"
@@ -605,38 +607,38 @@ const submit = () => {
                 <el-radio-button label="3">指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.minute.type == '1'">
+            <el-form-item v-if="cronValue.minute.type == '1'" label="范围">
               <el-input-number
                 v-model="cronValue.minute.range.start"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               <span style="padding: 0 15px">-</span>
               <el-input-number
                 v-model="cronValue.minute.range.end"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.minute.type == '2'">
+            <el-form-item v-if="cronValue.minute.type == '2'" label="间隔">
               <el-input-number
                 v-model="cronValue.minute.loop.start"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               分钟开始,每
               <el-input-number
                 v-model="cronValue.minute.loop.end"
-                :min="0"
                 :max="59"
+                :min="0"
                 controls-position="right"
               />
               分钟执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.minute.type == '3'">
+            <el-form-item v-if="cronValue.minute.type == '3'" label="指定">
               <el-select v-model="cronValue.minute.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.minute"
@@ -664,38 +666,38 @@ const submit = () => {
                 <el-radio-button label="3">指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.hour.type == '1'">
+            <el-form-item v-if="cronValue.hour.type == '1'" label="范围">
               <el-input-number
                 v-model="cronValue.hour.range.start"
-                :min="0"
                 :max="23"
+                :min="0"
                 controls-position="right"
               />
               <span style="padding: 0 15px">-</span>
               <el-input-number
                 v-model="cronValue.hour.range.end"
-                :min="0"
                 :max="23"
+                :min="0"
                 controls-position="right"
               />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.hour.type == '2'">
+            <el-form-item v-if="cronValue.hour.type == '2'" label="间隔">
               <el-input-number
                 v-model="cronValue.hour.loop.start"
-                :min="0"
                 :max="23"
+                :min="0"
                 controls-position="right"
               />
               小时开始,每
               <el-input-number
                 v-model="cronValue.hour.loop.end"
-                :min="0"
                 :max="23"
+                :min="0"
                 controls-position="right"
               />
               小时执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.hour.type == '3'">
+            <el-form-item v-if="cronValue.hour.type == '3'" label="指定">
               <el-select v-model="cronValue.hour.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.hour"
@@ -725,38 +727,38 @@ const submit = () => {
                 <el-radio-button label="5">不指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.day.type == '1'">
+            <el-form-item v-if="cronValue.day.type == '1'" label="范围">
               <el-input-number
                 v-model="cronValue.day.range.start"
-                :min="1"
                 :max="31"
+                :min="1"
                 controls-position="right"
               />
               <span style="padding: 0 15px">-</span>
               <el-input-number
                 v-model="cronValue.day.range.end"
-                :min="1"
                 :max="31"
+                :min="1"
                 controls-position="right"
               />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.day.type == '2'">
+            <el-form-item v-if="cronValue.day.type == '2'" label="间隔">
               <el-input-number
                 v-model="cronValue.day.loop.start"
-                :min="1"
                 :max="31"
+                :min="1"
                 controls-position="right"
               />
               号开始,每
               <el-input-number
                 v-model="cronValue.day.loop.end"
-                :min="1"
                 :max="31"
+                :min="1"
                 controls-position="right"
               />
               天执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.day.type == '3'">
+            <el-form-item v-if="cronValue.day.type == '3'" label="指定">
               <el-select v-model="cronValue.day.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.day"
@@ -784,38 +786,38 @@ const submit = () => {
                 <el-radio-button label="3">指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.month.type == '1'">
+            <el-form-item v-if="cronValue.month.type == '1'" label="范围">
               <el-input-number
                 v-model="cronValue.month.range.start"
-                :min="1"
                 :max="12"
+                :min="1"
                 controls-position="right"
               />
               <span style="padding: 0 15px">-</span>
               <el-input-number
                 v-model="cronValue.month.range.end"
-                :min="1"
                 :max="12"
+                :min="1"
                 controls-position="right"
               />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.month.type == '2'">
+            <el-form-item v-if="cronValue.month.type == '2'" label="间隔">
               <el-input-number
                 v-model="cronValue.month.loop.start"
-                :min="1"
                 :max="12"
+                :min="1"
                 controls-position="right"
               />
               月开始,每
               <el-input-number
                 v-model="cronValue.month.loop.end"
-                :min="1"
                 :max="12"
+                :min="1"
                 controls-position="right"
               />
               月执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.month.type == '3'">
+            <el-form-item v-if="cronValue.month.type == '3'" label="指定">
               <el-select v-model="cronValue.month.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.month"
@@ -846,7 +848,7 @@ const submit = () => {
                   <el-radio-button label="5">不指定</el-radio-button>
                 </el-radio-group>
               </el-form-item>
-              <el-form-item label="范围" v-if="cronValue.week.type == '1'">
+              <el-form-item v-if="cronValue.week.type == '1'" label="范围">
                 <el-select v-model="cronValue.week.range.start">
                   <el-option
                     v-for="(item, index) in data.week"
@@ -865,12 +867,12 @@ const submit = () => {
                   />
                 </el-select>
               </el-form-item>
-              <el-form-item label="间隔" v-if="cronValue.week.type == '2'">
+              <el-form-item v-if="cronValue.week.type == '2'" label="间隔">
                 第
                 <el-input-number
                   v-model="cronValue.week.loop.start"
-                  :min="1"
                   :max="4"
+                  :min="1"
                   controls-position="right"
                 />
                 周的星期
@@ -884,7 +886,7 @@ const submit = () => {
                 </el-select>
                 执行一次
               </el-form-item>
-              <el-form-item label="指定" v-if="cronValue.week.type == '3'">
+              <el-form-item v-if="cronValue.week.type == '3'" label="指定">
                 <el-select v-model="cronValue.week.appoint" multiple style="width: 100%">
                   <el-option
                     v-for="(item, index) in data.week"
@@ -894,7 +896,7 @@ const submit = () => {
                   />
                 </el-select>
               </el-form-item>
-              <el-form-item label="最后一周" v-if="cronValue.week.type == '4'">
+              <el-form-item v-if="cronValue.week.type == '4'" label="最后一周">
                 <el-select v-model="cronValue.week.last">
                   <el-option
                     v-for="(item, index) in data.week"
@@ -924,12 +926,12 @@ const submit = () => {
                 <el-radio-button label="3">指定</el-radio-button>
               </el-radio-group>
             </el-form-item>
-            <el-form-item label="范围" v-if="cronValue.year.type == '1'">
+            <el-form-item v-if="cronValue.year.type == '1'" label="范围">
               <el-input-number v-model="cronValue.year.range.start" controls-position="right" />
               <span style="padding: 0 15px">-</span>
               <el-input-number v-model="cronValue.year.range.end" controls-position="right" />
             </el-form-item>
-            <el-form-item label="间隔" v-if="cronValue.year.type == '2'">
+            <el-form-item v-if="cronValue.year.type == '2'" label="间隔">
               <el-input-number v-model="cronValue.year.loop.start" controls-position="right" />
               年开始,每
               <el-input-number
@@ -939,7 +941,7 @@ const submit = () => {
               />
               年执行一次
             </el-form-item>
-            <el-form-item label="指定" v-if="cronValue.year.type == '3'">
+            <el-form-item v-if="cronValue.year.type == '3'" label="指定">
               <el-select v-model="cronValue.year.appoint" multiple style="width: 100%">
                 <el-option
                   v-for="(item, index) in data.year"
@@ -968,16 +970,19 @@ const submit = () => {
   padding: 0 7px;
   vertical-align: bottom;
 }
+
 .sc-cron-num {
   text-align: center;
   margin-bottom: 15px;
   width: 100%;
 }
+
 .sc-cron-num h2 {
   font-size: 12px;
   margin-bottom: 15px;
   font-weight: normal;
 }
+
 .sc-cron-num h4 {
   display: block;
   height: 32px;
@@ -988,13 +993,16 @@ const submit = () => {
   background: var(--el-color-primary-light-9);
   border-radius: 4px;
 }
+
 .sc-cron:deep(.el-tabs__item.is-active) .sc-cron-num h4 {
   background: var(--el-color-primary);
   color: #fff;
 }
+
 [data-theme='dark'] .sc-cron-num h4 {
   background: var(--el-color-white);
 }
+
 .input-with-select .el-input-group__prepend {
   background-color: var(--el-fill-color-blank);
 }
diff --git a/src/components/Cropper/src/CopperModal.vue b/src/components/Cropper/src/CopperModal.vue
index 2365e5ec..c303b58c 100644
--- a/src/components/Cropper/src/CopperModal.vue
+++ b/src/components/Cropper/src/CopperModal.vue
@@ -2,26 +2,26 @@
   <div>
     <Dialog
       v-model="dialogVisible"
-      :title="t('cropper.modalTitle')"
-      width="800px"
-      maxHeight="380px"
       :canFullscreen="false"
+      :title="t('cropper.modalTitle')"
+      maxHeight="380px"
+      width="800px"
     >
       <div :class="prefixCls">
         <div :class="`${prefixCls}-left`">
           <div :class="`${prefixCls}-cropper`">
             <CropperImage
               v-if="src"
+              :circled="circled"
               :src="src"
               height="300px"
-              :circled="circled"
               @cropend="handleCropend"
               @ready="handleReady"
             />
           </div>
 
           <div :class="`${prefixCls}-toolbar`">
-            <el-upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
+            <el-upload :beforeUpload="handleBeforeUpload" :fileList="[]" accept="image/*">
               <el-tooltip :content="t('cropper.selectImage')" placement="bottom">
                 <XButton preIcon="ant-design:upload-outlined" type="primary" />
               </el-tooltip>
@@ -29,64 +29,64 @@
             <el-space>
               <el-tooltip :content="t('cropper.btn_reset')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="ant-design:reload-outlined"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('reset')"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_rotate_left')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="ant-design:rotate-left-outlined"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('rotate', -45)"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_rotate_right')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="ant-design:rotate-right-outlined"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('rotate', 45)"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_scale_x')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="vaadin:arrows-long-h"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('scaleX')"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_scale_y')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="vaadin:arrows-long-v"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('scaleY')"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_zoom_in')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="ant-design:zoom-in-outlined"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('zoom', 0.1)"
                 />
               </el-tooltip>
               <el-tooltip :content="t('cropper.btn_zoom_out')" placement="bottom">
                 <XButton
-                  type="primary"
+                  :disabled="!src"
                   preIcon="ant-design:zoom-out-outlined"
                   size="small"
-                  :disabled="!src"
+                  type="primary"
                   @click="handlerToolbar('zoom', -0.1)"
                 />
               </el-tooltip>
@@ -95,14 +95,14 @@
         </div>
         <div :class="`${prefixCls}-right`">
           <div :class="`${prefixCls}-preview`">
-            <img :src="previewSource" v-if="previewSource" :alt="t('cropper.preview')" />
+            <img v-if="previewSource" :alt="t('cropper.preview')" :src="previewSource" />
           </div>
           <template v-if="previewSource">
             <div :class="`${prefixCls}-group`">
               <el-avatar :src="previewSource" size="large" />
-              <el-avatar :src="previewSource" :size="48" />
-              <el-avatar :src="previewSource" :size="64" />
-              <el-avatar :src="previewSource" :size="80" />
+              <el-avatar :size="48" :src="previewSource" />
+              <el-avatar :size="64" :src="previewSource" />
+              <el-avatar :size="80" :src="previewSource" />
             </div>
           </template>
         </div>
@@ -113,7 +113,7 @@
     </Dialog>
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="CopperModal" setup>
 import { useDesign } from '@/hooks/web/useDesign'
 import { dataURLtoBlob } from '@/utils/filt'
 import { useI18n } from 'vue-i18n'
@@ -173,12 +173,15 @@ async function handleOk() {
   const blob = dataURLtoBlob(previewSource.value)
   emit('uploadSuccess', { source: previewSource.value, data: blob, filename: filename })
 }
+
 function openModal() {
   dialogVisible.value = true
 }
+
 function closeModal() {
   dialogVisible.value = false
 }
+
 defineExpose({ openModal, closeModal })
 </script>
 <style lang="scss">
diff --git a/src/components/Cropper/src/Cropper.vue b/src/components/Cropper/src/Cropper.vue
index 459c97fa..ced43f96 100644
--- a/src/components/Cropper/src/Cropper.vue
+++ b/src/components/Cropper/src/Cropper.vue
@@ -3,14 +3,14 @@
     <img
       v-show="isReady"
       ref="imgElRef"
-      :src="src"
       :alt="alt"
       :crossorigin="crossorigin"
+      :src="src"
       :style="getImageStyle"
     />
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="Cropper" setup>
 import { CSSProperties, PropType } from 'vue'
 import Cropper from 'cropperjs'
 import 'cropperjs/dist/cropper.css'
diff --git a/src/components/Cropper/src/CropperAvatar.vue b/src/components/Cropper/src/CropperAvatar.vue
index dc4c7475..179e0ec9 100644
--- a/src/components/Cropper/src/CropperAvatar.vue
+++ b/src/components/Cropper/src/CropperAvatar.vue
@@ -1,17 +1,17 @@
 <template>
   <div class="user-info-head" @click="open()">
-    <img :src="sourceValue" v-if="sourceValue" class="img-circle img-lg" alt="avatar" />
-    <el-button :class="`${prefixCls}-upload-btn`" @click="open()" v-if="showBtn">
+    <img v-if="sourceValue" :src="sourceValue" alt="avatar" class="img-circle img-lg" />
+    <el-button v-if="showBtn" :class="`${prefixCls}-upload-btn`" @click="open()">
       {{ btnText ? btnText : t('cropper.selectImage') }}
     </el-button>
     <CopperModal
       ref="cropperModelRef"
-      @upload-success="handleUploadSuccess"
       :srcValue="sourceValue"
+      @upload-success="handleUploadSuccess"
     />
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="CropperAvatar" setup>
 import { useDesign } from '@/hooks/web/useDesign'
 
 import { propTypes } from '@/utils/propTypes'
@@ -54,9 +54,11 @@ function handleUploadSuccess({ source, data, filename }) {
 function open() {
   cropperModelRef.value.openModal()
 }
+
 function close() {
   cropperModelRef.value.closeModal()
 }
+
 defineExpose({
   open,
   close
@@ -104,17 +106,21 @@ $prefix-cls: #{$namespace}--cropper-avatar;
     margin: 10px auto;
   }
 }
+
 .user-info-head {
   position: relative;
   display: inline-block;
 }
+
 .img-circle {
   border-radius: 50%;
 }
+
 .img-lg {
   width: 120px;
   height: 120px;
 }
+
 .user-info-head:hover:after {
   content: '+';
   position: absolute;
diff --git a/src/components/Descriptions/src/Descriptions.vue b/src/components/Descriptions/src/Descriptions.vue
index f1e77ddf..829c2014 100644
--- a/src/components/Descriptions/src/Descriptions.vue
+++ b/src/components/Descriptions/src/Descriptions.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Descriptions" setup>
 import { PropType } from 'vue'
 import dayjs from 'dayjs'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -84,7 +84,7 @@ const toggleClick = () => {
         <div class="flex items-center">
           {{ title }}
           <ElTooltip v-if="message" :content="message" placement="right">
-            <Icon icon="ep:warning" class="ml-5px" />
+            <Icon class="ml-5px" icon="ep:warning" />
           </ElTooltip>
         </div>
       </div>
@@ -95,8 +95,8 @@ const toggleClick = () => {
       <div v-show="show" :class="[`${prefixCls}-content`, 'p-10px']">
         <ElDescriptions
           :column="props.columns"
-          border
           :direction="mobile ? 'vertical' : 'horizontal'"
+          border
           v-bind="getBindValue"
         >
           <template v-if="slots['extra']" #extra>
@@ -114,8 +114,8 @@ const toggleClick = () => {
                 :row="{
                   label: item.label
                 }"
-                >{{ item.label }}</slot
-              >
+                >{{ item.label }}
+              </slot>
             </template>
 
             <template #default>
diff --git a/src/components/Dialog/src/Dialog.vue b/src/components/Dialog/src/Dialog.vue
index 48d5f1c3..449174d9 100644
--- a/src/components/Dialog/src/Dialog.vue
+++ b/src/components/Dialog/src/Dialog.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Dialog" setup>
 import { propTypes } from '@/utils/propTypes'
 import { isNumber } from '@/utils/is'
 
@@ -59,13 +59,13 @@ const dialogStyle = computed(() => {
 
 <template>
   <ElDialog
-    v-bind="getBindValue"
-    :fullscreen="isFullscreen"
-    destroy-on-close
-    lock-scroll
-    draggable
-    :width="width"
     :close-on-click-modal="true"
+    :fullscreen="isFullscreen"
+    :width="width"
+    destroy-on-close
+    draggable
+    lock-scroll
+    v-bind="getBindValue"
   >
     <template #header>
       <div class="flex justify-between">
@@ -74,8 +74,8 @@ const dialogStyle = computed(() => {
         </slot>
         <Icon
           v-if="fullscreen"
-          class="mr-22px cursor-pointer is-hover mt-2px z-10"
           :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
+          class="mr-22px cursor-pointer is-hover mt-2px z-10"
           color="var(--el-color-info)"
           @click="toggleFull"
         />
@@ -83,7 +83,7 @@ const dialogStyle = computed(() => {
     </template>
 
     <!-- 情况一:如果 scroll 为 true,说明开启滚动条 -->
-    <ElScrollbar :style="dialogStyle" v-if="scroll">
+    <ElScrollbar v-if="scroll" :style="dialogStyle">
       <slot></slot>
     </ElScrollbar>
     <!-- 情况二:如果 scroll 为 false,说明关闭滚动条滚动条 -->
diff --git a/src/components/Echart/src/Echart.vue b/src/components/Echart/src/Echart.vue
index 41fde039..31f2eea0 100644
--- a/src/components/Echart/src/Echart.vue
+++ b/src/components/Echart/src/Echart.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="EChart" setup>
 import type { EChartsOption } from 'echarts'
 import echarts from '@/plugins/echarts'
 import { debounce } from 'lodash-es'
diff --git a/src/components/Editor/src/Editor.vue b/src/components/Editor/src/Editor.vue
index 4d8e7dde..092404e3 100644
--- a/src/components/Editor/src/Editor.vue
+++ b/src/components/Editor/src/Editor.vue
@@ -1,7 +1,7 @@
-<script setup lang="ts">
+<script lang="ts" name="Editor" setup>
 import { PropType } from 'vue'
 import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
-import { IDomEditor, IEditorConfig, i18nChangeLanguage } from '@wangeditor/editor'
+import { i18nChangeLanguage, IDomEditor, IEditorConfig } from '@wangeditor/editor'
 import { propTypes } from '@/utils/propTypes'
 import { isNumber } from '@/utils/is'
 import { ElMessage } from 'element-plus'
@@ -188,8 +188,8 @@ defineExpose({
     <!-- 编辑器 -->
     <Editor
       v-model="valueHtml"
-      :editorId="editorId"
       :defaultConfig="editorConfig"
+      :editorId="editorId"
       :style="editorStyle"
       @on-change="handleChange"
       @on-created="handleCreated"
diff --git a/src/components/Error/src/Error.vue b/src/components/Error/src/Error.vue
index a979bc01..f8652a13 100644
--- a/src/components/Error/src/Error.vue
+++ b/src/components/Error/src/Error.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Error" setup>
 import pageError from '@/assets/svgs/404.svg'
 import networkError from '@/assets/svgs/500.svg'
 import noPermission from '@/assets/svgs/403.svg'
@@ -46,7 +46,7 @@ const btnClick = () => {
 <template>
   <div class="flex justify-center">
     <div class="text-center">
-      <img width="350" :src="errorMap[type].url" alt="" />
+      <img :src="errorMap[type].url" alt="" width="350" />
       <div class="text-14px text-[var(--el-color-info)]">{{ errorMap[type].message }}</div>
       <div class="mt-20px">
         <ElButton type="primary" @click="btnClick">{{ errorMap[type].buttonText }}</ElButton>
diff --git a/src/components/IFrame/src/IFrame.vue b/src/components/IFrame/src/IFrame.vue
index 522da3cc..a8864a72 100644
--- a/src/components/IFrame/src/IFrame.vue
+++ b/src/components/IFrame/src/IFrame.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="IFrame" setup>
 import { propTypes } from '@/utils/propTypes'
 
 const props = defineProps({
@@ -20,11 +20,11 @@ onMounted(() => {
 <template>
   <div v-loading="loading" :style="'height:' + height">
     <iframe
+      ref="frameRef"
       :src="props.src"
-      style="width: 100%; height: 100%"
       frameborder="no"
       scrolling="auto"
-      ref="frameRef"
+      style="width: 100%; height: 100%"
     ></iframe>
   </div>
 </template>
diff --git a/src/components/Icon/src/Icon.vue b/src/components/Icon/src/Icon.vue
index bd94fcd4..92d791c2 100644
--- a/src/components/Icon/src/Icon.vue
+++ b/src/components/Icon/src/Icon.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Icon" setup>
 import { propTypes } from '@/utils/propTypes'
 import Iconify from '@purge-icons/generated'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -72,7 +72,7 @@ watch(
 
 <template>
   <ElIcon :class="prefixCls" :color="color" :size="size">
-    <svg v-if="isLocal" aria-hidden="true" :class="getSvgClass">
+    <svg v-if="isLocal" :class="getSvgClass" aria-hidden="true">
       <use :xlink:href="symbolId" />
     </svg>
 
diff --git a/src/components/Icon/src/IconSelect.vue b/src/components/Icon/src/IconSelect.vue
index 1a124ca6..08fb1a2d 100644
--- a/src/components/Icon/src/IconSelect.vue
+++ b/src/components/Icon/src/IconSelect.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="IconSelect" setup>
 import { CSSProperties } from 'vue'
 import { cloneDeep } from 'lodash-es'
 import { IconJson } from '@/components/Icon/src/data'
@@ -116,13 +116,13 @@ watch(
     <ElInput v-model="inputValue" @click="visible = !visible">
       <template #append>
         <ElPopover
-          :width="350"
-          trigger="click"
-          popper-class="pure-popper"
           :popper-options="{
             placement: 'auto'
           }"
           :visible="visible"
+          :width="350"
+          popper-class="pure-popper"
+          trigger="click"
         >
           <template #reference>
             <div
@@ -133,7 +133,7 @@ watch(
             </div>
           </template>
 
-          <ElInput class="p-2" v-model="filterValue" placeholder="搜索图标" clearable />
+          <ElInput v-model="filterValue" class="p-2" clearable placeholder="搜索图标" />
           <ElDivider border-style="dashed" />
 
           <ElTabs v-model="currentActiveType" @tab-click="handleClick">
@@ -143,15 +143,15 @@ watch(
               :label="pane.label"
               :name="pane.name"
             >
-              <ElDivider class="tab-divider" border-style="dashed" />
+              <ElDivider border-style="dashed" class="tab-divider" />
               <ElScrollbar height="220px">
                 <ul class="flex flex-wrap px-2 ml-2">
                   <li
                     v-for="(item, key) in pageList"
                     :key="key"
+                    :style="iconItemStyle(item)"
                     :title="item"
                     class="icon-item p-2 w-1/10 cursor-pointer mr-2 mt-1 flex justify-center items-center border border-solid"
-                    :style="iconItemStyle(item)"
                     @click="onChangeIcon(item)"
                   >
                     <Icon :icon="currentActiveType + item" />
@@ -163,13 +163,13 @@ watch(
           <ElDivider border-style="dashed" />
 
           <ElPagination
-            small
-            :total="iconCount"
-            :page-size="pageSize"
             :current-page="currentPage"
+            :page-size="pageSize"
+            :total="iconCount"
             background
-            layout="prev, pager, next"
             class="flex items-center justify-center h-10"
+            layout="prev, pager, next"
+            small
             @current-change="onCurrentChange"
           />
         </ElPopover>
diff --git a/src/components/ImageViewer/src/ImageViewer.vue b/src/components/ImageViewer/src/ImageViewer.vue
index a2ddc072..c416f566 100644
--- a/src/components/ImageViewer/src/ImageViewer.vue
+++ b/src/components/ImageViewer/src/ImageViewer.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ImageViewer" setup>
 import { PropType } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 
diff --git a/src/components/Infotip/src/Infotip.vue b/src/components/Infotip/src/Infotip.vue
index a03f34e2..dde5f4bc 100644
--- a/src/components/Infotip/src/Infotip.vue
+++ b/src/components/Infotip/src/Infotip.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="InfoTip" setup>
 import { PropType } from 'vue'
 import { useDesign } from '@/hooks/web/useDesign'
 import { propTypes } from '@/utils/propTypes'
@@ -34,14 +34,14 @@ const keyClick = (key: string) => {
     ]"
   >
     <div v-if="title" :class="[`${prefixCls}__header`, 'flex items-center']">
-      <Icon icon="ep:warning-filled" :size="22" color="var(--el-color-primary)" />
+      <Icon :size="22" color="var(--el-color-primary)" icon="ep:warning-filled" />
       <span :class="[`${prefixCls}__title`, 'pl-5px text-16px font-bold']">{{ title }}</span>
     </div>
     <div :class="`${prefixCls}__content`">
       <p v-for="(item, $index) in schema" :key="$index" class="text-14px mt-15px">
         <Highlight
-          :keys="typeof item === 'string' ? [] : item.keys"
           :color="highlightColor"
+          :keys="typeof item === 'string' ? [] : item.keys"
           @click="keyClick"
         >
           {{ showIndex ? `${$index + 1}、` : '' }}{{ typeof item === 'string' ? item : item.label }}
diff --git a/src/components/InputPassword/src/InputPassword.vue b/src/components/InputPassword/src/InputPassword.vue
index 9e82cd41..19ce032c 100644
--- a/src/components/InputPassword/src/InputPassword.vue
+++ b/src/components/InputPassword/src/InputPassword.vue
@@ -1,8 +1,8 @@
-<script setup lang="ts">
+<script lang="ts" name="InputPassword" setup>
 import { propTypes } from '@/utils/propTypes'
 import { useConfigGlobal } from '@/hooks/web/useConfigGlobal'
-import { zxcvbn } from '@zxcvbn-ts/core'
 import type { ZxcvbnResult } from '@zxcvbn-ts/core'
+import { zxcvbn } from '@zxcvbn-ts/core'
 import { useDesign } from '@/hooks/web/useDesign'
 
 const { getPrefixCls } = useDesign()
@@ -57,9 +57,9 @@ const getIconName = computed(() => (unref(textType) === 'password' ? 'ep:hide' :
 
 <template>
   <div :class="[prefixCls, `${prefixCls}--${configGlobal?.size}`]">
-    <ElInput v-bind="$attrs" v-model="valueRef" :type="textType">
+    <ElInput v-model="valueRef" :type="textType" v-bind="$attrs">
       <template #suffix>
-        <Icon class="el-input__icon cursor-pointer" :icon="getIconName" @click="changeTextType" />
+        <Icon :icon="getIconName" class="el-input__icon cursor-pointer" @click="changeTextType" />
       </template>
     </ElInput>
     <div
diff --git a/src/components/Pagination/index.vue b/src/components/Pagination/index.vue
index 788809a5..43112c55 100644
--- a/src/components/Pagination/index.vue
+++ b/src/components/Pagination/index.vue
@@ -2,19 +2,19 @@
 <template>
   <el-pagination
     v-show="total > 0"
-    class="float-right mt-15px mb-15px"
-    :background="true"
-    layout="total, sizes, prev, pager, next, jumper"
-    :page-sizes="[10, 20, 30, 50, 100]"
     v-model:current-page="currentPage"
     v-model:page-size="pageSize"
+    :background="true"
+    :page-sizes="[10, 20, 30, 50, 100]"
     :pager-count="pagerCount"
     :total="total"
+    class="float-right mt-15px mb-15px"
+    layout="total, sizes, prev, pager, next, jumper"
     @size-change="handleSizeChange"
     @current-change="handleCurrentChange"
   />
 </template>
-<script setup>
+<script name="Pagination" setup>
 import { computed } from 'vue'
 
 const props = defineProps({
diff --git a/src/components/Qrcode/src/Qrcode.vue b/src/components/Qrcode/src/Qrcode.vue
index 0ef59ba7..2b72ef8b 100644
--- a/src/components/Qrcode/src/Qrcode.vue
+++ b/src/components/Qrcode/src/Qrcode.vue
@@ -1,7 +1,6 @@
-<script setup lang="ts">
-import { PropType, nextTick, ref, watch, computed, unref } from 'vue'
-import QRCode from 'qrcode'
-import { QRCodeRenderersOptions } from 'qrcode'
+<script lang="ts" name="Qrcode" setup>
+import { computed, nextTick, PropType, ref, unref, watch } from 'vue'
+import QRCode, { QRCodeRenderersOptions } from 'qrcode'
 import { cloneDeep } from 'lodash-es'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -230,7 +229,7 @@ const disabledClick = () => {
       @click="disabledClick"
     >
       <div class="absolute top-[50%] left-[50%] font-bold">
-        <Icon icon="ep:refresh-right" :size="30" color="var(--el-color-primary)" />
+        <Icon :size="30" color="var(--el-color-primary)" icon="ep:refresh-right" />
         <div>{{ disabledText }}</div>
       </div>
     </div>
diff --git a/src/components/Search/src/Search.vue b/src/components/Search/src/Search.vue
index cb3d5dea..8309c43f 100644
--- a/src/components/Search/src/Search.vue
+++ b/src/components/Search/src/Search.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Search" setup>
 import { PropType } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 
@@ -100,25 +100,25 @@ const setVisible = () => {
 <template>
   <!-- update by 芋艿:class="-mb-15px" 用于降低和 ContentWrap 组件的底部距离,避免空隙过大 -->
   <Form
-    :is-custom="false"
-    :label-width="labelWidth"
-    hide-required-asterisk
     :inline="inline"
     :is-col="isCol"
+    :is-custom="false"
+    :label-width="labelWidth"
     :schema="newSchema"
-    @register="register"
     class="-mb-15px"
+    hide-required-asterisk
+    @register="register"
   >
     <template #action>
       <div v-if="layout === 'inline'">
         <!-- update by 芋艿:去除搜索的 type="primary",颜色变淡一点 -->
         <ElButton v-if="showSearch" @click="search">
-          <Icon icon="ep:search" class="mr-5px" />
+          <Icon class="mr-5px" icon="ep:search" />
           {{ t('common.query') }}
         </ElButton>
         <!-- update by 芋艿:将 icon="ep:refresh-right" 修改成 icon="ep:refresh",和 ruoyi-vue 搜索保持一致  -->
         <ElButton v-if="showReset" @click="reset">
-          <Icon icon="ep:refresh" class="mr-5px" />
+          <Icon class="mr-5px" icon="ep:refresh" />
           {{ t('common.reset') }}
         </ElButton>
         <ElButton v-if="expand" text @click="setVisible">
@@ -129,19 +129,19 @@ const setVisible = () => {
         <slot name="actionMore"></slot>
       </div>
     </template>
-    <template #[name] v-for="name in Object.keys($slots)" :key="name"
-      ><slot :name="name"></slot
-    ></template>
+    <template v-for="name in Object.keys($slots)" :key="name" #[name]>
+      <slot :name="name"></slot>
+    </template>
   </Form>
 
   <template v-if="layout === 'bottom'">
     <div :style="bottonButtonStyle">
       <ElButton v-if="showSearch" type="primary" @click="search">
-        <Icon icon="ep:search" class="mr-5px" />
+        <Icon class="mr-5px" icon="ep:search" />
         {{ t('common.query') }}
       </ElButton>
       <ElButton v-if="showReset" @click="reset">
-        <Icon icon="ep:refresh-right" class="mr-5px" />
+        <Icon class="mr-5px" icon="ep:refresh-right" />
         {{ t('common.reset') }}
       </ElButton>
       <ElButton v-if="expand" text @click="setVisible">
diff --git a/src/components/Sticky/src/Sticky.vue b/src/components/Sticky/src/Sticky.vue
index 5d668059..bf9fc56b 100644
--- a/src/components/Sticky/src/Sticky.vue
+++ b/src/components/Sticky/src/Sticky.vue
@@ -1,7 +1,8 @@
-<script setup lang="ts">
+<script lang="ts" name="Sticky" setup>
 import { propTypes } from '@/utils/propTypes'
 import { isClient, useEventListener, useWindowSize } from '@vueuse/core'
 import type { CSSProperties } from 'vue'
+
 const props = defineProps({
   // 距离顶部或者底部的距离(单位px)
   offset: propTypes.number.def(0),
@@ -120,7 +121,7 @@ const reset = () => {
 }
 </script>
 <template>
-  <div :style="{ height: height, zIndex: zIndex }" ref="refSticky">
+  <div ref="refSticky" :style="{ height: height, zIndex: zIndex }">
     <div
       :class="className"
       :style="{
diff --git a/src/components/Tooltip/src/Tooltip.vue b/src/components/Tooltip/src/Tooltip.vue
index cad1cd29..eac37adb 100644
--- a/src/components/Tooltip/src/Tooltip.vue
+++ b/src/components/Tooltip/src/Tooltip.vue
@@ -1,5 +1,6 @@
-<script setup lang="ts">
+<script lang="ts" name="Tooltip" setup>
 import { propTypes } from '@/utils/propTypes'
+
 defineProps({
   titel: propTypes.string.def(''),
   message: propTypes.string.def(''),
diff --git a/src/components/Verifition/src/Verify.vue b/src/components/Verifition/src/Verify.vue
index 6bfc353e..861ed163 100644
--- a/src/components/Verifition/src/Verify.vue
+++ b/src/components/Verifition/src/Verify.vue
@@ -1,42 +1,42 @@
 <template>
-  <div :class="mode == 'pop' ? 'mask' : ''" v-show="showBox">
+  <div v-show="showBox" :class="mode == 'pop' ? 'mask' : ''">
     <div
       :class="mode == 'pop' ? 'verifybox' : ''"
       :style="{ 'max-width': parseInt(imgSize.width) + 20 + 'px' }"
     >
-      <div class="verifybox-top" v-if="mode == 'pop'">
+      <div v-if="mode == 'pop'" class="verifybox-top">
         {{ t('captcha.verification') }}
         <span class="verifybox-close" @click="closeBox">
           <i class="iconfont icon-close"></i>
         </span>
       </div>
-      <div class="verifybox-bottom" :style="{ padding: mode == 'pop' ? '10px' : '0' }">
+      <div :style="{ padding: mode == 'pop' ? '10px' : '0' }" class="verifybox-bottom">
         <!-- 验证码容器 -->
         <component
-          v-if="componentType"
           :is="componentType"
-          :captchaType="captchaType"
-          :type="verifyType"
-          :figure="figure"
-          :arith="arith"
-          :mode="mode"
-          :vSpace="vSpace"
-          :explain="explain"
-          :imgSize="imgSize"
-          :blockSize="blockSize"
-          :barSize="barSize"
+          v-if="componentType"
           ref="instance"
+          :arith="arith"
+          :barSize="barSize"
+          :blockSize="blockSize"
+          :captchaType="captchaType"
+          :explain="explain"
+          :figure="figure"
+          :imgSize="imgSize"
+          :mode="mode"
+          :type="verifyType"
+          :vSpace="vSpace"
         />
       </div>
     </div>
   </div>
 </template>
-<script type="text/babel">
+<script name="Verify" type="text/babel">
 /**
  * Verify 验证码组件
  * @description 分发验证码使用
  * */
-import { VerifySlide, VerifyPoints } from './Verify'
+import { VerifyPoints, VerifySlide } from './Verify'
 import { computed, ref, toRefs, watchEffect } from 'vue'
 
 export default {
@@ -155,6 +155,7 @@ export default {
   border-radius: 5px;
   transform: translate(-50%, -50%);
 }
+
 .verifybox-top {
   padding: 0 15px;
   height: 40px;
@@ -165,10 +166,12 @@ export default {
   border-bottom: 1px solid #e4e7eb;
   box-sizing: border-box;
 }
+
 .verifybox-bottom {
   padding: 10px;
   box-sizing: border-box;
 }
+
 .verifybox-close {
   position: absolute;
   top: 13px;
@@ -178,6 +181,7 @@ export default {
   text-align: center;
   cursor: pointer;
 }
+
 .mask {
   position: fixed;
   top: 0;
@@ -189,6 +193,7 @@ export default {
   /* display: none; */
   transition: all 0.5s;
 }
+
 .verify-tips {
   text-indent: 10px;
   position: absolute;
@@ -199,22 +204,27 @@ export default {
   line-height: 30px;
   color: #fff;
 }
+
 .suc-bg {
   background-color: rgba(92, 184, 92, 0.5);
   filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7f5CB85C, endcolorstr=#7f5CB85C);
 }
+
 .err-bg {
   background-color: rgba(217, 83, 79, 0.5);
   filter: progid:DXImageTransform.Microsoft.gradient(startcolorstr=#7fD9534F, endcolorstr=#7fD9534F);
 }
+
 .tips-enter,
 .tips-leave-to {
   bottom: -30px;
 }
+
 .tips-enter-active,
 .tips-leave-active {
   transition: bottom 0.5s;
 }
+
 /* ---------------------------- */
 /*常规验证码*/
 .verify-code {
diff --git a/src/components/Verifition/src/Verify/VerifyPoints.vue b/src/components/Verifition/src/Verify/VerifyPoints.vue
index 0e1fade7..5537c6e3 100644
--- a/src/components/Verifition/src/Verify/VerifyPoints.vue
+++ b/src/components/Verifition/src/Verify/VerifyPoints.vue
@@ -2,20 +2,20 @@
   <div style="position: relative">
     <div class="verify-img-out">
       <div
-        class="verify-img-panel"
         :style="{
           width: setSize.imgWidth,
           height: setSize.imgHeight,
           'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
           'margin-bottom': vSpace + 'px'
         }"
+        class="verify-img-panel"
       >
-        <div class="verify-refresh" style="z-index: 3" @click="refresh" v-show="showRefresh">
+        <div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
           <i class="iconfont icon-refresh"></i>
         </div>
         <img
-          :src="'data:image/png;base64,' + pointBackImgBase"
           ref="canvas"
+          :src="'data:image/png;base64,' + pointBackImgBase"
           alt=""
           style="width: 100%; height: 100%; display: block"
           @click="bindingClick ? canvasClick($event) : undefined"
@@ -24,7 +24,6 @@
         <div
           v-for="(tempPoint, index) in tempPoints"
           :key="index"
-          class="point-area"
           :style="{
             'background-color': '#1abd6c',
             color: '#fff',
@@ -38,6 +37,7 @@
             top: parseInt(tempPoint.y - 10) + 'px',
             left: parseInt(tempPoint.x - 10) + 'px'
           }"
+          class="point-area"
         >
           {{ index + 1 }}
         </div>
@@ -45,19 +45,19 @@
     </div>
     <!-- 'height': this.barSize.height, -->
     <div
-      class="verify-bar-area"
       :style="{
         width: setSize.imgWidth,
         color: barAreaColor,
         'border-color': barAreaBorderColor,
         'line-height': barSize.height
       }"
+      class="verify-bar-area"
     >
       <span class="verify-msg">{{ text }}</span>
     </div>
   </div>
 </template>
-<script type="text/babel" setup>
+<script name="VerifyPoints" setup type="text/babel">
 /**
  * VerifyPoints
  * @description 点选
@@ -65,7 +65,7 @@
 import { resetSize } from './../utils/util'
 import { aesEncrypt } from './../utils/ase'
 import { getCode, reqCheck } from '@/api/login'
-import { onMounted, reactive, ref, nextTick, toRefs, getCurrentInstance } from 'vue'
+import { getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs } from 'vue'
 
 const props = defineProps({
   //弹出式pop,固定fixed
diff --git a/src/components/Verifition/src/Verify/VerifySlide.vue b/src/components/Verifition/src/Verify/VerifySlide.vue
index 3961b129..68d8685d 100644
--- a/src/components/Verifition/src/Verify/VerifySlide.vue
+++ b/src/components/Verifition/src/Verify/VerifySlide.vue
@@ -2,20 +2,20 @@
   <div style="position: relative">
     <div
       v-if="type === '2'"
-      class="verify-img-out"
       :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }"
+      class="verify-img-out"
     >
-      <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
+      <div :style="{ width: setSize.imgWidth, height: setSize.imgHeight }" class="verify-img-panel">
         <img
           :src="'data:image/png;base64,' + backImgBase"
           alt=""
           style="width: 100%; height: 100%; display: block"
         />
-        <div class="verify-refresh" @click="refresh" v-show="showRefresh">
+        <div v-show="showRefresh" class="verify-refresh" @click="refresh">
           <i class="iconfont icon-refresh"></i>
         </div>
         <transition name="tips">
-          <span class="verify-tips" v-if="tipWords" :class="passFlag ? 'suc-bg' : 'err-bg'">
+          <span v-if="tipWords" :class="passFlag ? 'suc-bg' : 'err-bg'" class="verify-tips">
             {{ tipWords }}
           </span>
         </transition>
@@ -23,24 +23,21 @@
     </div>
     <!-- 公共部分 -->
     <div
-      class="verify-bar-area"
       :style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }"
+      class="verify-bar-area"
     >
       <span class="verify-msg" v-text="text"></span>
       <div
-        class="verify-left-bar"
         :style="{
           width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
           height: barSize.height,
           'border-color': leftBarBorderColor,
           transaction: transitionWidth
         }"
+        class="verify-left-bar"
       >
         <span class="verify-msg" v-text="finishText"></span>
         <div
-          class="verify-move-block"
-          @touchstart="start"
-          @mousedown="start"
           :style="{
             width: barSize.height,
             height: barSize.height,
@@ -48,17 +45,20 @@
             left: moveBlockLeft,
             transition: transitionLeft
           }"
+          class="verify-move-block"
+          @mousedown="start"
+          @touchstart="start"
         >
           <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }"></i>
           <div
             v-if="type === '2'"
-            class="verify-sub-block"
             :style="{
               width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
               height: setSize.imgHeight,
               top: '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
               'background-size': setSize.imgWidth + ' ' + setSize.imgHeight
             }"
+            class="verify-sub-block"
           >
             <img
               :src="'data:image/png;base64,' + blockBackImgBase"
@@ -71,7 +71,7 @@
     </div>
   </div>
 </template>
-<script type="text/babel" setup>
+<script name="VerifySlide" setup type="text/babel">
 /**
  * VerifySlide
  * @description 滑块
diff --git a/src/components/XButton/src/XButton.vue b/src/components/XButton/src/XButton.vue
index 3ef71230..e68dff24 100644
--- a/src/components/XButton/src/XButton.vue
+++ b/src/components/XButton/src/XButton.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="XButton" setup>
 import { PropType } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 
@@ -30,9 +30,9 @@ const getBindValue = computed(() => {
 
 <template>
   <el-button v-bind="getBindValue" @click="onClick">
-    <Icon :icon="preIcon" v-if="preIcon" class="mr-1px" />
+    <Icon v-if="preIcon" :icon="preIcon" class="mr-1px" />
     {{ title ? title : '' }}
-    <Icon :icon="postIcon" v-if="postIcon" class="mr-1px" />
+    <Icon v-if="postIcon" :icon="postIcon" class="mr-1px" />
   </el-button>
 </template>
 <style lang="scss" scoped>
@@ -40,6 +40,7 @@ const getBindValue = computed(() => {
   margin-left: 0;
   padding: 8px 4px;
 }
+
 :deep(.el-button.is-link) {
   margin-left: 0;
   padding: 8px 4px;
diff --git a/src/components/XButton/src/XTextButton.vue b/src/components/XButton/src/XTextButton.vue
index a256a985..c2ff9796 100644
--- a/src/components/XButton/src/XTextButton.vue
+++ b/src/components/XButton/src/XTextButton.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="XTextButton" setup>
 import { propTypes } from '@/utils/propTypes'
 import { PropType } from 'vue'
 
@@ -29,9 +29,9 @@ const getBindValue = computed(() => {
 
 <template>
   <el-button link v-bind="getBindValue" @click="onClick">
-    <Icon :icon="preIcon" v-if="preIcon" class="mr-1px" />
+    <Icon v-if="preIcon" :icon="preIcon" class="mr-1px" />
     {{ title ? title : '' }}
-    <Icon :icon="postIcon" v-if="postIcon" class="mr-1px" />
+    <Icon v-if="postIcon" :icon="postIcon" class="mr-1px" />
   </el-button>
 </template>
 <style lang="scss" scoped>
@@ -39,6 +39,7 @@ const getBindValue = computed(() => {
   margin-left: 0;
   padding: 8px 4px;
 }
+
 :deep(.el-button.is-link) {
   margin-left: 0;
   padding: 8px 4px;
diff --git a/src/layout/components/AppView.vue b/src/layout/components/AppView.vue
index dda59ed1..bf35ebe3 100644
--- a/src/layout/components/AppView.vue
+++ b/src/layout/components/AppView.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="AppView" setup>
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import { useAppStore } from '@/store/modules/app'
 import { Footer } from '@/layout/components/Footer'
diff --git a/src/layout/components/Collapse/src/Collapse.vue b/src/layout/components/Collapse/src/Collapse.vue
index a8f47dc6..523c34d4 100644
--- a/src/layout/components/Collapse/src/Collapse.vue
+++ b/src/layout/components/Collapse/src/Collapse.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Collapse" setup>
 import { useAppStore } from '@/store/modules/app'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -24,9 +24,9 @@ const toggleCollapse = () => {
 <template>
   <div :class="prefixCls">
     <Icon
-      :size="18"
-      :icon="collapse ? 'ep:expand' : 'ep:fold'"
       :color="color"
+      :icon="collapse ? 'ep:expand' : 'ep:fold'"
+      :size="18"
       class="cursor-pointer"
       @click="toggleCollapse"
     />
diff --git a/src/layout/components/ContextMenu/src/ContextMenu.vue b/src/layout/components/ContextMenu/src/ContextMenu.vue
index 8c18f2a1..de819692 100644
--- a/src/layout/components/ContextMenu/src/ContextMenu.vue
+++ b/src/layout/components/ContextMenu/src/ContextMenu.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ContextMenu" setup>
 import { PropType } from 'vue'
 
 import { useDesign } from '@/hooks/web/useDesign'
@@ -51,9 +51,9 @@ defineExpose({
     :class="prefixCls"
     :trigger="trigger"
     placement="bottom-start"
+    popper-class="v-context-menu-popper"
     @command="command"
     @visible-change="visibleChange"
-    popper-class="v-context-menu-popper"
   >
     <slot></slot>
     <template #dropdown>
@@ -61,11 +61,12 @@ defineExpose({
         <ElDropdownItem
           v-for="(item, index) in schema"
           :key="`dropdown${index}`"
-          :divided="item.divided"
-          :disabled="item.disabled"
           :command="item"
+          :disabled="item.disabled"
+          :divided="item.divided"
         >
-          <Icon :icon="item.icon" /> {{ t(item.label) }}
+          <Icon :icon="item.icon" />
+          {{ t(item.label) }}
         </ElDropdownItem>
       </ElDropdownMenu>
     </template>
diff --git a/src/layout/components/Footer/src/Footer.vue b/src/layout/components/Footer/src/Footer.vue
index 239812c6..c9fcd896 100644
--- a/src/layout/components/Footer/src/Footer.vue
+++ b/src/layout/components/Footer/src/Footer.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Footer" setup>
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 
diff --git a/src/layout/components/LocaleDropdown/src/LocaleDropdown.vue b/src/layout/components/LocaleDropdown/src/LocaleDropdown.vue
index 0e56724b..d16fbb2a 100644
--- a/src/layout/components/LocaleDropdown/src/LocaleDropdown.vue
+++ b/src/layout/components/LocaleDropdown/src/LocaleDropdown.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="LocaleDropdown" setup>
 import { useLocaleStore } from '@/store/modules/locale'
 import { useLocale } from '@/hooks/web/useLocale'
 import { propTypes } from '@/utils/propTypes'
@@ -33,11 +33,11 @@ const setLang = (lang: LocaleType) => {
 <template>
   <ElDropdown :class="prefixCls" trigger="click" @command="setLang">
     <Icon
-      :size="18"
-      icon="ion:language-sharp"
-      class="cursor-pointer"
       :class="$attrs.class"
       :color="color"
+      :size="18"
+      class="cursor-pointer"
+      icon="ion:language-sharp"
     />
     <template #dropdown>
       <ElDropdownMenu>
diff --git a/src/layout/components/Logo/src/Logo.vue b/src/layout/components/Logo/src/Logo.vue
index 9b70a0dc..17bdf1af 100644
--- a/src/layout/components/Logo/src/Logo.vue
+++ b/src/layout/components/Logo/src/Logo.vue
@@ -1,5 +1,5 @@
-<script setup lang="ts">
-import { ref, watch, computed, onMounted, unref } from 'vue'
+<script lang="ts" name="Logo" setup>
+import { computed, onMounted, ref, unref, watch } from 'vue'
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 
@@ -66,8 +66,8 @@ watch(
       to="/"
     >
       <img
-        src="@/assets/imgs/logo.png"
         class="w-[calc(var(--logo-height)-10px)] h-[calc(var(--logo-height)-10px)]"
+        src="@/assets/imgs/logo.png"
       />
       <div
         v-if="show"
diff --git a/src/layout/components/Message/src/Message.vue b/src/layout/components/Message/src/Message.vue
index d968eb6f..444e4611 100644
--- a/src/layout/components/Message/src/Message.vue
+++ b/src/layout/components/Message/src/Message.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="Message" setup>
 import { formatDate } from '@/utils/formatTime'
 import * as NotifyMessageApi from '@/api/system/notify/message'
 
@@ -40,10 +40,10 @@ onMounted(() => {
 </script>
 <template>
   <div class="message">
-    <ElPopover placement="bottom" :width="400" trigger="click">
+    <ElPopover :width="400" placement="bottom" trigger="click">
       <template #reference>
         <ElBadge :is-dot="unreadCount > 0" class="item">
-          <Icon icon="ep:bell" :size="18" class="cursor-pointer" @click="getList" />
+          <Icon :size="18" class="cursor-pointer" icon="ep:bell" @click="getList" />
         </ElBadge>
       </template>
       <ElTabs v-model="activeName">
@@ -51,7 +51,7 @@ onMounted(() => {
           <div class="message-list">
             <template v-for="item in list" :key="item.id">
               <div class="message-item">
-                <img src="@/assets/imgs/avatar.gif" alt="" class="message-icon" />
+                <img alt="" class="message-icon" src="@/assets/imgs/avatar.gif" />
                 <div class="message-content">
                   <span class="message-title">
                     {{ item.templateNickname }}:{{ item.templateContent }}
@@ -67,12 +67,12 @@ onMounted(() => {
       </ElTabs>
       <!-- 更多 -->
       <div style="text-align: right; margin-top: 10px">
-        <XButton type="primary" preIcon="ep:view" title="查看全部" @click="goMyList" />
+        <XButton preIcon="ep:view" title="查看全部" type="primary" @click="goMyList" />
       </div>
     </ElPopover>
   </div>
 </template>
-<style scoped lang="scss">
+<style lang="scss" scoped>
 .message-empty {
   display: flex;
   flex-direction: column;
@@ -81,28 +81,35 @@ onMounted(() => {
   height: 260px;
   line-height: 45px;
 }
+
 .message-list {
   display: flex;
   flex-direction: column;
+
   .message-item {
     display: flex;
     align-items: center;
     padding: 20px 0;
     border-bottom: 1px solid var(--el-border-color-light);
+
     &:last-child {
       border: none;
     }
+
     .message-icon {
       width: 40px;
       height: 40px;
       margin: 0 20px 0 5px;
     }
+
     .message-content {
       display: flex;
       flex-direction: column;
+
       .message-title {
         margin-bottom: 5px;
       }
+
       .message-date {
         font-size: 12px;
         color: var(--el-text-color-secondary);
diff --git a/src/layout/components/Screenfull/src/Screenfull.vue b/src/layout/components/Screenfull/src/Screenfull.vue
index 32a12e73..d0c4c44c 100644
--- a/src/layout/components/Screenfull/src/Screenfull.vue
+++ b/src/layout/components/Screenfull/src/Screenfull.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ScreenFull" setup>
 import { Icon } from '@/components/Icon'
 import { useFullscreen } from '@vueuse/core'
 import { propTypes } from '@/utils/propTypes'
@@ -22,9 +22,9 @@ const toggleFullscreen = () => {
 <template>
   <div :class="prefixCls" @click="toggleFullscreen">
     <Icon
-      :size="18"
-      :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
       :color="color"
+      :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'"
+      :size="18"
     />
   </div>
 </template>
diff --git a/src/layout/components/Setting/src/Setting.vue b/src/layout/components/Setting/src/Setting.vue
index de0532fd..8a395a81 100644
--- a/src/layout/components/Setting/src/Setting.vue
+++ b/src/layout/components/Setting/src/Setting.vue
@@ -1,12 +1,12 @@
-<script setup lang="ts">
+<script lang="ts" name="Setting" setup>
 import { ElMessage } from 'element-plus'
-import { useCssVar, useClipboard } from '@vueuse/core'
+import { useClipboard, useCssVar } from '@vueuse/core'
 
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
 import { useDesign } from '@/hooks/web/useDesign'
 
-import { trim, setCssVar } from '@/utils'
-import { colorIsDark, lighten, hexToRGB } from '@/utils/color'
+import { setCssVar, trim } from '@/utils'
+import { colorIsDark, hexToRGB, lighten } from '@/utils/color'
 import { useAppStore } from '@/store/modules/app'
 import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
 import ColorRadioPicker from './components/ColorRadioPicker.vue'
@@ -202,10 +202,10 @@ const clear = () => {
     class="fixed top-[45%] right-0 w-40px h-40px text-center leading-40px bg-[var(--el-color-primary)] cursor-pointer"
     @click="drawer = true"
   >
-    <Icon icon="ep:setting" color="#fff" />
+    <Icon color="#fff" icon="ep:setting" />
   </div>
 
-  <ElDrawer v-model="drawer" direction="rtl" size="350px" :z-index="4000">
+  <ElDrawer v-model="drawer" :z-index="4000" direction="rtl" size="350px">
     <template #header>
       <span class="text-16px font-700">{{ t('setting.projectSetting') }}</span>
     </template>
@@ -279,10 +279,10 @@ const clear = () => {
 
     <ElDivider />
     <div>
-      <ElButton type="primary" class="w-full" @click="copyConfig">{{ t('setting.copy') }}</ElButton>
+      <ElButton class="w-full" type="primary" @click="copyConfig">{{ t('setting.copy') }}</ElButton>
     </div>
     <div class="mt-5px">
-      <ElButton type="danger" class="w-full" @click="clear">
+      <ElButton class="w-full" type="danger" @click="clear">
         {{ t('setting.clearAndReset') }}
       </ElButton>
     </div>
diff --git a/src/layout/components/Setting/src/components/ColorRadioPicker.vue b/src/layout/components/Setting/src/components/ColorRadioPicker.vue
index 7c5e2404..8ef0f8c0 100644
--- a/src/layout/components/Setting/src/components/ColorRadioPicker.vue
+++ b/src/layout/components/Setting/src/components/ColorRadioPicker.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ColorRadioPicker" setup>
 import { PropType } from 'vue'
 import { propTypes } from '@/utils/propTypes'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -42,14 +42,14 @@ watch(
     <span
       v-for="(item, i) in schema"
       :key="`radio-${i}`"
-      class="w-20px h-20px cursor-pointer rounded-2px border-solid border-gray-300 border-2px text-center leading-20px mb-5px"
       :class="{ 'is-active': colorVal === item }"
       :style="{
         background: item
       }"
+      class="w-20px h-20px cursor-pointer rounded-2px border-solid border-gray-300 border-2px text-center leading-20px mb-5px"
       @click="colorVal = item"
     >
-      <Icon v-if="colorVal === item" color="#fff" icon="ep:check" :size="16" />
+      <Icon v-if="colorVal === item" :size="16" color="#fff" icon="ep:check" />
     </span>
   </div>
 </template>
diff --git a/src/layout/components/Setting/src/components/InterfaceDisplay.vue b/src/layout/components/Setting/src/components/InterfaceDisplay.vue
index e0dc0885..12f6fbc0 100644
--- a/src/layout/components/Setting/src/components/InterfaceDisplay.vue
+++ b/src/layout/components/Setting/src/components/InterfaceDisplay.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="InterfaceDisplay" setup>
 import { setCssVar } from '@/utils'
 
 import { useDesign } from '@/hooks/web/useDesign'
diff --git a/src/layout/components/Setting/src/components/LayoutRadioPicker.vue b/src/layout/components/Setting/src/components/LayoutRadioPicker.vue
index 07dbab95..b500683a 100644
--- a/src/layout/components/Setting/src/components/LayoutRadioPicker.vue
+++ b/src/layout/components/Setting/src/components/LayoutRadioPicker.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="LayoutRadioPicker" setup>
 import { useAppStore } from '@/store/modules/app'
 import { useDesign } from '@/hooks/web/useDesign'
 
diff --git a/src/layout/components/SizeDropdown/src/SizeDropdown.vue b/src/layout/components/SizeDropdown/src/SizeDropdown.vue
index 0dc698c0..d191dbe2 100644
--- a/src/layout/components/SizeDropdown/src/SizeDropdown.vue
+++ b/src/layout/components/SizeDropdown/src/SizeDropdown.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="SizeDropdown" setup>
 import { useAppStore } from '@/store/modules/app'
 
 import { propTypes } from '@/utils/propTypes'
@@ -26,7 +26,7 @@ const setCurrentSize = (size: ElementPlusSize) => {
 
 <template>
   <ElDropdown :class="prefixCls" trigger="click" @command="setCurrentSize">
-    <Icon :size="18" icon="mdi:format-size" :color="color" class="cursor-pointer" />
+    <Icon :color="color" :size="18" class="cursor-pointer" icon="mdi:format-size" />
     <template #dropdown>
       <ElDropdownMenu>
         <ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">
diff --git a/src/layout/components/TagsView/src/TagsView.vue b/src/layout/components/TagsView/src/TagsView.vue
index d6e9768d..6b4f7be7 100644
--- a/src/layout/components/TagsView/src/TagsView.vue
+++ b/src/layout/components/TagsView/src/TagsView.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="TagsView" setup>
 import type { RouteLocationNormalizedLoaded, RouterLinkProps } from 'vue-router'
 import { usePermissionStore } from '@/store/modules/permission'
 import { useTagsViewStore } from '@/store/modules/tagsView'
@@ -266,15 +266,24 @@ watch(
       @click="move(-200)"
     >
       <Icon
-        icon="ep:d-arrow-left"
         :color="appStore.getIsDark ? 'var(--el-text-color-regular)' : '#333'"
+        icon="ep:d-arrow-left"
       />
     </span>
     <div class="overflow-hidden flex-1">
       <ElScrollbar ref="scrollbarRef" class="h-full" @scroll="scroll">
         <div class="flex h-full">
           <ContextMenu
+            v-for="item in visitedViews"
+            :key="item.fullPath"
             :ref="itemRefs.set"
+            :class="[
+              `${prefixCls}__item`,
+              item?.meta?.affix ? `${prefixCls}__item--affix` : '',
+              {
+                'is-active': isActive(item)
+              }
+            ]"
             :schema="[
               {
                 icon: 'ep:refresh',
@@ -332,23 +341,14 @@ watch(
                 }
               }
             ]"
-            v-for="item in visitedViews"
-            :key="item.fullPath"
             :tag-item="item"
-            :class="[
-              `${prefixCls}__item`,
-              item?.meta?.affix ? `${prefixCls}__item--affix` : '',
-              {
-                'is-active': isActive(item)
-              }
-            ]"
             @visible-change="visibleChange"
           >
             <div>
-              <router-link :ref="tagLinksRefs.set" :to="{ ...item }" custom v-slot="{ navigate }">
+              <router-link :ref="tagLinksRefs.set" v-slot="{ navigate }" :to="{ ...item }" custom>
                 <div
-                  @click="navigate"
                   class="h-full flex justify-center items-center whitespace-nowrap pl-15px"
+                  @click="navigate"
                 >
                   <Icon
                     v-if="
@@ -364,9 +364,9 @@ watch(
                   {{ t(item?.meta?.title as string) }}
                   <Icon
                     :class="`${prefixCls}__item--close`"
+                    :size="12"
                     color="#333"
                     icon="ep:close"
-                    :size="12"
                     @click.prevent.stop="closeSelectedTag(item)"
                   />
                 </div>
@@ -382,8 +382,8 @@ watch(
       @click="move(200)"
     >
       <Icon
-        icon="ep:d-arrow-right"
         :color="appStore.getIsDark ? 'var(--el-text-color-regular)' : '#333'"
+        icon="ep:d-arrow-right"
       />
     </span>
     <span
@@ -392,12 +392,11 @@ watch(
       @click="refreshSelectedTag(selectedTag)"
     >
       <Icon
-        icon="ep:refresh-right"
         :color="appStore.getIsDark ? 'var(--el-text-color-regular)' : '#333'"
+        icon="ep:refresh-right"
       />
     </span>
     <ContextMenu
-      trigger="click"
       :schema="[
         {
           icon: 'ep:refresh',
@@ -449,14 +448,15 @@ watch(
           }
         }
       ]"
+      trigger="click"
     >
       <span
         :class="`${prefixCls}__tool`"
         class="w-[var(--tags-view-height)] h-[var(--tags-view-height)] text-center leading-[var(--tags-view-height)] cursor-pointer block"
       >
         <Icon
-          icon="ep:menu"
           :color="appStore.getIsDark ? 'var(--el-text-color-regular)' : '#333'"
+          icon="ep:menu"
         />
       </span>
     </ContextMenu>
@@ -513,6 +513,7 @@ $prefix-cls: #{$namespace}-tags-view;
       display: none;
       transform: translate(0, -50%);
     }
+
     &:not(.#{$prefix-cls}__item--affix):hover {
       .#{$prefix-cls}__item--close {
         display: block;
@@ -530,6 +531,7 @@ $prefix-cls: #{$namespace}-tags-view;
     color: var(--el-color-white);
     background-color: var(--el-color-primary);
     border: 1px solid var(--el-color-primary);
+
     .#{$prefix-cls}__item--close {
       :deep(span) {
         color: var(--el-color-white) !important;
@@ -573,6 +575,7 @@ $prefix-cls: #{$namespace}-tags-view;
     &__item.is-active {
       color: var(--el-color-white);
       background-color: var(--el-color-primary);
+
       .#{$prefix-cls}__item--close {
         :deep(span) {
           color: var(--el-color-white) !important;
diff --git a/src/layout/components/ThemeSwitch/src/ThemeSwitch.vue b/src/layout/components/ThemeSwitch/src/ThemeSwitch.vue
index 45243011..5a926508 100644
--- a/src/layout/components/ThemeSwitch/src/ThemeSwitch.vue
+++ b/src/layout/components/ThemeSwitch/src/ThemeSwitch.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="ThemeSwitch" setup>
 import { useAppStore } from '@/store/modules/app'
 import { useIcon } from '@/hooks/web/useIcon'
 import { useDesign } from '@/hooks/web/useDesign'
@@ -26,14 +26,14 @@ const themeChange = (val: boolean) => {
 
 <template>
   <ElSwitch
-    :class="prefixCls"
     v-model="isDark"
-    inline-prompt
-    :border-color="blackColor"
-    :inactive-color="blackColor"
     :active-color="blackColor"
     :active-icon="Sun"
+    :border-color="blackColor"
+    :class="prefixCls"
+    :inactive-color="blackColor"
     :inactive-icon="CrescentMoon"
+    inline-prompt
     @change="themeChange"
   />
 </template>
diff --git a/src/layout/components/UserInfo/src/UserInfo.vue b/src/layout/components/UserInfo/src/UserInfo.vue
index 7ccadb57..20837540 100644
--- a/src/layout/components/UserInfo/src/UserInfo.vue
+++ b/src/layout/components/UserInfo/src/UserInfo.vue
@@ -1,4 +1,4 @@
-<script setup lang="ts">
+<script lang="ts" name="UserInfo" setup>
 import { ElMessageBox } from 'element-plus'
 
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
diff --git a/src/views/Error/403.vue b/src/views/Error/403.vue
index d477304b..cb106465 100644
--- a/src/views/Error/403.vue
+++ b/src/views/Error/403.vue
@@ -1,6 +1,6 @@
 <template>
   <Error type="403" @error-click="push('/')" />
 </template>
-<script setup lang="ts">
+<script lang="ts" name="Error403" setup>
 const { push } = useRouter()
 </script>
diff --git a/src/views/Error/404.vue b/src/views/Error/404.vue
index d1ccb62e..c55d3325 100644
--- a/src/views/Error/404.vue
+++ b/src/views/Error/404.vue
@@ -1,6 +1,6 @@
 <template>
   <Error @error-click="push('/')" />
 </template>
-<script setup lang="ts">
+<script lang="ts" name="Error404" setup>
 const { push } = useRouter()
 </script>
diff --git a/src/views/Error/500.vue b/src/views/Error/500.vue
index 9f784fd2..6cfe47b7 100644
--- a/src/views/Error/500.vue
+++ b/src/views/Error/500.vue
@@ -1,6 +1,6 @@
 <template>
   <Error type="500" @error-click="push('/')" />
 </template>
-<script setup lang="ts">
+<script lang="ts" name="Error500" setup>
 const { push } = useRouter()
 </script>
diff --git a/src/views/Home/Index2.vue b/src/views/Home/Index2.vue
index 0f588510..457aced3 100644
--- a/src/views/Home/Index2.vue
+++ b/src/views/Home/Index2.vue
@@ -1,26 +1,26 @@
 <template>
-  <el-row :gutter="20" justify="space-between" :class="prefixCls">
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="2">
+  <el-row :class="prefixCls" :gutter="20" justify="space-between">
+    <el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
+        <el-skeleton :loading="loading" :rows="2" animated>
           <template #default>
             <div :class="`${prefixCls}__item flex justify-between`">
               <div>
                 <div
                   :class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
                 >
-                  <Icon icon="svg-icon:peoples" :size="40" />
+                  <Icon :size="40" icon="svg-icon:peoples" />
                 </div>
               </div>
               <div class="flex flex-col justify-between">
-                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
-                  t('analysis.newUser')
-                }}</div>
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
+                  >{{ t('analysis.newUser') }}
+                </div>
                 <CountTo
-                  class="text-20px font-700 text-right"
-                  :start-val="0"
-                  :end-val="102400"
                   :duration="2600"
+                  :end-val="102400"
+                  :start-val="0"
+                  class="text-20px font-700 text-right"
                 />
               </div>
             </div>
@@ -29,27 +29,27 @@
       </el-card>
     </el-col>
 
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="2">
+    <el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
+        <el-skeleton :loading="loading" :rows="2" animated>
           <template #default>
             <div :class="`${prefixCls}__item flex justify-between`">
               <div>
                 <div
                   :class="`${prefixCls}__item--icon ${prefixCls}__item--message p-16px inline-block rounded-6px`"
                 >
-                  <Icon icon="svg-icon:message" :size="40" />
+                  <Icon :size="40" icon="svg-icon:message" />
                 </div>
               </div>
               <div class="flex flex-col justify-between">
-                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
-                  t('analysis.unreadInformation')
-                }}</div>
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
+                  >{{ t('analysis.unreadInformation') }}
+                </div>
                 <CountTo
-                  class="text-20px font-700 text-right"
-                  :start-val="0"
-                  :end-val="81212"
                   :duration="2600"
+                  :end-val="81212"
+                  :start-val="0"
+                  class="text-20px font-700 text-right"
                 />
               </div>
             </div>
@@ -58,27 +58,27 @@
       </el-card>
     </el-col>
 
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="2">
+    <el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
+        <el-skeleton :loading="loading" :rows="2" animated>
           <template #default>
             <div :class="`${prefixCls}__item flex justify-between`">
               <div>
                 <div
                   :class="`${prefixCls}__item--icon ${prefixCls}__item--money p-16px inline-block rounded-6px`"
                 >
-                  <Icon icon="svg-icon:money" :size="40" />
+                  <Icon :size="40" icon="svg-icon:money" />
                 </div>
               </div>
               <div class="flex flex-col justify-between">
-                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
-                  t('analysis.transactionAmount')
-                }}</div>
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
+                  >{{ t('analysis.transactionAmount') }}
+                </div>
                 <CountTo
-                  class="text-20px font-700 text-right"
-                  :start-val="0"
-                  :end-val="9280"
                   :duration="2600"
+                  :end-val="9280"
+                  :start-val="0"
+                  class="text-20px font-700 text-right"
                 />
               </div>
             </div>
@@ -87,27 +87,27 @@
       </el-card>
     </el-col>
 
-    <el-col :xl="6" :lg="6" :md="12" :sm="12" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="2">
+    <el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
+        <el-skeleton :loading="loading" :rows="2" animated>
           <template #default>
             <div :class="`${prefixCls}__item flex justify-between`">
               <div>
                 <div
                   :class="`${prefixCls}__item--icon ${prefixCls}__item--shopping p-16px inline-block rounded-6px`"
                 >
-                  <Icon icon="svg-icon:shopping" :size="40" />
+                  <Icon :size="40" icon="svg-icon:shopping" />
                 </div>
               </div>
               <div class="flex flex-col justify-between">
-                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`">{{
-                  t('analysis.totalShopping')
-                }}</div>
+                <div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
+                  >{{ t('analysis.totalShopping') }}
+                </div>
                 <CountTo
-                  class="text-20px font-700 text-right"
-                  :start-val="0"
-                  :end-val="13600"
                   :duration="2600"
+                  :end-val="13600"
+                  :start-val="0"
+                  class="text-20px font-700 text-right"
                 />
               </div>
             </div>
@@ -117,36 +117,36 @@
     </el-col>
   </el-row>
   <el-row :gutter="20" justify="space-between">
-    <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
+    <el-col :lg="10" :md="24" :sm="24" :xl="10" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
         <el-skeleton :loading="loading" animated>
-          <Echart :options="pieOptionsData" :height="300" />
+          <Echart :height="300" :options="pieOptionsData" />
         </el-skeleton>
       </el-card>
     </el-col>
-    <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
-      <el-card shadow="hover" class="mb-20px">
+    <el-col :lg="14" :md="24" :sm="24" :xl="14" :xs="24">
+      <el-card class="mb-20px" shadow="hover">
         <el-skeleton :loading="loading" animated>
-          <Echart :options="barOptionsData" :height="300" />
+          <Echart :height="300" :options="barOptionsData" />
         </el-skeleton>
       </el-card>
     </el-col>
     <el-col :span="24">
-      <el-card shadow="hover" class="mb-20px">
-        <el-skeleton :loading="loading" animated :rows="4">
-          <Echart :options="lineOptionsData" :height="350" />
+      <el-card class="mb-20px" shadow="hover">
+        <el-skeleton :loading="loading" :rows="4" animated>
+          <Echart :height="350" :options="lineOptionsData" />
         </el-skeleton>
       </el-card>
     </el-col>
   </el-row>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="Home2" setup>
 import { set } from 'lodash-es'
 import { EChartsOption } from 'echarts'
 
 import { useDesign } from '@/hooks/web/useDesign'
 import type { AnalysisTotalTypes } from './types'
-import { pieOptions, barOptions, lineOptions } from './echarts-data'
+import { barOptions, lineOptions, pieOptions } from './echarts-data'
 
 const { t } = useI18n()
 const loading = ref(true)
@@ -291,18 +291,23 @@ $prefix-cls: #{$namespace}-panel;
       :deep(.#{$namespace}-icon) {
         color: #fff !important;
       }
+
       .#{$prefix-cls}__item--icon {
         transition: all 0.38s ease-out;
       }
+
       .#{$prefix-cls}__item--peoples {
         background: #40c9c6;
       }
+
       .#{$prefix-cls}__item--message {
         background: #36a3f7;
       }
+
       .#{$prefix-cls}__item--money {
         background: #f4516c;
       }
+
       .#{$prefix-cls}__item--shopping {
         background: #34bfa3;
       }
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index a0186ab7..eb323d86 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -60,7 +60,7 @@
     </div>
   </div>
 </template>
-<script lang="ts" setup>
+<script lang="ts" name="Login" setup>
 import { underlineToHump } from '@/utils'
 
 import { useDesign } from '@/hooks/web/useDesign'
diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue
index 176aba3b..8f0b8b64 100644
--- a/src/views/Login/components/LoginForm.vue
+++ b/src/views/Login/components/LoginForm.vue
@@ -1,13 +1,13 @@
 <template>
   <el-form
-    :model="loginData.loginForm"
-    :rules="LoginRules"
-    label-position="top"
-    class="login-form"
-    label-width="120px"
-    size="large"
     v-show="getShow"
     ref="formLogin"
+    :model="loginData.loginForm"
+    :rules="LoginRules"
+    class="login-form"
+    label-position="top"
+    label-width="120px"
+    size="large"
   >
     <el-row style="maring-left: -10px; maring-right: -10px">
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
@@ -16,12 +16,12 @@
         </el-form-item>
       </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
-        <el-form-item prop="tenantName" v-if="loginData.tenantEnable === 'true'">
+        <el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
           <el-input
-            type="text"
             v-model="loginData.loginForm.tenantName"
             :placeholder="t('login.tenantNamePlaceholder')"
             :prefix-icon="iconHouse"
+            type="text"
           />
         </el-form-item>
       </el-col>
@@ -38,11 +38,11 @@
         <el-form-item prop="password">
           <el-input
             v-model="loginData.loginForm.password"
-            type="password"
             :placeholder="t('login.passwordPlaceholder')"
-            show-password
-            @keyup.enter="getCode()"
             :prefix-icon="iconLock"
+            show-password
+            type="password"
+            @keyup.enter="getCode()"
           />
         </el-form-item>
       </el-col>
@@ -57,8 +57,8 @@
                 {{ t('login.remember') }}
               </el-checkbox>
             </el-col>
-            <el-col :span="12" :offset="6">
-              <el-link type="primary" style="float: right">{{ t('login.forgetPassword') }}</el-link>
+            <el-col :offset="6" :span="12">
+              <el-link style="float: right" type="primary">{{ t('login.forgetPassword') }}</el-link>
             </el-col>
           </el-row>
         </el-form-item>
@@ -67,41 +67,41 @@
         <el-form-item>
           <XButton
             :loading="loginLoading"
-            type="primary"
-            class="w-[100%]"
             :title="t('login.login')"
+            class="w-[100%]"
+            type="primary"
             @click="getCode()"
           />
         </el-form-item>
       </el-col>
       <Verify
         ref="verify"
-        mode="pop"
         :captchaType="captchaType"
         :imgSize="{ width: '400px', height: '200px' }"
+        mode="pop"
         @success="handleLogin"
       />
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
         <el-form-item>
-          <el-row justify="space-between" style="width: 100%" :gutter="5">
+          <el-row :gutter="5" justify="space-between" style="width: 100%">
             <el-col :span="8">
               <XButton
-                class="w-[100%]"
                 :title="t('login.btnMobile')"
+                class="w-[100%]"
                 @click="setLoginState(LoginStateEnum.MOBILE)"
               />
             </el-col>
             <el-col :span="8">
               <XButton
-                class="w-[100%]"
                 :title="t('login.btnQRCode')"
+                class="w-[100%]"
                 @click="setLoginState(LoginStateEnum.QR_CODE)"
               />
             </el-col>
             <el-col :span="8">
               <XButton
-                class="w-[100%]"
                 :title="t('login.btnRegister')"
+                class="w-[100%]"
                 @click="setLoginState(LoginStateEnum.REGISTER)"
               />
             </el-col>
@@ -127,7 +127,7 @@
     </el-row>
   </el-form>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="LoginForm" setup>
 import { ElLoading } from 'element-plus'
 import LoginFormTitle from './LoginFormTitle.vue'
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
diff --git a/src/views/Login/components/LoginFormTitle.vue b/src/views/Login/components/LoginFormTitle.vue
index ea55be93..b192a5fa 100644
--- a/src/views/Login/components/LoginFormTitle.vue
+++ b/src/views/Login/components/LoginFormTitle.vue
@@ -3,7 +3,7 @@
     {{ getFormTitle }}
   </h2>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="LoginFormTitle" setup>
 import { LoginStateEnum, useLoginState } from './useLogin'
 
 const { t } = useI18n()
diff --git a/src/views/Login/components/MobileForm.vue b/src/views/Login/components/MobileForm.vue
index 3a0ab686..4c291f9e 100644
--- a/src/views/Login/components/MobileForm.vue
+++ b/src/views/Login/components/MobileForm.vue
@@ -1,13 +1,13 @@
 <template>
   <el-form
-    :model="loginData.loginForm"
-    :rules="rules"
-    label-position="top"
-    class="login-form"
-    label-width="120px"
-    size="large"
     v-show="getShow"
     ref="formSmsLogin"
+    :model="loginData.loginForm"
+    :rules="rules"
+    class="login-form"
+    label-position="top"
+    label-width="120px"
+    size="large"
   >
     <el-row style="margin-left: -10px; margin-right: -10px">
       <!-- 租户名 -->
@@ -17,12 +17,12 @@
         </el-form-item>
       </el-col>
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
-        <el-form-item prop="tenantName" v-if="loginData.tenantEnable === 'true'">
+        <el-form-item v-if="loginData.tenantEnable === 'true'" prop="tenantName">
           <el-input
-            type="text"
             v-model="loginData.loginForm.tenantName"
             :placeholder="t('login.tenantNamePlaceholder')"
             :prefix-icon="iconHouse"
+            type="text"
           />
         </el-form-item>
       </el-col>
@@ -39,7 +39,7 @@
       <!-- 验证码 -->
       <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
         <el-form-item prop="code">
-          <el-row justify="space-between" style="width: 100%" :gutter="5">
+          <el-row :gutter="5" justify="space-between" style="width: 100%">
             <el-col :span="24">
               <el-input
                 v-model="loginData.loginForm.code"
@@ -50,9 +50,9 @@
                 <template #append>
                   <span
                     v-if="mobileCodeTimer <= 0"
-                    @click="getSmsCode"
                     class="getMobileCode"
                     style="cursor: pointer"
+                    @click="getSmsCode"
                   >
                     {{ t('login.getSmsCode') }}
                   </span>
@@ -71,9 +71,9 @@
         <el-form-item>
           <XButton
             :loading="loginLoading"
-            type="primary"
-            class="w-[100%]"
             :title="t('login.login')"
+            class="w-[100%]"
+            type="primary"
             @click="signIn()"
           />
         </el-form-item>
@@ -82,8 +82,8 @@
         <el-form-item>
           <XButton
             :loading="loginLoading"
-            class="w-[100%]"
             :title="t('login.backLogin')"
+            class="w-[100%]"
             @click="handleBackLogin()"
           />
         </el-form-item>
@@ -91,7 +91,7 @@
     </el-row>
   </el-form>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="MobileForm" setup>
 import type { RouteLocationNormalizedLoaded } from 'vue-router'
 
 import { useIcon } from '@/hooks/web/useIcon'
@@ -100,7 +100,7 @@ import { setTenantId, setToken } from '@/utils/auth'
 import { usePermissionStore } from '@/store/modules/permission'
 import { getTenantIdByName, sendSmsCode, smsLogin } from '@/api/login'
 import LoginFormTitle from './LoginFormTitle.vue'
-import { useLoginState, LoginStateEnum, useFormValid } from './useLogin'
+import { LoginStateEnum, useFormValid, useLoginState } from './useLogin'
 
 const { t } = useI18n()
 const message = useMessage()
diff --git a/src/views/Login/components/QrCodeForm.vue b/src/views/Login/components/QrCodeForm.vue
index bdf7e2a5..c485d287 100644
--- a/src/views/Login/components/QrCodeForm.vue
+++ b/src/views/Login/components/QrCodeForm.vue
@@ -4,23 +4,23 @@
       <LoginFormTitle style="width: 100%" />
     </el-col>
     <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
-      <el-card shadow="hover" class="mb-10px text-center">
+      <el-card class="mb-10px text-center" shadow="hover">
         <Qrcode :logo="logoImg" />
       </el-card>
     </el-col>
     <el-divider class="enter-x">{{ t('login.qrcode') }}</el-divider>
     <el-col :span="24" style="padding-left: 10px; padding-right: 10px">
       <div class="w-[100%] mt-15px">
-        <XButton class="w-[100%]" :title="t('login.backLogin')" @click="handleBackLogin()" />
+        <XButton :title="t('login.backLogin')" class="w-[100%]" @click="handleBackLogin()" />
       </div>
     </el-col>
   </el-row>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="QrCodeForm" setup>
 import logoImg from '@/assets/imgs/logo.png'
 
 import LoginFormTitle from './LoginFormTitle.vue'
-import { useLoginState, LoginStateEnum } from './useLogin'
+import { LoginStateEnum, useLoginState } from './useLogin'
 
 const { t } = useI18n()
 const { handleBackLogin, getLoginState } = useLoginState()
diff --git a/src/views/Login/components/RegisterForm.vue b/src/views/Login/components/RegisterForm.vue
index 7d048506..de6b5967 100644
--- a/src/views/Login/components/RegisterForm.vue
+++ b/src/views/Login/components/RegisterForm.vue
@@ -1,12 +1,12 @@
 <template>
   <Form
-    :schema="schema"
-    :rules="rules"
-    label-position="top"
-    hide-required-asterisk
-    size="large"
     v-show="getShow"
+    :rules="rules"
+    :schema="schema"
     class="dark:(border-1 border-[var(--el-border-color)] border-solid)"
+    hide-required-asterisk
+    label-position="top"
+    size="large"
     @register="register"
   >
     <template #title>
@@ -23,25 +23,25 @@
       <div class="w-[100%]">
         <XButton
           :loading="loading"
-          type="primary"
-          class="w-[100%]"
           :title="t('login.register')"
+          class="w-[100%]"
+          type="primary"
           @click="loginRegister()"
         />
       </div>
       <div class="w-[100%] mt-15px">
-        <XButton class="w-[100%]" :title="t('login.hasUser')" @click="handleBackLogin()" />
+        <XButton :title="t('login.hasUser')" class="w-[100%]" @click="handleBackLogin()" />
       </div>
     </template>
   </Form>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="RegisterForm" setup>
 import type { FormRules } from 'element-plus'
 
 import { useForm } from '@/hooks/web/useForm'
 import { useValidator } from '@/hooks/web/useValidator'
 import LoginFormTitle from './LoginFormTitle.vue'
-import { useLoginState, LoginStateEnum } from './useLogin'
+import { LoginStateEnum, useLoginState } from './useLogin'
 import { FormSchema } from '@/types/form'
 
 const { t } = useI18n()
diff --git a/src/views/Profile/components/BasicInfo.vue b/src/views/Profile/components/BasicInfo.vue
index f5e9da72..f3cc81c7 100644
--- a/src/views/Profile/components/BasicInfo.vue
+++ b/src/views/Profile/components/BasicInfo.vue
@@ -1,5 +1,5 @@
 <template>
-  <Form ref="formRef" :rules="rules" :schema="schema" :labelWidth="80">
+  <Form ref="formRef" :labelWidth="80" :rules="rules" :schema="schema">
     <template #sex="form">
       <el-radio-group v-model="form['sex']">
         <el-radio :label="1">{{ t('profile.user.man') }}</el-radio>
@@ -8,9 +8,9 @@
     </template>
   </Form>
   <XButton :title="t('common.save')" @click="submit()" />
-  <XButton type="danger" :title="t('common.reset')" @click="init()" />
+  <XButton :title="t('common.reset')" type="danger" @click="init()" />
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BasicInfo" setup>
 import type { FormRules } from 'element-plus'
 import { ElMessage } from 'element-plus'
 
diff --git a/src/views/Profile/components/ProfileUser.vue b/src/views/Profile/components/ProfileUser.vue
index 8657bc75..523985d4 100644
--- a/src/views/Profile/components/ProfileUser.vue
+++ b/src/views/Profile/components/ProfileUser.vue
@@ -5,41 +5,48 @@
     </div>
     <ul class="list-group list-group-striped">
       <li class="list-group-item">
-        <Icon icon="ep:user" class="mr-5px" />{{ t('profile.user.username') }}
+        <Icon class="mr-5px" icon="ep:user" />
+        {{ t('profile.user.username') }}
         <div class="pull-right">{{ userInfo?.username }}</div>
       </li>
       <li class="list-group-item">
-        <Icon icon="ep:phone" class="mr-5px" />{{ t('profile.user.mobile') }}
+        <Icon class="mr-5px" icon="ep:phone" />
+        {{ t('profile.user.mobile') }}
         <div class="pull-right">{{ userInfo?.mobile }}</div>
       </li>
       <li class="list-group-item">
-        <Icon icon="fontisto:email" class="mr-5px" />{{ t('profile.user.email') }}
+        <Icon class="mr-5px" icon="fontisto:email" />
+        {{ t('profile.user.email') }}
         <div class="pull-right">{{ userInfo?.email }}</div>
       </li>
       <li class="list-group-item">
-        <Icon icon="carbon:tree-view-alt" class="mr-5px" />{{ t('profile.user.dept') }}
-        <div class="pull-right" v-if="userInfo?.dept">{{ userInfo?.dept.name }}</div>
+        <Icon class="mr-5px" icon="carbon:tree-view-alt" />
+        {{ t('profile.user.dept') }}
+        <div v-if="userInfo?.dept" class="pull-right">{{ userInfo?.dept.name }}</div>
       </li>
       <li class="list-group-item">
-        <Icon icon="ep:suitcase" class="mr-5px" />{{ t('profile.user.posts') }}
-        <div class="pull-right" v-if="userInfo?.posts">
+        <Icon class="mr-5px" icon="ep:suitcase" />
+        {{ t('profile.user.posts') }}
+        <div v-if="userInfo?.posts" class="pull-right">
           {{ userInfo?.posts.map((post) => post.name).join(',') }}
         </div>
       </li>
       <li class="list-group-item">
-        <Icon icon="icon-park-outline:peoples" class="mr-5px" />{{ t('profile.user.roles') }}
-        <div class="pull-right" v-if="userInfo?.roles">
+        <Icon class="mr-5px" icon="icon-park-outline:peoples" />
+        {{ t('profile.user.roles') }}
+        <div v-if="userInfo?.roles" class="pull-right">
           {{ userInfo?.roles.map((role) => role.name).join(',') }}
         </div>
       </li>
       <li class="list-group-item">
-        <Icon icon="ep:calendar" class="mr-5px" />{{ t('profile.user.createTime') }}
+        <Icon class="mr-5px" icon="ep:calendar" />
+        {{ t('profile.user.createTime') }}
         <div class="pull-right">{{ formatDate(userInfo?.createTime) }}</div>
       </li>
     </ul>
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ProfileUser" setup>
 import { formatDate } from '@/utils/formatTime'
 import UserAvatar from './UserAvatar.vue'
 
@@ -62,6 +69,7 @@ onMounted(async () => {
   position: relative;
   height: 120px;
 }
+
 .list-group-striped > .list-group-item {
   border-left: 0;
   border-right: 0;
@@ -82,6 +90,7 @@ onMounted(async () => {
   padding: 11px 0px;
   font-size: 13px;
 }
+
 .pull-right {
   float: right !important;
 }
diff --git a/src/views/Profile/components/ResetPwd.vue b/src/views/Profile/components/ResetPwd.vue
index 0d6f9cc4..d348511e 100644
--- a/src/views/Profile/components/ResetPwd.vue
+++ b/src/views/Profile/components/ResetPwd.vue
@@ -10,13 +10,13 @@
       <InputPassword v-model="password.confirmPassword" strength />
     </el-form-item>
     <el-form-item>
-      <XButton type="primary" @click="submit(formRef)" :title="t('common.save')" />
-      <XButton type="danger" :title="t('common.reset')" @click="reset(formRef)" />
+      <XButton :title="t('common.save')" type="primary" @click="submit(formRef)" />
+      <XButton :title="t('common.reset')" type="danger" @click="reset(formRef)" />
     </el-form-item>
   </el-form>
 </template>
-<script setup lang="ts">
-import type { FormRules, FormInstance } from 'element-plus'
+<script lang="ts" name="ResetPwd" setup>
+import type { FormInstance, FormRules } from 'element-plus'
 
 import { InputPassword } from '@/components/InputPassword'
 import { updateUserPassword } from '@/api/system/user/profile'
diff --git a/src/views/Profile/components/UserAvatar.vue b/src/views/Profile/components/UserAvatar.vue
index 50a14d81..88dc8d9e 100644
--- a/src/views/Profile/components/UserAvatar.vue
+++ b/src/views/Profile/components/UserAvatar.vue
@@ -2,17 +2,18 @@
   <div class="change-avatar">
     <CropperAvatar
       ref="cropperRef"
-      :value="avatar"
-      :showBtn="false"
-      @change="handelUpload"
       :btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
+      :showBtn="false"
+      :value="avatar"
       width="120px"
+      @change="handelUpload"
     />
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="UserAvatar" setup>
 import { propTypes } from '@/utils/propTypes'
 import { uploadAvatar } from '@/api/system/user/profile'
+
 const props = defineProps({
   img: propTypes.string.def('')
 })
@@ -27,7 +28,7 @@ const handelUpload = async ({ data }) => {
 }
 </script>
 
-<style scoped lang="scss">
+<style lang="scss" scoped>
 .change-avatar {
   img {
     display: block;
diff --git a/src/views/bpm/form/editor/index.vue b/src/views/bpm/form/editor/index.vue
index 3a28697f..14a2c50f 100644
--- a/src/views/bpm/form/editor/index.vue
+++ b/src/views/bpm/form/editor/index.vue
@@ -4,14 +4,15 @@
     <fc-designer ref="designer" height="780px">
       <template #handle>
         <el-button round size="small" type="primary" @click="handleSave">
-          <Icon icon="ep:plus" class="mr-5px" /> 保存
+          <Icon class="mr-5px" icon="ep:plus" />
+          保存
         </el-button>
       </template>
     </fc-designer>
   </ContentWrap>
 
   <!-- 表单保存的弹窗 -->
-  <Dialog title="保存表单" v-model="dialogVisible" width="600">
+  <Dialog v-model="dialogVisible" title="保存表单" width="600">
     <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
       <el-form-item label="表单名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入表单名" />
@@ -28,16 +29,16 @@
         </el-radio-group>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
+        <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmFormEditor" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as FormApi from '@/api/bpm/form'
diff --git a/src/views/bpm/group/UserGroupForm.vue b/src/views/bpm/group/UserGroupForm.vue
index e8011d8c..1adbea15 100644
--- a/src/views/bpm/group/UserGroupForm.vue
+++ b/src/views/bpm/group/UserGroupForm.vue
@@ -1,17 +1,17 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="100px"
-      v-loading="formLoading"
     >
       <el-form-item label="组名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入组名" />
       </el-form-item>
       <el-form-item label="描述">
-        <el-input type="textarea" v-model="formData.name" placeholder="请输入描述" />
+        <el-input v-model="formData.name" placeholder="请输入描述" type="textarea" />
       </el-form-item>
       <el-form-item label="成员" prop="memberUserIds">
         <el-select v-model="formData.memberUserIds" multiple placeholder="请选择成员">
@@ -36,12 +36,12 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="UserGroupForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as UserGroupApi from '@/api/bpm/userGroup'
diff --git a/src/views/bpm/model/ModelForm.vue b/src/views/bpm/model/ModelForm.vue
index 24484ec6..1967e17f 100644
--- a/src/views/bpm/model/ModelForm.vue
+++ b/src/views/bpm/model/ModelForm.vue
@@ -1,45 +1,45 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" width="600">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="600">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="110px"
-      v-loading="formLoading"
     >
       <el-form-item label="流程标识" prop="key">
         <el-input
           v-model="formData.key"
+          :disabled="!!formData.id"
           placeholder="请输入流标标识"
           style="width: 330px"
-          :disabled="!!formData.id"
         />
         <el-tooltip
           v-if="!formData.id"
           class="item"
-          effect="light"
           content="新建后,流程标识不可修改!"
+          effect="light"
           placement="top"
         >
-          <i style="padding-left: 5px" class="el-icon-question"></i>
+          <i class="el-icon-question" style="padding-left: 5px"></i>
         </el-tooltip>
-        <el-tooltip v-else class="item" effect="light" content="流程标识不可修改!" placement="top">
-          <i style="padding-left: 5px" class="el-icon-question"></i>
+        <el-tooltip v-else class="item" content="流程标识不可修改!" effect="light" placement="top">
+          <i class="el-icon-question" style="padding-left: 5px"></i>
         </el-tooltip>
       </el-form-item>
       <el-form-item label="流程名称" prop="name">
         <el-input
           v-model="formData.name"
-          placeholder="请输入流程名称"
           :disabled="!!formData.id"
           clearable
+          placeholder="请输入流程名称"
         />
       </el-form-item>
       <el-form-item v-if="formData.id" label="流程分类" prop="category">
         <el-select
           v-model="formData.category"
-          placeholder="请选择流程分类"
           clearable
+          placeholder="请选择流程分类"
           style="width: 100%"
         >
           <el-option
@@ -51,7 +51,7 @@
         </el-select>
       </el-form-item>
       <el-form-item label="流程描述" prop="description">
-        <el-input type="textarea" v-model="formData.description" clearable />
+        <el-input v-model="formData.description" clearable type="textarea" />
       </el-form-item>
       <div v-if="formData.id">
         <el-form-item label="表单类型" prop="formType">
@@ -87,11 +87,11 @@
           />
           <el-tooltip
             class="item"
-            effect="light"
             content="自定义表单的提交路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/create"
+            effect="light"
             placement="top"
           >
-            <i style="padding-left: 5px" class="el-icon-question"></i>
+            <i class="el-icon-question" style="padding-left: 5px"></i>
           </el-tooltip>
         </el-form-item>
         <el-form-item
@@ -106,26 +106,27 @@
           />
           <el-tooltip
             class="item"
-            effect="light"
             content="自定义表单的查看路径,使用 Vue 的路由地址,例如说:bpm/oa/leave/view"
+            effect="light"
             placement="top"
           >
-            <i style="padding-left: 5px" class="el-icon-question"></i>
+            <i class="el-icon-question" style="padding-left: 5px"></i>
           </el-tooltip>
         </el-form-item>
       </div>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ModelForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { ElMessageBox } from 'element-plus'
 import * as ModelApi from '@/api/bpm/model'
 import * as FormApi from '@/api/bpm/form'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/bpm/model/ModelImportForm.vue b/src/views/bpm/model/ModelImportForm.vue
index 76493c95..ad2d0b66 100644
--- a/src/views/bpm/model/ModelImportForm.vue
+++ b/src/views/bpm/model/ModelImportForm.vue
@@ -1,24 +1,24 @@
 <template>
-  <Dialog title="导入流程" v-model="dialogVisible" width="400">
+  <Dialog v-model="dialogVisible" title="导入流程" width="400">
     <div>
       <el-upload
         ref="uploadRef"
-        :action="importUrl"
-        :headers="uploadHeaders"
-        :data="formData"
-        name="bpmnFile"
         v-model:file-list="fileList"
-        drag
+        :action="importUrl"
         :auto-upload="false"
-        accept=".bpmn, .xml"
+        :data="formData"
+        :disabled="formLoading"
+        :headers="uploadHeaders"
         :limit="1"
+        :on-error="submitFormError"
         :on-exceed="handleExceed"
         :on-success="submitFormSuccess"
-        :on-error="submitFormError"
-        :disabled="formLoading"
+        accept=".bpmn, .xml"
+        drag
+        name="bpmnFile"
       >
         <Icon class="el-icon--upload" icon="ep:upload-filled" />
-        <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em> </div>
+        <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em></div>
         <template #tip>
           <div class="el-upload__tip" style="color: red">
             提示:仅允许导入“bpm”或“xml”格式文件!
@@ -33,10 +33,10 @@
                 />
               </el-form-item>
               <el-form-item label="流程名称" prop="name">
-                <el-input v-model="formData.name" placeholder="请输入流程名称" clearable />
+                <el-input v-model="formData.name" clearable placeholder="请输入流程名称" />
               </el-form-item>
               <el-form-item label="流程描述" prop="description">
-                <el-input type="textarea" v-model="formData.description" clearable />
+                <el-input v-model="formData.description" clearable type="textarea" />
               </el-form-item>
             </el-form>
           </div>
@@ -44,13 +44,14 @@
       </el-upload>
     </div>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ModelImportForm" setup>
 import { getAccessToken, getTenantId } from '@/utils/auth'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/bpm/oa/leave/create.vue b/src/views/bpm/oa/leave/create.vue
index 321ec609..6bf7760e 100644
--- a/src/views/bpm/oa/leave/create.vue
+++ b/src/views/bpm/oa/leave/create.vue
@@ -1,14 +1,14 @@
 <template>
-  <Dialog title="发起 OA 请假流程" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="发起 OA 请假流程">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="请假类型" prop="type">
-        <el-select v-model="formData.type" placeholder="请选择请假类型" clearable>
+        <el-select v-model="formData.type" clearable placeholder="请选择请假类型">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
             :key="dict.value"
@@ -19,35 +19,36 @@
       </el-form-item>
       <el-form-item label="开始时间" prop="startTime">
         <el-date-picker
-          clearable
           v-model="formData.startTime"
+          clearable
+          placeholder="请选择开始时间"
           type="datetime"
           value-format="x"
-          placeholder="请选择开始时间"
         />
       </el-form-item>
       <el-form-item label="结束时间" prop="endTime">
         <el-date-picker
-          clearable
           v-model="formData.endTime"
+          clearable
+          placeholder="请选择结束时间"
           type="datetime"
           value-format="x"
-          placeholder="请选择结束时间"
         />
       </el-form-item>
       <el-form-item label="原因" prop="reason">
-        <el-input v-model="formData.reason" type="textarea" placeholder="请输请假原因" />
+        <el-input v-model="formData.reason" placeholder="请输请假原因" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmOALeaveCreate" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as LeaveApi from '@/api/bpm/leave'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/bpm/oa/leave/detail.vue b/src/views/bpm/oa/leave/detail.vue
index 838be149..caf07f50 100644
--- a/src/views/bpm/oa/leave/detail.vue
+++ b/src/views/bpm/oa/leave/detail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="200">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="200" :scroll="true" title="详情">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="请假类型">
         <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="detailData.type" />
       </el-descriptions-item>
@@ -16,7 +16,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmOALeaveDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as LeaveApi from '@/api/bpm/leave'
diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue b/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue
index 3a3e244b..684a9495 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceBpmnViewer.vue
@@ -1,20 +1,20 @@
 <template>
-  <el-card class="box-card" v-loading="loading">
+  <el-card v-loading="loading" class="box-card">
     <template #header>
       <span class="el-icon-picture-outline">流程图</span>
     </template>
     <my-process-viewer
       key="designer"
-      :value="bpmnXml"
-      v-bind="bpmnControlForm"
-      :prefix="bpmnControlForm.prefix"
       :activityData="activityList"
+      :prefix="bpmnControlForm.prefix"
       :processInstanceData="processInstance"
       :taskData="tasks"
+      :value="bpmnXml"
+      v-bind="bpmnControlForm"
     />
   </el-card>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmProcessInstanceBpmnViewer" setup>
 import { propTypes } from '@/utils/propTypes'
 import * as ActivityApi from '@/api/bpm/activity'
 // import * as DefinitionApi from '@/api/bpm/definition'
diff --git a/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue b/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue
index a8aa0120..dbb90753 100644
--- a/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue
+++ b/src/views/bpm/processInstance/detail/ProcessInstanceTaskList.vue
@@ -1,9 +1,9 @@
 <template>
-  <el-card class="box-card" v-loading="loading">
+  <el-card v-loading="loading" class="box-card">
     <template #header>
       <span class="el-icon-picture-outline">审批记录</span>
     </template>
-    <el-col :span="16" :offset="4">
+    <el-col :offset="4" :span="16">
       <div class="block">
         <el-timeline>
           <el-timeline-item
@@ -16,9 +16,9 @@
             <el-card :body-style="{ padding: '10px' }">
               <label v-if="item.assigneeUser" style="font-weight: normal; margin-right: 30px">
                 审批人:{{ item.assigneeUser.nickname }}
-                <el-tag type="info" size="small">{{ item.assigneeUser.deptName }}</el-tag>
+                <el-tag size="small" type="info">{{ item.assigneeUser.deptName }}</el-tag>
               </label>
-              <label style="font-weight: normal" v-if="item.createTime">创建时间:</label>
+              <label v-if="item.createTime" style="font-weight: normal">创建时间:</label>
               <label style="color: #8a909c; font-weight: normal">
                 {{ formatDate(item?.createTime) }}
               </label>
@@ -44,7 +44,7 @@
     </el-col>
   </el-card>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmProcessInstanceTaskList" setup>
 import { formatDate, formatPast2 } from '@/utils/formatTime'
 import { propTypes } from '@/utils/propTypes'
 
diff --git a/src/views/bpm/processInstance/detail/TaskUpdateAssigneeForm.vue b/src/views/bpm/processInstance/detail/TaskUpdateAssigneeForm.vue
index 0f16deeb..1c9971cd 100644
--- a/src/views/bpm/processInstance/detail/TaskUpdateAssigneeForm.vue
+++ b/src/views/bpm/processInstance/detail/TaskUpdateAssigneeForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog title="转派审批人" v-model="dialogVisible" width="500">
+  <Dialog v-model="dialogVisible" title="转派审批人" width="500">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="110px"
-      v-loading="formLoading"
     >
       <el-form-item label="新审批人" prop="assigneeUserId">
         <el-select v-model="formData.assigneeUserId" clearable style="width: 100%">
@@ -19,12 +19,12 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmTaskUpdateAssigneeForm" setup>
 import * as TaskApi from '@/api/bpm/task'
 import * as UserApi from '@/api/system/user'
 
diff --git a/src/views/bpm/task/done/TaskDetail.vue b/src/views/bpm/task/done/TaskDetail.vue
index 4c293c17..68624d19 100644
--- a/src/views/bpm/task/done/TaskDetail.vue
+++ b/src/views/bpm/task/done/TaskDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="任务编号" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -25,7 +25,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmTaskDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as TaskApi from '@/api/bpm/task'
diff --git a/src/views/bpm/taskAssignRule/TaskAssignRuleForm.vue b/src/views/bpm/taskAssignRule/TaskAssignRuleForm.vue
index 2ddebab1..b1140a60 100644
--- a/src/views/bpm/taskAssignRule/TaskAssignRuleForm.vue
+++ b/src/views/bpm/taskAssignRule/TaskAssignRuleForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog title="修改任务规则" v-model="dialogVisible" width="600">
+  <Dialog v-model="dialogVisible" title="修改任务规则" width="600">
     <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
       <el-form-item label="任务名称" prop="taskDefinitionName">
-        <el-input v-model="formData.taskDefinitionName" placeholder="请输入流标标识" disabled />
+        <el-input v-model="formData.taskDefinitionName" disabled placeholder="请输入流标标识" />
       </el-form-item>
       <el-form-item label="任务标识" prop="taskDefinitionKey">
-        <el-input v-model="formData.taskDefinitionKey" placeholder="请输入任务标识" disabled />
+        <el-input v-model="formData.taskDefinitionKey" disabled placeholder="请输入任务标识" />
       </el-form-item>
       <el-form-item label="规则类型" prop="type">
         <el-select v-model="formData.type" clearable style="width: 100%">
@@ -18,7 +18,7 @@
         </el-select>
       </el-form-item>
       <el-form-item v-if="formData.type === 10" label="指定角色" prop="roleIds">
-        <el-select v-model="formData.roleIds" multiple clearable style="width: 100%">
+        <el-select v-model="formData.roleIds" clearable multiple style="width: 100%">
           <el-option
             v-for="item in roleOptions"
             :key="item.id"
@@ -28,24 +28,24 @@
         </el-select>
       </el-form-item>
       <el-form-item
+        v-if="formData.type === 20 || formData.type === 21"
         label="指定部门"
         prop="deptIds"
         span="24"
-        v-if="formData.type === 20 || formData.type === 21"
       >
         <el-tree-select
           ref="treeRef"
           v-model="formData.deptIds"
-          node-key="id"
-          show-checkbox
-          :props="defaultProps"
           :data="deptTreeOptions"
+          :props="defaultProps"
           empty-text="加载中,请稍后"
           multiple
+          node-key="id"
+          show-checkbox
         />
       </el-form-item>
-      <el-form-item label="指定岗位" prop="postIds" span="24" v-if="formData.type === 22">
-        <el-select v-model="formData.postIds" multiple clearable style="width: 100%">
+      <el-form-item v-if="formData.type === 22" label="指定岗位" prop="postIds" span="24">
+        <el-select v-model="formData.postIds" clearable multiple style="width: 100%">
           <el-option
             v-for="item in postOptions"
             :key="parseInt(item.id)"
@@ -55,12 +55,12 @@
         </el-select>
       </el-form-item>
       <el-form-item
+        v-if="formData.type === 30 || formData.type === 31 || formData.type === 32"
         label="指定用户"
         prop="userIds"
         span="24"
-        v-if="formData.type === 30 || formData.type === 31 || formData.type === 32"
       >
-        <el-select v-model="formData.userIds" multiple clearable style="width: 100%">
+        <el-select v-model="formData.userIds" clearable multiple style="width: 100%">
           <el-option
             v-for="item in userOptions"
             :key="parseInt(item.id)"
@@ -69,8 +69,8 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="指定用户组" prop="userGroupIds" v-if="formData.type === 40">
-        <el-select v-model="formData.userGroupIds" multiple clearable style="width: 100%">
+      <el-form-item v-if="formData.type === 40" label="指定用户组" prop="userGroupIds">
+        <el-select v-model="formData.userGroupIds" clearable multiple style="width: 100%">
           <el-option
             v-for="item in userGroupOptions"
             :key="parseInt(item.id)"
@@ -79,8 +79,8 @@
           />
         </el-select>
       </el-form-item>
-      <el-form-item label="指定脚本" prop="scripts" v-if="formData.type === 50">
-        <el-select v-model="formData.scripts" multiple clearable style="width: 100%">
+      <el-form-item v-if="formData.type === 50" label="指定脚本" prop="scripts">
+        <el-select v-model="formData.scripts" clearable multiple style="width: 100%">
           <el-option
             v-for="dict in taskAssignScriptDictDatas"
             :key="dict.value"
@@ -92,20 +92,21 @@
     </el-form>
     <!-- 操作按钮 -->
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="BpmTaskAssignRuleForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { handleTree, defaultProps } from '@/utils/tree'
+import { defaultProps, handleTree } from '@/utils/tree'
 import * as TaskAssignRuleApi from '@/api/bpm/taskAssignRule'
 import * as RoleApi from '@/api/system/role'
 import * as DeptApi from '@/api/system/dept'
 import * as PostApi from '@/api/system/post'
 import * as UserApi from '@/api/system/user'
 import * as UserGroupApi from '@/api/bpm/userGroup'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/infra/apiAccessLog/ApiAccessLogDetail.vue b/src/views/infra/apiAccessLog/ApiAccessLogDetail.vue
index 4746b0c7..fac82aa3 100644
--- a/src/views/infra/apiAccessLog/ApiAccessLogDetail.vue
+++ b/src/views/infra/apiAccessLog/ApiAccessLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500" width="800">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志主键" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -33,14 +33,14 @@
       <el-descriptions-item label="操作结果">
         <div v-if="detailData.resultCode === 0">正常</div>
         <div v-else-if="detailData.resultCode > 0"
-          >失败 | {{ detailData.resultCode }} | {{ detailData.resultMsg }}</div
-        >
+          >失败 | {{ detailData.resultCode }} | {{ detailData.resultMsg }}
+        </div>
       </el-descriptions-item>
     </el-descriptions>
   </Dialog>
 </template>
 
-<script setup lang="ts">
+<script lang="ts" name="ApiAccessLogDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as ApiAccessLog from '@/api/infra/apiAccessLog'
diff --git a/src/views/infra/apiErrorLog/ApiErrorLogDetail.vue b/src/views/infra/apiErrorLog/ApiErrorLogDetail.vue
index 4b279924..7fe17570 100644
--- a/src/views/infra/apiErrorLog/ApiErrorLogDetail.vue
+++ b/src/views/infra/apiErrorLog/ApiErrorLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500" width="800">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志主键" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -32,12 +32,12 @@
       <el-descriptions-item label="异常名">
         {{ detailData.exceptionName }}
       </el-descriptions-item>
-      <el-descriptions-item label="异常堆栈" v-if="detailData.exceptionStackTrace">
+      <el-descriptions-item v-if="detailData.exceptionStackTrace" label="异常堆栈">
         <el-input
-          type="textarea"
-          :readonly="true"
-          :autosize="{ maxRows: 20 }"
           v-model="detailData.exceptionStackTrace"
+          :autosize="{ maxRows: 20 }"
+          :readonly="true"
+          type="textarea"
         />
       </el-descriptions-item>
       <el-descriptions-item label="处理状态">
@@ -46,16 +46,16 @@
           :value="detailData.processStatus"
         />
       </el-descriptions-item>
-      <el-descriptions-item label="处理人" v-if="detailData.processUserId">
+      <el-descriptions-item v-if="detailData.processUserId" label="处理人">
         {{ detailData.processUserId }}
       </el-descriptions-item>
-      <el-descriptions-item label="处理时间" v-if="detailData.processTime">
+      <el-descriptions-item v-if="detailData.processTime" label="处理时间">
         {{ formatDate(detailData.processTime) }}
       </el-descriptions-item>
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ApiErrorLogDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as ApiErrorLog from '@/api/infra/apiErrorLog'
diff --git a/src/views/infra/codegen/EditTable.vue b/src/views/infra/codegen/EditTable.vue
index 8d9f498e..e540f96b 100644
--- a/src/views/infra/codegen/EditTable.vue
+++ b/src/views/infra/codegen/EditTable.vue
@@ -13,16 +13,17 @@
     </el-tabs>
     <el-form>
       <el-form-item style="float: right">
-        <el-button type="primary" @click="submitForm" :loading="formLoading">保存</el-button>
+        <el-button :loading="formLoading" type="primary" @click="submitForm">保存</el-button>
         <el-button @click="close">返回</el-button>
       </el-form-item>
     </el-form>
   </ContentWrap>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraCodegenEditTable" setup>
 import { useTagsViewStore } from '@/store/modules/tagsView'
 import { BasicInfoForm, ColumInfoForm, GenerateInfoForm } from './components'
 import * as CodegenApi from '@/api/infra/codegen'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 const { push, currentRoute } = useRouter() // 路由
diff --git a/src/views/infra/codegen/ImportTable.vue b/src/views/infra/codegen/ImportTable.vue
index 0146b6c3..fb37aa26 100644
--- a/src/views/infra/codegen/ImportTable.vue
+++ b/src/views/infra/codegen/ImportTable.vue
@@ -1,12 +1,12 @@
 <template>
-  <Dialog title="导入表" v-model="dialogVisible" width="800px">
+  <Dialog v-model="dialogVisible" title="导入表" width="800px">
     <!-- 搜索栏 -->
-    <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+    <el-form ref="queryFormRef" :inline="true" :model="queryParams" label-width="68px">
       <el-form-item label="数据源" prop="dataSourceConfigId">
         <el-select
           v-model="queryParams.dataSourceConfigId"
-          placeholder="请选择数据源"
           class="!w-240px"
+          placeholder="请选择数据源"
         >
           <el-option
             v-for="config in dataSourceConfigList"
@@ -19,54 +19,61 @@
       <el-form-item label="表名称" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输入表名称"
-          clearable
-          @keyup.enter="getList"
           class="!w-240px"
+          clearable
+          placeholder="请输入表名称"
+          @keyup.enter="getList"
         />
       </el-form-item>
       <el-form-item label="表描述" prop="comment">
         <el-input
           v-model="queryParams.comment"
-          placeholder="请输入表描述"
-          clearable
-          @keyup.enter="getList"
           class="!w-240px"
+          clearable
+          placeholder="请输入表描述"
+          @keyup.enter="getList"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="getList"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button @click="getList">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
       </el-form-item>
     </el-form>
     <!-- 列表 -->
     <el-row>
       <el-table
-        v-loading="dbTableLoading"
-        @row-click="handleRowClick"
         ref="tableRef"
+        v-loading="dbTableLoading"
         :data="dbTableList"
-        @selection-change="handleSelectionChange"
         height="260px"
+        @row-click="handleRowClick"
+        @selection-change="handleSelectionChange"
       >
         <el-table-column type="selection" width="55" />
-        <el-table-column prop="name" label="表名称" :show-overflow-tooltip="true" />
-        <el-table-column prop="comment" label="表描述" :show-overflow-tooltip="true" />
+        <el-table-column :show-overflow-tooltip="true" label="表名称" prop="name" />
+        <el-table-column :show-overflow-tooltip="true" label="表描述" prop="comment" />
       </el-table>
     </el-row>
     <!-- 操作 -->
     <template #footer>
-      <el-button @click="handleImportTable" type="primary" :disabled="tableList.length === 0">
+      <el-button :disabled="tableList.length === 0" type="primary" @click="handleImportTable">
         导入
       </el-button>
       <el-button @click="close">关闭</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraCodegenImportTable" setup>
 import * as CodegenApi from '@/api/infra/codegen'
 import * as DataSourceConfigApi from '@/api/infra/dataSourceConfig'
 import { ElTable } from 'element-plus'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/infra/codegen/PreviewCode.vue b/src/views/infra/codegen/PreviewCode.vue
index 5dd3907b..339d9a53 100644
--- a/src/views/infra/codegen/PreviewCode.vue
+++ b/src/views/infra/codegen/PreviewCode.vue
@@ -1,48 +1,48 @@
 <template>
   <Dialog
-    title="代码预览"
     v-model="dialogVisible"
     align-center
-    width="80%"
     class="app-infra-codegen-preview-container"
+    title="代码预览"
+    width="80%"
   >
     <div class="flex">
       <!-- 代码目录树 -->
       <el-card
-        class="w-1/3"
-        :gutter="12"
-        shadow="hover"
         v-loading="loading"
+        :gutter="12"
+        class="w-1/3"
         element-loading-text="生成文件目录中..."
+        shadow="hover"
       >
         <el-scrollbar height="calc(100vh - 88px - 40px)">
           <el-tree
             ref="treeRef"
-            node-key="id"
             :data="preview.fileTree"
             :expand-on-click-node="false"
-            highlight-current
-            @node-click="handleNodeClick"
             default-expand-all
+            highlight-current
+            node-key="id"
+            @node-click="handleNodeClick"
           />
         </el-scrollbar>
       </el-card>
       <!-- 代码 -->
       <el-card
-        class="w-2/3 ml-3"
-        :gutter="12"
-        shadow="hover"
         v-loading="loading"
+        :gutter="12"
+        class="w-2/3 ml-3"
         element-loading-text="加载代码中..."
+        shadow="hover"
       >
         <el-tabs v-model="preview.activeName">
           <el-tab-pane
             v-for="item in previewCodegen"
+            :key="item.filePath"
             :label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)"
             :name="item.filePath"
-            :key="item.filePath"
           >
-            <el-button text type="primary" class="float-right" @click="copy(item.code)">
+            <el-button class="float-right" text type="primary" @click="copy(item.code)">
               {{ t('common.copy') }}
             </el-button>
             <div v-highlight>
@@ -54,10 +54,11 @@
     </div>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraCodegenPreviewCode" setup>
 import { useClipboard } from '@vueuse/core'
 import { handleTree2 } from '@/utils/tree'
 import * as CodegenApi from '@/api/infra/codegen'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/infra/codegen/components/BasicInfoForm.vue b/src/views/infra/codegen/components/BasicInfoForm.vue
index 73174cbc..dcccd9e5 100644
--- a/src/views/infra/codegen/components/BasicInfoForm.vue
+++ b/src/views/infra/codegen/components/BasicInfoForm.vue
@@ -3,12 +3,12 @@
     <el-row>
       <el-col :span="12">
         <el-form-item label="表名称" prop="tableName">
-          <el-input placeholder="请输入仓库名称" v-model="formData.tableName" />
+          <el-input v-model="formData.tableName" placeholder="请输入仓库名称" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
         <el-form-item label="表描述" prop="tableComment">
-          <el-input placeholder="请输入" v-model="formData.tableComment" />
+          <el-input v-model="formData.tableComment" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
@@ -20,27 +20,27 @@
                 content="默认去除表名的前缀。如果存在重复,则需要手动添加前缀,避免 MyBatis 报 Alias 重复的问题。"
                 placement="top"
               >
-                <Icon icon="ep:question-filled" class="" />
+                <Icon class="" icon="ep:question-filled" />
               </el-tooltip>
             </span>
           </template>
-          <el-input placeholder="请输入" v-model="formData.className" />
+          <el-input v-model="formData.className" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="12">
         <el-form-item label="作者" prop="author">
-          <el-input placeholder="请输入" v-model="formData.author" />
+          <el-input v-model="formData.author" placeholder="请输入" />
         </el-form-item>
       </el-col>
       <el-col :span="24">
         <el-form-item label="备注" prop="remark">
-          <el-input type="textarea" :rows="3" v-model="formData.remark" />
+          <el-input v-model="formData.remark" :rows="3" type="textarea" />
         </el-form-item>
       </el-col>
     </el-row>
   </el-form>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraCodegenBasicInfoForm" setup>
 import * as CodegenApi from '@/api/infra/codegen'
 import { PropType } from 'vue'
 
diff --git a/src/views/infra/codegen/components/ColumInfoForm.vue b/src/views/infra/codegen/components/ColumInfoForm.vue
index 5d2a036d..e228d3af 100644
--- a/src/views/infra/codegen/components/ColumInfoForm.vue
+++ b/src/views/infra/codegen/components/ColumInfoForm.vue
@@ -1,10 +1,10 @@
 <template>
-  <el-table ref="dragTable" :data="formData" row-key="columnId" :max-height="tableHeight">
+  <el-table ref="dragTable" :data="formData" :max-height="tableHeight" row-key="columnId">
     <el-table-column
-      label="字段列名"
-      prop="columnName"
-      min-width="10%"
       :show-overflow-tooltip="true"
+      label="字段列名"
+      min-width="10%"
+      prop="columnName"
     />
     <el-table-column label="字段描述" min-width="10%">
       <template #default="scope">
@@ -12,10 +12,10 @@
       </template>
     </el-table-column>
     <el-table-column
-      label="物理类型"
-      prop="dataType"
-      min-width="10%"
       :show-overflow-tooltip="true"
+      label="物理类型"
+      min-width="10%"
+      prop="dataType"
     />
     <el-table-column label="Java类型" min-width="11%">
       <template #default="scope">
@@ -37,26 +37,26 @@
     </el-table-column>
     <el-table-column label="插入" min-width="4%">
       <template #default="scope">
-        <el-checkbox true-label="true" false-label="false" v-model="scope.row.createOperation" />
+        <el-checkbox v-model="scope.row.createOperation" false-label="false" true-label="true" />
       </template>
     </el-table-column>
     <el-table-column label="编辑" min-width="4%">
       <template #default="scope">
-        <el-checkbox true-label="true" false-label="false" v-model="scope.row.updateOperation" />
+        <el-checkbox v-model="scope.row.updateOperation" false-label="false" true-label="true" />
       </template>
     </el-table-column>
     <el-table-column label="列表" min-width="4%">
       <template #default="scope">
         <el-checkbox
-          true-label="true"
-          false-label="false"
           v-model="scope.row.listOperationResult"
+          false-label="false"
+          true-label="true"
         />
       </template>
     </el-table-column>
     <el-table-column label="查询" min-width="4%">
       <template #default="scope">
-        <el-checkbox true-label="true" false-label="false" v-model="scope.row.listOperation" />
+        <el-checkbox v-model="scope.row.listOperation" false-label="false" true-label="true" />
       </template>
     </el-table-column>
     <el-table-column label="查询方式" min-width="10%">
@@ -75,7 +75,7 @@
     </el-table-column>
     <el-table-column label="允许空" min-width="5%">
       <template #default="scope">
-        <el-checkbox true-label="true" false-label="false" v-model="scope.row.nullable" />
+        <el-checkbox v-model="scope.row.nullable" false-label="false" true-label="true" />
       </template>
     </el-table-column>
     <el-table-column label="显示类型" min-width="12%">
@@ -112,7 +112,7 @@
     </el-table-column>
   </el-table>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraCodegenColumInfoForm" setup>
 import { PropType } from 'vue'
 import * as CodegenApi from '@/api/infra/codegen'
 import * as DictDataApi from '@/api/system/dict/dict.type'
diff --git a/src/views/infra/codegen/components/GenerateInfoForm.vue b/src/views/infra/codegen/components/GenerateInfoForm.vue
index b9898c09..51e01ad2 100644
--- a/src/views/infra/codegen/components/GenerateInfoForm.vue
+++ b/src/views/infra/codegen/components/GenerateInfoForm.vue
@@ -2,7 +2,7 @@
   <el-form ref="formRef" :model="formData" :rules="rules" label-width="150px">
     <el-row>
       <el-col :span="12">
-        <el-form-item prop="templateType" label="生成模板">
+        <el-form-item label="生成模板" prop="templateType">
           <el-select v-model="formData.templateType" @change="tplSelectChange">
             <el-option
               v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)"
@@ -14,7 +14,7 @@
         </el-form-item>
       </el-col>
       <el-col :span="12">
-        <el-form-item prop="frontType" label="前端类型">
+        <el-form-item label="前端类型" prop="frontType">
           <el-select v-model="formData.frontType">
             <el-option
               v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_FRONT_TYPE)"
@@ -27,7 +27,7 @@
       </el-col>
 
       <el-col :span="12">
-        <el-form-item prop="scene" label="生成场景">
+        <el-form-item label="生成场景" prop="scene">
           <el-select v-model="formData.scene">
             <el-option
               v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_SCENE)"
@@ -50,11 +50,11 @@
           </template>
           <el-tree-select
             v-model="formData.parentMenuId"
-            placeholder="请选择系统菜单"
-            node-key="id"
-            check-strictly
             :data="menus"
             :props="menuTreeProps"
+            check-strictly
+            node-key="id"
+            placeholder="请选择系统菜单"
           />
         </el-form-item>
       </el-col>
@@ -148,7 +148,7 @@
         </el-form-item>
       </el-col>
 
-      <el-col :span="24" v-if="formData.genType === '1'">
+      <el-col v-if="formData.genType === '1'" :span="24">
         <el-form-item prop="genPath">
           <template #label>
             <span>
@@ -291,8 +291,8 @@
     </el-row>
   </el-form>
 </template>
-<script setup lang="ts">
-import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
+<script lang="ts" name="InfraCodegenGenerateInfoForm" setup>
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { handleTree } from '@/utils/tree'
 import * as CodegenApi from '@/api/infra/codegen'
 import * as MenuApi from '@/api/system/menu'
diff --git a/src/views/infra/config/ConfigForm.vue b/src/views/infra/config/ConfigForm.vue
index f5eb1174..5c2d0283 100644
--- a/src/views/infra/config/ConfigForm.vue
+++ b/src/views/infra/config/ConfigForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="参数分类" prop="category">
         <el-input v-model="formData.category" placeholder="请输入参数分类" />
@@ -31,16 +31,16 @@
         </el-radio-group>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+        <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraConfigForm" setup>
 import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
 import * as ConfigApi from '@/api/infra/config'
 
diff --git a/src/views/infra/dataSourceConfig/DataSourceConfigForm.vue b/src/views/infra/dataSourceConfig/DataSourceConfigForm.vue
index b3ebb871..26a83583 100644
--- a/src/views/infra/dataSourceConfig/DataSourceConfigForm.vue
+++ b/src/views/infra/dataSourceConfig/DataSourceConfigForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="100px"
-      v-loading="formLoading"
     >
       <el-form-item label="数据源名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入参数名称" />
@@ -21,12 +21,12 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraDataSourceConfigForm" setup>
 import * as DataSourceConfigApi from '@/api/infra/dataSourceConfig'
 
 const { t } = useI18n() // 国际化
diff --git a/src/views/infra/file/FileForm.vue b/src/views/infra/file/FileForm.vue
index 5485870d..57fd147d 100644
--- a/src/views/infra/file/FileForm.vue
+++ b/src/views/infra/file/FileForm.vue
@@ -1,23 +1,23 @@
 <template>
-  <Dialog title="上传文件" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="上传文件">
     <el-upload
       ref="uploadRef"
-      :action="url"
-      :data="data"
-      :headers="uploadHeaders"
       v-model:file-list="fileList"
-      drag
-      accept=".jpg, .png, .gif"
-      :limit="1"
-      :on-success="submitFormSuccess"
-      :on-exceed="handleExceed"
-      :on-error="submitFormError"
-      :on-change="handleFileChange"
+      :action="url"
       :auto-upload="false"
+      :data="data"
       :disabled="formLoading"
+      :headers="uploadHeaders"
+      :limit="1"
+      :on-change="handleFileChange"
+      :on-error="submitFormError"
+      :on-exceed="handleExceed"
+      :on-success="submitFormSuccess"
+      accept=".jpg, .png, .gif"
+      drag
     >
       <i class="el-icon-upload"></i>
-      <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em> </div>
+      <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em></div>
       <template #tip>
         <div class="el-upload__tip" style="color: red">
           提示:仅允许导入 jpg、png、gif 格式文件!
@@ -25,13 +25,14 @@
       </template>
     </el-upload>
     <template #footer>
-      <el-button @click="submitFileForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitFileForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraFileForm" setup>
 import { getAccessToken, getTenantId } from '@/utils/auth'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/infra/fileConfig/FileConfigForm.vue b/src/views/infra/fileConfig/FileConfigForm.vue
index 2f5a7586..42e0bbad 100644
--- a/src/views/infra/fileConfig/FileConfigForm.vue
+++ b/src/views/infra/fileConfig/FileConfigForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="120px"
-      v-loading="formLoading"
     >
       <el-form-item label="配置名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入配置名" />
@@ -16,8 +16,8 @@
       <el-form-item label="存储器" prop="storage">
         <el-select
           v-model="formData.storage"
-          placeholder="请选择存储器"
           :disabled="formData.id !== undefined"
+          placeholder="请选择存储器"
         >
           <el-option
             v-for="dict in getDictOptions(DICT_TYPE.INFRA_FILE_STORAGE)"
@@ -48,7 +48,7 @@
         label="主机端口"
         prop="config.port"
       >
-        <el-input-number :min="0" v-model="formData.config.port" placeholder="请输入主机端口" />
+        <el-input-number v-model="formData.config.port" :min="0" placeholder="请输入主机端口" />
       </el-form-item>
       <el-form-item
         v-if="formData.storage >= 11 && formData.storage <= 12"
@@ -93,14 +93,15 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraFileConfigForm" setup>
 import { DICT_TYPE, getDictOptions } from '@/utils/dict'
 import * as FileConfigApi from '@/api/infra/fileConfig'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/infra/job/JobDetail.vue b/src/views/infra/job/JobDetail.vue
index 18e4235b..45bc4a5d 100644
--- a/src/views/infra/job/JobDetail.vue
+++ b/src/views/infra/job/JobDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="任务详细" v-model="dialogVisible" width="700px">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" title="任务详细" width="700px">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="任务编号" min-width="60">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -42,7 +42,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraJobDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as JobApi from '@/api/infra/job'
diff --git a/src/views/infra/job/logger/JobLogDetail.vue b/src/views/infra/job/logger/JobLogDetail.vue
index 3b8795d9..a8ef8d4f 100644
--- a/src/views/infra/job/logger/JobLogDetail.vue
+++ b/src/views/infra/job/logger/JobLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="任务详细" v-model="dialogVisible" width="700px">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" title="任务详细" width="700px">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志编号" min-width="60">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -31,7 +31,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="JobLogDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as JobLogApi from '@/api/infra/jobLog'
diff --git a/src/views/infra/webSocket/index.vue b/src/views/infra/webSocket/index.vue
index b4e0acc0..c1690db2 100644
--- a/src/views/infra/webSocket/index.vue
+++ b/src/views/infra/webSocket/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="flex">
-    <el-card class="w-1/2" :gutter="12" shadow="always">
+    <el-card :gutter="12" class="w-1/2" shadow="always">
       <template #header>
         <div class="card-header">
           <span>连接</span>
@@ -14,7 +14,7 @@
 
       <div class="flex">
         <el-input v-model="server" disabled>
-          <template #prepend> 服务地址 </template>
+          <template #prepend> 服务地址</template>
         </el-input>
         <el-button :type="getIsOpen ? 'danger' : 'primary'" @click="toggle">
           {{ getIsOpen ? '关闭连接' : '开启连接' }}
@@ -25,15 +25,15 @@
       <el-input
         v-model="sendValue"
         :autosize="{ minRows: 2, maxRows: 4 }"
-        type="textarea"
         :disabled="!getIsOpen"
         clearable
+        type="textarea"
       />
-      <el-button type="primary" block class="mt-4" :disabled="!getIsOpen" @click="handlerSend">
+      <el-button :disabled="!getIsOpen" block class="mt-4" type="primary" @click="handlerSend">
         发送
       </el-button>
     </el-card>
-    <el-card class="w-1/2" :gutter="12" shadow="always">
+    <el-card :gutter="12" class="w-1/2" shadow="always">
       <template #header>
         <div class="card-header">
           <span>消息记录</span>
@@ -41,7 +41,7 @@
       </template>
       <div class="max-h-80 overflow-auto">
         <ul>
-          <li v-for="item in getList" class="mt-2" :key="item.time">
+          <li v-for="item in getList" :key="item.time" class="mt-2">
             <div class="flex items-center">
               <span class="mr-2 text-primary font-medium">收到消息:</span>
               <span>{{ formatDate(item.time) }}</span>
@@ -55,7 +55,7 @@
     </el-card>
   </div>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="InfraWebSocket" setup>
 import { formatDate } from '@/utils/formatTime'
 import { useUserStore } from '@/store/modules/user'
 import { useWebSocket } from '@vueuse/core'
diff --git a/src/views/mall/product/property/PropertyForm.vue b/src/views/mall/product/property/PropertyForm.vue
index 48832f76..c5955fc9 100644
--- a/src/views/mall/product/property/PropertyForm.vue
+++ b/src/views/mall/product/property/PropertyForm.vue
@@ -1,27 +1,28 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入名称" />
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+        <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ProductPropertyForm" setup>
 import * as PropertyApi from '@/api/mall/product/property'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/mall/product/property/value/ValueForm.vue b/src/views/mall/product/property/value/ValueForm.vue
index 3f6a5225..3257cbc6 100644
--- a/src/views/mall/product/property/value/ValueForm.vue
+++ b/src/views/mall/product/property/value/ValueForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="属性编号" prop="category">
         <el-input v-model="formData.propertyId" disabled="" />
@@ -14,17 +14,18 @@
         <el-input v-model="formData.name" placeholder="请输入名称" />
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+        <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="ProductPropertyValueForm" setup>
 import * as PropertyApi from '@/api/mall/product/property'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/mp/account/AccountForm.vue b/src/views/mp/account/AccountForm.vue
index a80bb48f..f9c651ca 100644
--- a/src/views/mp/account/AccountForm.vue
+++ b/src/views/mp/account/AccountForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="rules"
       label-width="120px"
-      v-loading="formLoading"
     >
       <el-form-item label="名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入名称" />
@@ -59,17 +59,18 @@
         <el-input v-model="formData.aesKey" placeholder="请输入消息加解密密钥" />
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
+        <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="MpAccountForm" setup>
 import * as AccountApi from '@/api/mp/account'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/mp/components/wx-editor/WxEditor.vue b/src/views/mp/components/wx-editor/WxEditor.vue
index 50c65c6e..52e9862f 100644
--- a/src/views/mp/components/wx-editor/WxEditor.vue
+++ b/src/views/mp/components/wx-editor/WxEditor.vue
@@ -1,5 +1,5 @@
-<script setup>
-import { ref, reactive } from 'vue'
+<script name="WxEditor" setup>
+import { reactive, ref } from 'vue'
 import { QuillEditor } from '@vueup/vue-quill'
 import '@vueup/vue-quill/dist/vue-quill.snow.css'
 import { getAccessToken } from '@/utils/auth'
@@ -88,21 +88,21 @@ const uploadError = () => {
     <div v-loading="loading" element-loading-text="请稍等,图片上传中">
       <!-- 图片上传组件辅助-->
       <el-upload
+        :action="actionUrl"
+        :before-upload="beforeUpload"
+        :data="uploadData"
+        :headers="headers"
+        :on-error="uploadError"
+        :on-success="uploadSuccess"
+        :show-file-list="false"
         class="avatar-uploader"
         name="file"
-        :action="actionUrl"
-        :headers="headers"
-        :show-file-list="false"
-        :data="uploadData"
-        :on-success="uploadSuccess"
-        :on-error="uploadError"
-        :before-upload="beforeUpload"
       />
       <QuillEditor
-        class="editor"
-        v-model="content"
         ref="quillEditorRef"
+        v-model="content"
         :options="editorOptions"
+        class="editor"
         @change="onEditorChange($event)"
       />
     </div>
diff --git a/src/views/mp/components/wx-news/main.vue b/src/views/mp/components/wx-news/main.vue
index d08e2813..326b674c 100644
--- a/src/views/mp/components/wx-news/main.vue
+++ b/src/views/mp/components/wx-news/main.vue
@@ -9,13 +9,13 @@
   <div class="news-home">
     <div v-for="(article, index) in articles" :key="index" class="news-div">
       <!-- 头条 -->
-      <a target="_blank" :href="article.url" v-if="index === 0">
+      <a v-if="index === 0" :href="article.url" target="_blank">
         <div class="news-main">
           <div class="news-content">
             <el-image
+              :src="article.picUrl"
               class="material-img"
               style="width: 100%; height: 120px"
-              :src="article.picUrl"
             />
             <div class="news-content-title">
               <span>{{ article.title }}</span>
@@ -24,12 +24,12 @@
         </div>
       </a>
       <!-- 二条/三条等等 -->
-      <a target="_blank" :href="article.url" v-else>
+      <a v-else :href="article.url" target="_blank">
         <div class="news-main-item">
           <div class="news-content-item">
             <div class="news-content-item-title">{{ article.title }}</div>
             <div class="news-content-item-img">
-              <img class="material-img" :src="article.picUrl" height="100%" />
+              <img :src="article.picUrl" class="material-img" height="100%" />
             </div>
           </div>
         </div>
@@ -38,7 +38,7 @@
   </div>
 </template>
 
-<script setup lang="ts">
+<script lang="ts" name="WxNews" setup>
 const props = defineProps({
   articles: {
     type: Array,
@@ -57,15 +57,18 @@ defineExpose({
   width: 100%;
   margin: auto;
 }
+
 .news-main {
   width: 100%;
   margin: auto;
 }
+
 .news-content {
   background-color: #acadae;
   width: 100%;
   position: relative;
 }
+
 .news-content-title {
   display: inline-block;
   font-size: 12px;
@@ -80,14 +83,17 @@ defineExpose({
   white-space: normal;
   box-sizing: unset !important;
 }
+
 .news-main-item {
   background-color: #ffffff;
   padding: 5px 0;
   border-top: 1px solid #eaeaea;
 }
+
 .news-content-item {
   position: relative;
 }
+
 .news-content-item-title {
   display: inline-block;
   font-size: 10px;
@@ -95,12 +101,14 @@ defineExpose({
   margin-left: 1%;
   white-space: normal;
 }
+
 .news-content-item-img {
   display: inline-block;
   width: 25%;
   background-color: #acadae;
   margin-right: 1%;
 }
+
 .material-img {
   width: 100%;
 }
diff --git a/src/views/mp/tag/TagForm.vue b/src/views/mp/tag/TagForm.vue
index e190af89..38af16e1 100644
--- a/src/views/mp/tag/TagForm.vue
+++ b/src/views/mp/tag/TagForm.vue
@@ -1,24 +1,25 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="标签名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入标签名称" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="MpTagForm" setup>
 import * as MpTagApi from '@/api/mp/tag'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/mp/user/UserForm.vue b/src/views/mp/user/UserForm.vue
index a23d271f..612e4964 100644
--- a/src/views/mp/user/UserForm.vue
+++ b/src/views/mp/user/UserForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog title="修改" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="修改">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="昵称" prop="nickname">
         <el-input v-model="formData.nickname" placeholder="请输入昵称" />
@@ -14,7 +14,7 @@
         <el-input v-model="formData.remark" placeholder="请输入备注" />
       </el-form-item>
       <el-form-item label="标签" prop="tagIds">
-        <el-select v-model="formData.tagIds" multiple clearable placeholder="请选择标签">
+        <el-select v-model="formData.tagIds" clearable multiple placeholder="请选择标签">
           <el-option
             v-for="item in tagList"
             :key="item.tagId"
@@ -25,14 +25,15 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="MpUserForm" setup>
 import * as MpTagApi from '@/api/mp/tag'
 import * as MpUserApi from '@/api/mp/user'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/pay/app/AppForm.vue b/src/views/pay/app/AppForm.vue
index 2e6c81da..a04ca49e 100644
--- a/src/views/pay/app/AppForm.vue
+++ b/src/views/pay/app/AppForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="160px"
-      v-loading="formLoading"
     >
       <el-form-item label="应用名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入应用名" />
@@ -42,16 +42,17 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="PayAppForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as AppApi from '@/api/pay/app'
 import * as MerchantApi from '@/api/pay/merchant'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/pay/merchant/MerchantForm.vue b/src/views/pay/merchant/MerchantForm.vue
index 34dea00a..8d86e3f0 100644
--- a/src/views/pay/merchant/MerchantForm.vue
+++ b/src/views/pay/merchant/MerchantForm.vue
@@ -1,5 +1,5 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form ref="formRef" :model="formData" :rules="formRules" label-width="80px">
       <el-form-item label="商户全称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入商户全称" />
@@ -8,7 +8,7 @@
         <el-input v-model="formData.shortName" placeholder="请输入商户简称" />
       </el-form-item>
       <el-form-item label="开启状态" prop="status">
-        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -18,19 +18,20 @@
         </el-select>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input type="textarea" v-model="formData.remark" placeholder="请输入备注" />
+        <el-input v-model="formData.remark" placeholder="请输入备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="PayMerchantForm" setup>
 import * as MerchantApi from '@/api/pay/merchant'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/pay/order/OrderDetail.vue b/src/views/pay/order/OrderDetail.vue
index bb4bee74..ec2af786 100644
--- a/src/views/pay/order/OrderDetail.vue
+++ b/src/views/pay/order/OrderDetail.vue
@@ -1,5 +1,5 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" width="50%">
+  <Dialog v-model="dialogVisible" title="详情" width="50%">
     <el-descriptions :column="2">
       <el-descriptions-item label="商户名称">{{ detailData.merchantName }}</el-descriptions-item>
       <el-descriptions-item label="应用名称">{{ detailData.appName }}</el-descriptions-item>
@@ -66,7 +66,7 @@
       </el-descriptions-item>
     </el-descriptions>
     <el-divider />
-    <el-descriptions :column="1" direction="vertical" border>
+    <el-descriptions :column="1" border direction="vertical">
       <el-descriptions-item label="商品描述">
         {{ detailData.body }}
       </el-descriptions-item>
@@ -78,7 +78,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts" name="orderForm">
+<script lang="ts" name="PayOrderDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import * as OrderApi from '@/api/pay/order'
 import { formatDate } from '@/utils/formatTime'
diff --git a/src/views/pay/refund/RefundDetail.vue b/src/views/pay/refund/RefundDetail.vue
index 8a47c6f6..4d241d98 100644
--- a/src/views/pay/refund/RefundDetail.vue
+++ b/src/views/pay/refund/RefundDetail.vue
@@ -1,5 +1,5 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" width="50%">
+  <Dialog v-model="dialogVisible" title="详情" width="50%">
     <el-descriptions :column="2">
       <el-descriptions-item label="商户名称">{{ detailData.merchantName }}</el-descriptions-item>
       <el-descriptions-item label="应用名称">{{ detailData.appName }}</el-descriptions-item>
@@ -76,7 +76,7 @@
       </el-descriptions-item>
     </el-descriptions>
     <br />
-    <el-descriptions :column="1" direction="vertical" border>
+    <el-descriptions :column="1" border direction="vertical">
       <el-descriptions-item label="渠道额外参数">
         {{ detailData.channelExtras }}
       </el-descriptions-item>
@@ -84,7 +84,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts" name="refundForm">
+<script lang="ts" name="PayRefundDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as RefundApi from '@/api/pay/refund'
diff --git a/src/views/system/area/AreaForm.vue b/src/views/system/area/AreaForm.vue
index c0a51494..1610c9b9 100644
--- a/src/views/system/area/AreaForm.vue
+++ b/src/views/system/area/AreaForm.vue
@@ -1,27 +1,28 @@
 <template>
-  <Dialog title="IP 查询" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="IP 查询">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="IP" prop="ip">
         <el-input v-model="formData.ip" placeholder="请输入 IP 地址" />
       </el-form-item>
       <el-form-item label="地址" prop="result">
-        <el-input v-model="formData.result" readonly placeholder="展示查询 IP 结果" />
+        <el-input v-model="formData.result" placeholder="展示查询 IP 结果" readonly />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemAreaForm" setup>
 import * as AreaApi from '@/api/system/area'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/system/dept/DeptForm.vue b/src/views/system/dept/DeptForm.vue
index 92b4cb39..ec476a26 100644
--- a/src/views/system/dept/DeptForm.vue
+++ b/src/views/system/dept/DeptForm.vue
@@ -1,31 +1,31 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="上级部门" prop="parentId">
         <el-tree-select
           v-model="formData.parentId"
           :data="deptTree"
           :props="defaultProps"
-          value-key="deptId"
-          placeholder="请选择上级部门"
           check-strictly
           default-expand-all
+          placeholder="请选择上级部门"
+          value-key="deptId"
         />
       </el-form-item>
       <el-form-item label="部门名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入部门名称" />
       </el-form-item>
       <el-form-item label="显示排序" prop="sort">
-        <el-input-number v-model="formData.sort" controls-position="right" :min="0" />
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
       </el-form-item>
       <el-form-item label="负责人" prop="leaderUserId">
-        <el-select v-model="formData.leaderUserId" placeholder="请输入负责人" clearable>
+        <el-select v-model="formData.leaderUserId" clearable placeholder="请输入负责人">
           <el-option
             v-for="item in userList"
             :key="item.id"
@@ -35,13 +35,13 @@
         </el-select>
       </el-form-item>
       <el-form-item label="联系电话" prop="phone">
-        <el-input v-model="formData.phone" placeholder="请输入联系电话" maxlength="11" />
+        <el-input v-model="formData.phone" maxlength="11" placeholder="请输入联系电话" />
       </el-form-item>
       <el-form-item label="邮箱" prop="email">
-        <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
+        <el-input v-model="formData.email" maxlength="50" placeholder="请输入邮箱" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -57,12 +57,13 @@
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemDeptForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { handleTree, defaultProps } from '@/utils/tree'
+import { defaultProps, handleTree } from '@/utils/tree'
 import * as DeptApi from '@/api/system/dept'
 import * as UserApi from '@/api/system/user'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/dict/DictTypeForm.vue b/src/views/system/dict/DictTypeForm.vue
index bb0deb17..d9b7efd1 100644
--- a/src/views/system/dict/DictTypeForm.vue
+++ b/src/views/system/dict/DictTypeForm.vue
@@ -1,19 +1,19 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="字典名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入字典名称" />
       </el-form-item>
       <el-form-item label="字典类型" prop="type">
         <el-input
-          :disabled="typeof formData.id !== 'undefined'"
           v-model="formData.type"
+          :disabled="typeof formData.id !== 'undefined'"
           placeholder="请输入参数名称"
         />
       </el-form-item>
@@ -29,19 +29,20 @@
         </el-radio-group>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+        <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemDictTypeForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as DictTypeApi from '@/api/system/dict/dict.type'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/dict/data/DictDataForm.vue b/src/views/system/dict/data/DictDataForm.vue
index dc2f6057..c9d25916 100644
--- a/src/views/system/dict/data/DictDataForm.vue
+++ b/src/views/system/dict/data/DictDataForm.vue
@@ -1,16 +1,16 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="字典类型" prop="type">
         <el-input
-          :disabled="typeof formData.id !== 'undefined'"
           v-model="formData.dictType"
+          :disabled="typeof formData.id !== 'undefined'"
           placeholder="请输入参数名称"
         />
       </el-form-item>
@@ -21,7 +21,7 @@
         <el-input v-model="formData.value" placeholder="请输入数据键值" />
       </el-form-item>
       <el-form-item label="显示排序" prop="sort">
-        <el-input-number v-model="formData.sort" controls-position="right" :min="0" />
+        <el-input-number v-model="formData.sort" :min="0" controls-position="right" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
         <el-radio-group v-model="formData.status">
@@ -48,19 +48,20 @@
         <el-input v-model="formData.cssClass" placeholder="请输入 CSS Class" />
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+        <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemDictDataForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as DictDataApi from '@/api/system/dict/dict.data'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/errorCode/ErrorCodeForm.vue b/src/views/system/errorCode/ErrorCodeForm.vue
index 3747ed06..9525a1a5 100644
--- a/src/views/system/errorCode/ErrorCodeForm.vue
+++ b/src/views/system/errorCode/ErrorCodeForm.vue
@@ -1,32 +1,32 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="100px"
-      v-loading="formLoading"
     >
       <el-form-item label="应用名" prop="applicationName">
-        <el-input v-model="formData.applicationName" placeholder="请输入应用名" clearable />
+        <el-input v-model="formData.applicationName" clearable placeholder="请输入应用名" />
       </el-form-item>
       <el-form-item label="错误码编码" prop="code">
-        <el-input v-model="formData.code" placeholder="请输入错误码编码" clearable />
+        <el-input v-model="formData.code" clearable placeholder="请输入错误码编码" />
       </el-form-item>
       <el-form-item label="错误码提示" prop="message">
-        <el-input v-model="formData.message" placeholder="请输入错误码提示" clearable />
+        <el-input v-model="formData.message" clearable placeholder="请输入错误码提示" />
       </el-form-item>
       <el-form-item label="备注" prop="memo">
-        <el-input v-model="formData.memo" placeholder="请输入备注" clearable />
+        <el-input v-model="formData.memo" clearable placeholder="请输入备注" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemErrorCodeForm" setup>
 import * as ErrorCodeApi from '@/api/system/errorCode'
 
 const { t } = useI18n() // 国际化
diff --git a/src/views/system/loginlog/LoginLogDetail.vue b/src/views/system/loginlog/LoginLogDetail.vue
index 3a8157ce..c59746b6 100644
--- a/src/views/system/loginlog/LoginLogDetail.vue
+++ b/src/views/system/loginlog/LoginLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" width="800">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" title="详情" width="800">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志编号" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -25,7 +25,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemLoginLogDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as LoginLogApi from '@/api/system/loginLog'
diff --git a/src/views/system/mail/account/MailAccountDetail.vue b/src/views/system/mail/account/MailAccountDetail.vue
index b64c8d16..49bf98d6 100644
--- a/src/views/system/mail/account/MailAccountDetail.vue
+++ b/src/views/system/mail/account/MailAccountDetail.vue
@@ -1,9 +1,9 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible">
-    <Descriptions :schema="allSchemas.detailSchema" :data="detailData" />
+  <Dialog v-model="dialogVisible" title="详情">
+    <Descriptions :data="detailData" :schema="allSchemas.detailSchema" />
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMailAccountDetail" setup>
 import * as MailAccountApi from '@/api/system/mail/account'
 import { allSchemas } from './account.data'
 
diff --git a/src/views/system/mail/account/MailAccountForm.vue b/src/views/system/mail/account/MailAccountForm.vue
index fdc31dbd..53f12ac6 100644
--- a/src/views/system/mail/account/MailAccountForm.vue
+++ b/src/views/system/mail/account/MailAccountForm.vue
@@ -1,15 +1,16 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
-    <Form ref="formRef" :schema="allSchemas.formSchema" :rules="rules" v-loading="formLoading" />
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
+    <Form ref="formRef" v-loading="formLoading" :rules="rules" :schema="allSchemas.formSchema" />
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMailAccountForm" setup>
 import * as MailAccountApi from '@/api/system/mail/account'
-import { rules, allSchemas } from './account.data'
+import { allSchemas, rules } from './account.data'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/mail/log/MailLogDetail.vue b/src/views/system/mail/log/MailLogDetail.vue
index f781bc00..26c56bc1 100644
--- a/src/views/system/mail/log/MailLogDetail.vue
+++ b/src/views/system/mail/log/MailLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500">
-    <Descriptions :schema="allSchemas.detailSchema" :data="detailData">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情">
+    <Descriptions :data="detailData" :schema="allSchemas.detailSchema">
       <!-- 展示 HTML 内容 -->
       <template #templateContent="{ row }">
         <div v-html="row.templateContent"></div>
@@ -8,7 +8,7 @@
     </Descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMailLogDetail" setup>
 import * as MailLogApi from '@/api/system/mail/log'
 import { allSchemas } from './log.data'
 
diff --git a/src/views/system/mail/template/MailTemplateForm.vue b/src/views/system/mail/template/MailTemplateForm.vue
index e35dcd7b..55367e16 100644
--- a/src/views/system/mail/template/MailTemplateForm.vue
+++ b/src/views/system/mail/template/MailTemplateForm.vue
@@ -1,21 +1,22 @@
 <template>
   <Dialog
-    :title="dialogTitle"
     v-model="dialogVisible"
-    :scroll="true"
-    :width="800"
     :max-height="500"
+    :scroll="true"
+    :title="dialogTitle"
+    :width="800"
   >
-    <Form ref="formRef" :schema="allSchemas.formSchema" :rules="rules" v-loading="formLoading" />
+    <Form ref="formRef" v-loading="formLoading" :rules="rules" :schema="allSchemas.formSchema" />
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMailTemplateForm" setup>
 import * as MailTemplateApi from '@/api/system/mail/template'
 import { allSchemas, rules } from './template.data'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/mail/template/MailTemplateSendForm.vue b/src/views/system/mail/template/MailTemplateSendForm.vue
index 01c98041..e900f1cb 100644
--- a/src/views/system/mail/template/MailTemplateSendForm.vue
+++ b/src/views/system/mail/template/MailTemplateSendForm.vue
@@ -1,14 +1,14 @@
 <template>
-  <Dialog title="测试" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="测试">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="120px"
-      v-loading="formLoading"
     >
       <el-form-item label="模板内容" prop="content">
-        <Editor :model-value="formData.content" readonly height="150px" />
+        <Editor :model-value="formData.content" height="150px" readonly />
       </el-form-item>
       <el-form-item label="收件邮箱" prop="mail">
         <el-input v-model="formData.mail" placeholder="请输入收件邮箱" />
@@ -26,13 +26,14 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMailTemplateSendForm" setup>
 import * as MailTemplateApi from '@/api/system/mail/template'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/system/menu/MenuForm.vue b/src/views/system/menu/MenuForm.vue
index 3e7b705c..278a9b51 100644
--- a/src/views/system/menu/MenuForm.vue
+++ b/src/views/system/menu/MenuForm.vue
@@ -1,24 +1,24 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="100px"
-      v-loading="formLoading"
     >
       <el-form-item label="上级菜单">
         <el-tree-select
-          node-key="id"
           v-model="formData.parentId"
-          :props="defaultProps"
           :data="menuTree"
           :default-expanded-keys="[0]"
+          :props="defaultProps"
           check-strictly
+          node-key="id"
         />
       </el-form-item>
       <el-form-item label="菜单名称" prop="name">
-        <el-input v-model="formData.name" placeholder="请输入菜单名称" clearable />
+        <el-input v-model="formData.name" clearable placeholder="请输入菜单名称" />
       </el-form-item>
       <el-form-item label="菜单类型" prop="type">
         <el-radio-group v-model="formData.type">
@@ -31,35 +31,35 @@
           </el-radio-button>
         </el-radio-group>
       </el-form-item>
-      <el-form-item label="菜单图标" v-if="formData.type !== 3">
+      <el-form-item v-if="formData.type !== 3" label="菜单图标">
         <IconSelect v-model="formData.icon" clearable />
       </el-form-item>
-      <el-form-item label="路由地址" prop="path" v-if="formData.type !== 3">
+      <el-form-item v-if="formData.type !== 3" label="路由地址" prop="path">
         <template #label>
           <Tooltip
-            titel="路由地址"
             message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头"
+            titel="路由地址"
           />
         </template>
-        <el-input v-model="formData.path" placeholder="请输入路由地址" clearable />
+        <el-input v-model="formData.path" clearable placeholder="请输入路由地址" />
       </el-form-item>
-      <el-form-item label="组件地址" prop="component" v-if="formData.type === 2">
-        <el-input v-model="formData.component" placeholder="例如说:system/user/index" clearable />
+      <el-form-item v-if="formData.type === 2" label="组件地址" prop="component">
+        <el-input v-model="formData.component" clearable placeholder="例如说:system/user/index" />
       </el-form-item>
-      <el-form-item label="组件名字" prop="componentName" v-if="formData.type === 2">
-        <el-input v-model="formData.componentName" placeholder="例如说:SystemUser" clearable />
+      <el-form-item v-if="formData.type === 2" label="组件名字" prop="componentName">
+        <el-input v-model="formData.componentName" clearable placeholder="例如说:SystemUser" />
       </el-form-item>
-      <el-form-item label="权限标识" prop="permission" v-if="formData.type !== 1">
+      <el-form-item v-if="formData.type !== 1" label="权限标识" prop="permission">
         <template #label>
           <Tooltip
-            titel="权限标识"
             message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)"
+            titel="权限标识"
           />
         </template>
-        <el-input v-model="formData.permission" placeholder="请输入权限标识" clearable />
+        <el-input v-model="formData.permission" clearable placeholder="请输入权限标识" />
       </el-form-item>
       <el-form-item label="显示排序" prop="sort">
-        <el-input-number v-model="formData.sort" controls-position="right" :min="0" clearable />
+        <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" />
       </el-form-item>
       <el-form-item label="菜单状态" prop="status">
         <el-radio-group v-model="formData.status">
@@ -72,52 +72,53 @@
           </el-radio>
         </el-radio-group>
       </el-form-item>
-      <el-form-item label="显示状态" prop="visible" v-if="formData.type !== 3">
+      <el-form-item v-if="formData.type !== 3" label="显示状态" prop="visible">
         <template #label>
-          <Tooltip titel="显示状态" message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" />
+          <Tooltip message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" titel="显示状态" />
         </template>
         <el-radio-group v-model="formData.visible">
-          <el-radio border key="true" :label="true">显示</el-radio>
-          <el-radio border key="false" :label="false">隐藏</el-radio>
+          <el-radio key="true" :label="true" border>显示</el-radio>
+          <el-radio key="false" :label="false" border>隐藏</el-radio>
         </el-radio-group>
       </el-form-item>
-      <el-form-item label="总是显示" prop="alwaysShow" v-if="formData.type !== 3">
+      <el-form-item v-if="formData.type !== 3" label="总是显示" prop="alwaysShow">
         <template #label>
           <Tooltip
-            titel="总是显示"
             message="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单"
+            titel="总是显示"
           />
         </template>
         <el-radio-group v-model="formData.alwaysShow">
-          <el-radio border key="true" :label="true">总是</el-radio>
-          <el-radio border key="false" :label="false">不是</el-radio>
+          <el-radio key="true" :label="true" border>总是</el-radio>
+          <el-radio key="false" :label="false" border>不是</el-radio>
         </el-radio-group>
       </el-form-item>
-      <el-form-item label="缓存状态" prop="keepAlive" v-if="formData.type === 2">
+      <el-form-item v-if="formData.type === 2" label="缓存状态" prop="keepAlive">
         <template #label>
           <Tooltip
-            titel="缓存状态"
             message="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段"
+            titel="缓存状态"
           />
         </template>
         <el-radio-group v-model="formData.keepAlive">
-          <el-radio border key="true" :label="true">缓存</el-radio>
-          <el-radio border key="false" :label="false">不缓存</el-radio>
+          <el-radio key="true" :label="true" border>缓存</el-radio>
+          <el-radio key="false" :label="false" border>不缓存</el-radio>
         </el-radio-group>
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemMenuForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as MenuApi from '@/api/system/menu'
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
-import { SystemMenuTypeEnum, CommonStatusEnum } from '@/utils/constants'
-import { handleTree, defaultProps } from '@/utils/tree'
+import { CommonStatusEnum, SystemMenuTypeEnum } from '@/utils/constants'
+import { defaultProps, handleTree } from '@/utils/tree'
+
 const { wsCache } = useCache()
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
diff --git a/src/views/system/notice/NoticeForm.vue b/src/views/system/notice/NoticeForm.vue
index bf76c7d0..114a2c81 100644
--- a/src/views/system/notice/NoticeForm.vue
+++ b/src/views/system/notice/NoticeForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" width="800">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="800">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="公告标题" prop="title">
         <el-input v-model="formData.title" placeholder="请输入公告标题" />
@@ -14,7 +14,7 @@
         <Editor :model-value="formData.content" height="150px" />
       </el-form-item>
       <el-form-item label="公告类型" prop="type">
-        <el-select v-model="formData.type" placeholder="请选择公告类型" clearable>
+        <el-select v-model="formData.type" clearable placeholder="请选择公告类型">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_NOTICE_TYPE)"
             :key="parseInt(dict.value)"
@@ -24,7 +24,7 @@
         </el-select>
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="parseInt(dict.value)"
@@ -34,19 +34,20 @@
         </el-select>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
+        <el-input v-model="formData.remark" placeholder="请输备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemNoticeForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as NoticeApi from '@/api/system/notice'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/notify/message/NotifyMessageDetail.vue b/src/views/system/notify/message/NotifyMessageDetail.vue
index 0a29ebb1..908d75a3 100644
--- a/src/views/system/notify/message/NotifyMessageDetail.vue
+++ b/src/views/system/notify/message/NotifyMessageDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="编号" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -40,7 +40,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemNotifyMessageDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as NotifyMessageApi from '@/api/system/notify/message'
diff --git a/src/views/system/notify/my/MyNotifyMessageDetail.vue b/src/views/system/notify/my/MyNotifyMessageDetail.vue
index 247136b0..ad45d4eb 100644
--- a/src/views/system/notify/my/MyNotifyMessageDetail.vue
+++ b/src/views/system/notify/my/MyNotifyMessageDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="消息详情" v-model="dialogVisible" :scroll="true" :max-height="500">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="消息详情">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="发送人">
         {{ detailData.templateNickname }}
       </el-descriptions-item>
@@ -13,7 +13,7 @@
       <el-descriptions-item label="是否已读">
         <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="detailData.readStatus" />
       </el-descriptions-item>
-      <el-descriptions-item label="阅读时间" v-if="detailData.readStatus">
+      <el-descriptions-item v-if="detailData.readStatus" label="阅读时间">
         {{ formatDate(detailData.readTime) }}
       </el-descriptions-item>
       <el-descriptions-item label="内容">
@@ -22,7 +22,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="MyNotifyMessageDetailDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as NotifyMessageApi from '@/api/system/notify/message'
diff --git a/src/views/system/oauth2/client/ClientForm.vue b/src/views/system/oauth2/client/ClientForm.vue
index b5936c37..d874a249 100644
--- a/src/views/system/oauth2/client/ClientForm.vue
+++ b/src/views/system/oauth2/client/ClientForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" scroll max-height="500px">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" max-height="500px" scroll>
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="160px"
-      v-loading="formLoading"
     >
       <el-form-item label="客户端编号" prop="secret">
         <el-input v-model="formData.clientId" placeholder="请输入客户端编号" />
@@ -20,7 +20,7 @@
         <UploadImg v-model="formData.logo" :limit="1" />
       </el-form-item>
       <el-form-item label="应用描述">
-        <el-input type="textarea" v-model="formData.description" placeholder="请输入应用名" />
+        <el-input v-model="formData.description" placeholder="请输入应用名" type="textarea" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
         <el-radio-group v-model="formData.status">
@@ -42,8 +42,8 @@
       <el-form-item label="授权类型" prop="authorizedGrantTypes">
         <el-select
           v-model="formData.authorizedGrantTypes"
-          multiple
           filterable
+          multiple
           placeholder="请输入授权类型"
           style="width: 500px"
         >
@@ -58,9 +58,9 @@
       <el-form-item label="授权范围" prop="scopes">
         <el-select
           v-model="formData.scopes"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请输入授权范围"
           style="width: 500px"
         >
@@ -70,8 +70,8 @@
       <el-form-item label="自动授权范围" prop="autoApproveScopes">
         <el-select
           v-model="formData.autoApproveScopes"
-          multiple
           filterable
+          multiple
           placeholder="请输入授权范围"
           style="width: 500px"
         >
@@ -81,9 +81,9 @@
       <el-form-item label="可重定向的 URI 地址" prop="redirectUris">
         <el-select
           v-model="formData.redirectUris"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请输入可重定向的 URI 地址"
           style="width: 500px"
         >
@@ -98,9 +98,9 @@
       <el-form-item label="权限" prop="authorities">
         <el-select
           v-model="formData.authorities"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请输入权限"
           style="width: 500px"
         >
@@ -115,9 +115,9 @@
       <el-form-item label="资源" prop="resourceIds">
         <el-select
           v-model="formData.resourceIds"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请输入资源"
           style="width: 500px"
         >
@@ -131,22 +131,23 @@
       </el-form-item>
       <el-form-item label="附加信息" prop="additionalInformation">
         <el-input
-          type="textarea"
           v-model="formData.additionalInformation"
           placeholder="请输入附加信息,JSON 格式数据"
+          type="textarea"
         />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemOAuth2ClientForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as ClientApi from '@/api/system/oauth2/client'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/operatelog/OperateLogDetail.vue b/src/views/system/operatelog/OperateLogDetail.vue
index 1cf88663..f69af13a 100644
--- a/src/views/system/operatelog/OperateLogDetail.vue
+++ b/src/views/system/operatelog/OperateLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500" width="800">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志主键" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -25,10 +25,10 @@
       <el-descriptions-item label="操作名">
         {{ detailData.name }}
       </el-descriptions-item>
-      <el-descriptions-item label="操作内容" v-if="detailData.content">
+      <el-descriptions-item v-if="detailData.content" label="操作内容">
         {{ detailData.content }}
       </el-descriptions-item>
-      <el-descriptions-item label="操作拓展参数" v-if="detailData.exts">
+      <el-descriptions-item v-if="detailData.exts" label="操作拓展参数">
         {{ detailData.exts }}
       </el-descriptions-item>
       <el-descriptions-item label="请求 URL">
@@ -48,16 +48,16 @@
         <div v-if="detailData.resultCode === 0">正常</div>
         <div v-else>失败({{ detailData.resultCode }})</div>
       </el-descriptions-item>
-      <el-descriptions-item label="操作结果" v-if="detailData.resultCode === 0">
+      <el-descriptions-item v-if="detailData.resultCode === 0" label="操作结果">
         {{ detailData.resultData }}
       </el-descriptions-item>
-      <el-descriptions-item label="失败提示" v-if="detailData.resultCode > 0">
+      <el-descriptions-item v-if="detailData.resultCode > 0" label="失败提示">
         {{ detailData.resultMsg }}
       </el-descriptions-item>
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemOperateLogDetail" setup>
 import { formatDate } from '@/utils/formatTime'
 import * as OperateLogApi from '@/api/system/operatelog'
 
diff --git a/src/views/system/post/PostForm.vue b/src/views/system/post/PostForm.vue
index 586b86c6..e4ea8ad7 100644
--- a/src/views/system/post/PostForm.vue
+++ b/src/views/system/post/PostForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" width="800">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="800">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="岗位标题" prop="name">
         <el-input v-model="formData.name" placeholder="请输入岗位标题" />
@@ -17,7 +17,7 @@
         <el-input v-model="formData.sort" placeholder="请输入岗位顺序" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -27,16 +27,16 @@
         </el-select>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
+        <el-input v-model="formData.remark" placeholder="请输备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemPostForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as PostApi from '@/api/system/post'
diff --git a/src/views/system/role/RoleAssignMenuForm.vue b/src/views/system/role/RoleAssignMenuForm.vue
index cc8e2708..9b7d5a15 100644
--- a/src/views/system/role/RoleAssignMenuForm.vue
+++ b/src/views/system/role/RoleAssignMenuForm.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="菜单权限" v-model="dialogVisible">
-    <el-form ref="formRef" :model="formData" label-width="80px" v-loading="formLoading">
+  <Dialog v-model="dialogVisible" title="菜单权限">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
       <el-form-item label="角色名称">
         <el-tag>{{ formData.name }}</el-tag>
       </el-form-item>
@@ -13,42 +13,43 @@
             全选/全不选:
             <el-switch
               v-model="treeNodeAll"
-              inline-prompt
               active-text="是"
               inactive-text="否"
+              inline-prompt
               @change="handleCheckedTreeNodeAll"
             />
             全部展开/折叠:
             <el-switch
               v-model="menuExpand"
-              inline-prompt
               active-text="展开"
               inactive-text="折叠"
+              inline-prompt
               @change="handleCheckedTreeExpand"
             />
           </template>
           <el-tree
             ref="treeRef"
+            :data="menuOptions"
+            :props="defaultProps"
+            empty-text="加载中,请稍候"
             node-key="id"
             show-checkbox
-            :props="defaultProps"
-            :data="menuOptions"
-            empty-text="加载中,请稍候"
           />
         </el-card>
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
-import { handleTree, defaultProps } from '@/utils/tree'
+<script lang="ts" name="SystemRoleAssignMenuForm" setup>
+import { defaultProps, handleTree } from '@/utils/tree'
 import * as RoleApi from '@/api/system/role'
 import * as MenuApi from '@/api/system/menu'
 import * as PermissionApi from '@/api/system/permission'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/role/RoleDataPermissionForm.vue b/src/views/system/role/RoleDataPermissionForm.vue
index 6b017278..87a33e6c 100644
--- a/src/views/system/role/RoleDataPermissionForm.vue
+++ b/src/views/system/role/RoleDataPermissionForm.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="菜单权限" v-model="dialogVisible" width="800">
-    <el-form ref="formRef" :model="formData" label-width="80px" v-loading="formLoading">
+  <Dialog v-model="dialogVisible" title="菜单权限" width="800">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
       <el-form-item label="角色名称">
         <el-tag>{{ formData.name }}</el-tag>
       </el-form-item>
@@ -19,8 +19,8 @@
       </el-form-item>
     </el-form>
     <el-form-item
-      label="权限范围"
       v-if="formData.dataScope === SystemDataScopeEnum.DEPT_CUSTOM"
+      label="权限范围"
       style="display: flex"
     >
       <el-card class="card" shadow="never">
@@ -28,47 +28,48 @@
           全选/全不选:
           <el-switch
             v-model="treeNodeAll"
-            inline-prompt
             active-text="是"
             inactive-text="否"
+            inline-prompt
             @change="handleCheckedTreeNodeAll()"
           />
           全部展开/折叠:
           <el-switch
             v-model="deptExpand"
-            inline-prompt
             active-text="展开"
             inactive-text="折叠"
+            inline-prompt
             @change="handleCheckedTreeExpand"
           />
           父子联动(选中父节点,自动选择子节点):
-          <el-switch v-model="checkStrictly" inline-prompt active-text="是" inactive-text="否" />
+          <el-switch v-model="checkStrictly" active-text="是" inactive-text="否" inline-prompt />
         </template>
         <el-tree
           ref="treeRef"
+          :check-strictly="!checkStrictly"
+          :data="deptOptions"
+          :props="defaultProps"
+          default-expand-all
+          empty-text="加载中,请稍后"
           node-key="id"
           show-checkbox
-          :check-strictly="!checkStrictly"
-          :props="defaultProps"
-          :data="deptOptions"
-          empty-text="加载中,请稍后"
-          default-expand-all
         />
       </el-card>
     </el-form-item>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemRoleDataPermissionForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { handleTree, defaultProps } from '@/utils/tree'
+import { defaultProps, handleTree } from '@/utils/tree'
 import { SystemDataScopeEnum } from '@/utils/constants'
 import * as RoleApi from '@/api/system/role'
 import * as DeptApi from '@/api/system/dept'
 import * as PermissionApi from '@/api/system/permission'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/role/RoleForm.vue b/src/views/system/role/RoleForm.vue
index eecd2cdd..828d7f14 100644
--- a/src/views/system/role/RoleForm.vue
+++ b/src/views/system/role/RoleForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="角色名称" prop="name">
         <el-input v-model="formData.name" placeholder="请输入角色名称" />
@@ -17,7 +17,7 @@
         <el-input v-model="formData.sort" placeholder="请输入显示顺序" />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+        <el-select v-model="formData.status" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -27,19 +27,20 @@
         </el-select>
       </el-form-item>
       <el-form-item label="备注" prop="remark">
-        <el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
+        <el-input v-model="formData.remark" placeholder="请输备注" type="textarea" />
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemRoleForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import * as RoleApi from '@/api/system/role'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/role/index.vue b/src/views/system/role/index.vue
index 618a4990..4df19ef8 100644
--- a/src/views/system/role/index.vue
+++ b/src/views/system/role/index.vue
@@ -5,32 +5,32 @@
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form
-      class="-mb-15px"
-      :model="queryParams"
       ref="queryFormRef"
       :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
       label-width="68px"
     >
       <el-form-item label="角色名称" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输入角色名称"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请输入角色名称"
+          @keyup.enter="handleQuery"
         />
       </el-form-item>
       <el-form-item label="角色标识" prop="code">
         <el-input
           v-model="queryParams.code"
-          placeholder="请输入角色标识"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请输入角色标识"
+          @keyup.enter="handleQuery"
         />
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择状态" clearable class="!w-240px">
+        <el-select v-model="queryParams.status" class="!w-240px" clearable placeholder="请选择状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -42,33 +42,41 @@
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
           class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['system:role:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
         </el-button>
         <el-button
-          type="success"
+          v-hasPermi="['system:role:create']"
           plain
-          @click="handleExport"
-          :loading="exportLoading"
-          v-hasPermi="['system:role:export']"
+          type="primary"
+          @click="openForm('create')"
         >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
+          <Icon class="mr-5px" icon="ep:plus" />
+          新增
+        </el-button>
+        <el-button
+          v-hasPermi="['system:role:export']"
+          :loading="exportLoading"
+          plain
+          type="success"
+          @click="handleExport"
+        >
+          <Icon class="mr-5px" icon="ep:download" />
+          导出
         </el-button>
       </el-form-item>
     </el-form>
@@ -77,59 +85,59 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list">
-      <el-table-column label="角色编号" align="center" prop="id" />
-      <el-table-column label="角色名称" align="center" prop="name" />
-      <el-table-column label="角色类型" align="center" prop="type" />
-      <el-table-column label="角色标识" align="center" prop="code" />
-      <el-table-column label="显示顺序" align="center" prop="sort" />
-      <el-table-column label="备注" align="center" prop="remark" />
-      <el-table-column label="状态" align="center" prop="status">
+      <el-table-column align="center" label="角色编号" prop="id" />
+      <el-table-column align="center" label="角色名称" prop="name" />
+      <el-table-column align="center" label="角色类型" prop="type" />
+      <el-table-column align="center" label="角色标识" prop="code" />
+      <el-table-column align="center" label="显示顺序" prop="sort" />
+      <el-table-column align="center" label="备注" prop="remark" />
+      <el-table-column align="center" label="状态" prop="status">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
         </template>
       </el-table-column>
       <el-table-column
-        label="创建时间"
+        :formatter="dateFormatter"
         align="center"
+        label="创建时间"
         prop="createTime"
         width="180"
-        :formatter="dateFormatter"
       />
-      <el-table-column :width="300" label="操作" align="center">
+      <el-table-column :width="300" align="center" label="操作">
         <template #default="scope">
           <el-button
+            v-hasPermi="['system:role:update']"
             link
             type="primary"
             @click="openForm('update', scope.row.id)"
-            v-hasPermi="['system:role:update']"
           >
             编辑
           </el-button>
           <el-button
+            v-hasPermi="['system:permission:assign-role-menu']"
             link
-            type="primary"
             preIcon="ep:basketball"
             title="菜单权限"
-            v-hasPermi="['system:permission:assign-role-menu']"
+            type="primary"
             @click="openAssignMenuForm(scope.row)"
           >
             菜单权限
           </el-button>
           <el-button
+            v-hasPermi="['system:permission:assign-role-data-scope']"
             link
-            type="primary"
             preIcon="ep:coin"
             title="数据权限"
-            v-hasPermi="['system:permission:assign-role-data-scope']"
+            type="primary"
             @click="openDataPermissionForm(scope.row)"
           >
             数据权限
           </el-button>
           <el-button
+            v-hasPermi="['system:role:delete']"
             link
             type="danger"
             @click="handleDelete(scope.row.id)"
-            v-hasPermi="['system:role:delete']"
           >
             删除
           </el-button>
@@ -138,9 +146,9 @@
     </el-table>
     <!-- 分页 -->
     <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
       v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
       @pagination="getList"
     />
   </ContentWrap>
@@ -152,7 +160,7 @@
   <!-- 表单弹窗:数据权限 -->
   <RoleDataPermissionForm ref="dataPermissionFormRef" />
 </template>
-<script setup lang="tsx" name="SystemRole">
+<script lang="ts" name="SystemRole" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
@@ -160,6 +168,7 @@ import * as RoleApi from '@/api/system/role'
 import RoleForm from './RoleForm.vue'
 import RoleAssignMenuForm from './RoleAssignMenuForm.vue'
 import RoleDataPermissionForm from './RoleDataPermissionForm.vue'
+
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 
diff --git a/src/views/system/sensitiveWord/SensitiveWordForm.vue b/src/views/system/sensitiveWord/SensitiveWordForm.vue
index aebaf6de..d9b5b78f 100644
--- a/src/views/system/sensitiveWord/SensitiveWordForm.vue
+++ b/src/views/system/sensitiveWord/SensitiveWordForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="敏感词" prop="name">
         <el-input v-model="formData.name" placeholder="请输入敏感词" />
@@ -27,9 +27,9 @@
       <el-form-item label="标签" prop="tags">
         <el-select
           v-model="formData.tags"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请选择文章标签"
           style="width: 380px"
         >
@@ -38,15 +38,16 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts" name="SensitiveWordForm">
+<script lang="ts" name="SystemSensitiveWordForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as SensitiveWordApi from '@/api/system/sensitiveWord'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/sensitiveWord/SensitiveWordTestForm.vue b/src/views/system/sensitiveWord/SensitiveWordTestForm.vue
index 80308033..93750603 100644
--- a/src/views/system/sensitiveWord/SensitiveWordTestForm.vue
+++ b/src/views/system/sensitiveWord/SensitiveWordTestForm.vue
@@ -1,21 +1,21 @@
 <template>
-  <Dialog title="检测敏感词" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="检测敏感词">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="文本" prop="text">
-        <el-input type="textarea" v-model="formData.text" placeholder="请输入测试文本" />
+        <el-input v-model="formData.text" placeholder="请输入测试文本" type="textarea" />
       </el-form-item>
       <el-form-item label="标签" prop="tags">
         <el-select
           v-model="formData.tags"
-          multiple
-          filterable
           allow-create
+          filterable
+          multiple
           placeholder="请选择标签"
           style="width: 380px"
         >
@@ -24,13 +24,14 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">检 测</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">检 测</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemSensitiveWordTestForm" setup>
 import * as SensitiveWordApi from '@/api/system/sensitiveWord'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/system/sensitiveWord/index.vue b/src/views/system/sensitiveWord/index.vue
index 741d873c..921bde3e 100644
--- a/src/views/system/sensitiveWord/index.vue
+++ b/src/views/system/sensitiveWord/index.vue
@@ -2,34 +2,34 @@
   <!-- 搜索工作栏 -->
   <ContentWrap>
     <el-form
-      class="-mb-15px"
-      :model="queryParams"
       ref="queryFormRef"
       :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
       label-width="68px"
     >
       <el-form-item label="敏感词" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输入敏感词"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请输入敏感词"
+          @keyup.enter="handleQuery"
         />
       </el-form-item>
       <el-form-item label="标签" prop="tag">
         <el-select
           v-model="queryParams.tag"
-          placeholder="请选择标签"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请选择标签"
+          @keyup.enter="handleQuery"
         >
           <el-option v-for="tag in tagList" :key="tag" :label="tag" :value="tag" />
         </el-select>
       </el-form-item>
       <el-form-item label="状态" prop="status">
-        <el-select v-model="queryParams.status" placeholder="请选择启用状态" clearable>
+        <el-select v-model="queryParams.status" clearable placeholder="请选择启用状态">
           <el-option
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
@@ -42,36 +42,45 @@
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
           class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
         <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
           v-hasPermi="['system:sensitive-word:create']"
+          plain
+          type="primary"
+          @click="openForm('create')"
         >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
+          <Icon class="mr-5px" icon="ep:plus" />
+          新增
         </el-button>
         <el-button
-          type="success"
-          plain
-          @click="handleExport"
-          :loading="exportLoading"
           v-hasPermi="['system:sensitive-word:export']"
+          :loading="exportLoading"
+          plain
+          type="success"
+          @click="handleExport"
         >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
+          <Icon class="mr-5px" icon="ep:download" />
+          导出
         </el-button>
-        <el-button type="warning" plain @click="openTestForm">
-          <Icon icon="ep:document-checked" class="mr-5px" /> 测试
+        <el-button plain type="warning" @click="openTestForm">
+          <Icon class="mr-5px" icon="ep:document-checked" />
+          测试
         </el-button>
       </el-form-item>
     </el-form>
@@ -80,48 +89,48 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list">
-      <el-table-column label="编号" align="center" prop="id" />
-      <el-table-column label="敏感词" align="center" prop="name" />
-      <el-table-column label="状态" align="center" prop="status">
+      <el-table-column align="center" label="编号" prop="id" />
+      <el-table-column align="center" label="敏感词" prop="name" />
+      <el-table-column align="center" label="状态" prop="status">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
         </template>
       </el-table-column>
-      <el-table-column label="描述" align="center" prop="description" />
-      <el-table-column label="标签" align="center" prop="tags">
+      <el-table-column align="center" label="描述" prop="description" />
+      <el-table-column align="center" label="标签" prop="tags">
         <template #default="scope">
           <el-tag
-            class="mr-5px"
             v-for="tag in scope.row.tags"
             :key="tag"
             :disable-transitions="true"
+            class="mr-5px"
           >
             {{ tag }}
           </el-tag>
         </template>
       </el-table-column>
       <el-table-column
-        label="创建时间"
+        :formatter="dateFormatter"
         align="center"
+        label="创建时间"
         prop="createTime"
         width="180"
-        :formatter="dateFormatter"
       />
-      <el-table-column label="操作" align="center">
+      <el-table-column align="center" label="操作">
         <template #default="scope">
           <el-button
+            v-hasPermi="['infra:config:update']"
             link
             type="primary"
             @click="openForm('update', scope.row.id)"
-            v-hasPermi="['infra:config:update']"
           >
             编辑
           </el-button>
           <el-button
+            v-hasPermi="['infra:config:delete']"
             link
             type="danger"
             @click="handleDelete(scope.row.id)"
-            v-hasPermi="['infra:config:delete']"
           >
             删除
           </el-button>
@@ -130,9 +139,9 @@
     </el-table>
     <!-- 分页 -->
     <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
       v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
       @pagination="getList"
     />
   </ContentWrap>
@@ -143,13 +152,14 @@
   <!-- 表单弹窗:测试敏感词 -->
   <SensitiveWordTestForm ref="testFormRef" />
 </template>
-<script setup lang="ts" name="SystemSensitiveWordhao">
+<script lang="ts" name="SystemSensitiveWordHao" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import * as SensitiveWordApi from '@/api/system/sensitiveWord'
 import SensitiveWordForm from './SensitiveWordForm.vue'
 import SensitiveWordTestForm from './SensitiveWordTestForm.vue'
+
 const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 
diff --git a/src/views/system/sms/channel/SmsChannelForm.vue b/src/views/system/sms/channel/SmsChannelForm.vue
index cd491112..c5267393 100644
--- a/src/views/system/sms/channel/SmsChannelForm.vue
+++ b/src/views/system/sms/channel/SmsChannelForm.vue
@@ -1,17 +1,17 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="130px"
-      v-loading="formLoading"
     >
       <el-form-item label="短信签名" prop="signature">
         <el-input v-model="formData.signature" placeholder="请输入短信签名" />
       </el-form-item>
       <el-form-item label="渠道编码" prop="code">
-        <el-select v-model="formData.code" placeholder="请选择渠道编码" clearable>
+        <el-select v-model="formData.code" clearable placeholder="请选择渠道编码">
           <el-option
             v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE)"
             :key="dict.value"
@@ -45,15 +45,16 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemSmsChannelForm" setup>
 import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
 import * as SmsChannelApi from '@/api/system/sms/smsChannel'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/sms/log/SmsLogDetail.vue b/src/views/system/sms/log/SmsLogDetail.vue
index 8a368b3e..bb63de03 100644
--- a/src/views/system/sms/log/SmsLogDetail.vue
+++ b/src/views/system/sms/log/SmsLogDetail.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="500" width="800">
-    <el-descriptions border :column="1">
+  <Dialog v-model="dialogVisible" :max-height="500" :scroll="true" title="详情" width="800">
+    <el-descriptions :column="1" border>
       <el-descriptions-item label="日志主键" min-width="120">
         {{ detailData.id }}
       </el-descriptions-item>
@@ -59,7 +59,7 @@
     </el-descriptions>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemSmsLogDetail" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
 import * as SmsLogApi from '@/api/system/sms/smsLog'
diff --git a/src/views/system/sms/template/SmsTemplateForm.vue b/src/views/system/sms/template/SmsTemplateForm.vue
index 22de060a..91bf829a 100644
--- a/src/views/system/sms/template/SmsTemplateForm.vue
+++ b/src/views/system/sms/template/SmsTemplateForm.vue
@@ -1,22 +1,22 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="140px"
-      v-loading="formLoading"
     >
       <el-form-item label="短信渠道编号" prop="channelId">
         <el-select v-model="formData.channelId" placeholder="请选择短信渠道编号">
           <el-option
             v-for="channel in channelList"
             :key="channel.id"
-            :value="channel.id"
             :label="
               channel.signature +
               `【 ${getDictLabel(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE, channel.code)}】`
             "
+            :value="channel.id"
           />
         </el-select>
       </el-form-item>
@@ -37,7 +37,7 @@
         <el-input v-model="formData.name" placeholder="请输入模板名称" />
       </el-form-item>
       <el-form-item label="模板内容" prop="content">
-        <el-input type="textarea" v-model="formData.content" placeholder="请输入模板内容" />
+        <el-input v-model="formData.content" placeholder="请输入模板内容" type="textarea" />
       </el-form-item>
       <el-form-item label="开启状态" prop="status">
         <el-radio-group v-model="formData.status">
@@ -58,16 +58,17 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
-import { DICT_TYPE, getIntDictOptions, getDictLabel } from '@/utils/dict'
+<script lang="ts" name="SystemSmsTemplateForm" setup>
+import { DICT_TYPE, getDictLabel, getIntDictOptions } from '@/utils/dict'
 import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
 import * as SmsChannelApi from '@/api/system/sms/smsChannel'
 import { CommonStatusEnum } from '@/utils/constants'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/sms/template/SmsTemplateSendForm.vue b/src/views/system/sms/template/SmsTemplateSendForm.vue
index 2da0e3f6..ec204ec3 100644
--- a/src/views/system/sms/template/SmsTemplateSendForm.vue
+++ b/src/views/system/sms/template/SmsTemplateSendForm.vue
@@ -1,18 +1,18 @@
 <template>
-  <Dialog title="测试" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" title="测试">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="140px"
-      v-loading="formLoading"
     >
       <el-form-item label="模板内容" prop="content">
         <el-input
           v-model="formData.content"
-          type="textarea"
           placeholder="请输入模板内容"
           readonly
+          type="textarea"
         />
       </el-form-item>
       <el-form-item label="手机号" prop="mobile">
@@ -31,13 +31,14 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemSmsTemplateSendForm" setup>
 import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示
diff --git a/src/views/system/tenant/TenantForm.vue b/src/views/system/tenant/TenantForm.vue
index ec19b487..c6bd6fec 100644
--- a/src/views/system/tenant/TenantForm.vue
+++ b/src/views/system/tenant/TenantForm.vue
@@ -1,17 +1,17 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" width="50%">
+  <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="租户名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入租户名" />
       </el-form-item>
       <el-form-item label="租户套餐" prop="packageId">
-        <el-select v-model="formData.packageId" placeholder="请选择租户套餐" clearable>
+        <el-select v-model="formData.packageId" clearable placeholder="请选择租户套餐">
           <el-option
             v-for="item in packageList"
             :key="item.id"
@@ -33,25 +33,25 @@
         <el-input
           v-model="formData.password"
           placeholder="请输入用户密码"
-          type="password"
           show-password
+          type="password"
         />
       </el-form-item>
       <el-form-item label="账号额度" prop="accountCount">
         <el-input-number
           v-model="formData.accountCount"
-          placeholder="请输入账号额度"
-          controls-position="right"
           :min="0"
+          controls-position="right"
+          placeholder="请输入账号额度"
         />
       </el-form-item>
       <el-form-item label="过期时间" prop="expireTime">
         <el-date-picker
-          clearable
           v-model="formData.expireTime"
+          clearable
+          placeholder="请选择过期时间"
           type="date"
           value-format="x"
-          placeholder="请选择过期时间"
         />
       </el-form-item>
       <el-form-item label="绑定域名" prop="domain">
@@ -70,12 +70,12 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemTenantForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as TenantApi from '@/api/system/tenant'
 import { CommonStatusEnum } from '@/utils/constants'
diff --git a/src/views/system/tenantPackage/TenantPackageForm.vue b/src/views/system/tenantPackage/TenantPackageForm.vue
index becbcaab..d4230261 100644
--- a/src/views/system/tenantPackage/TenantPackageForm.vue
+++ b/src/views/system/tenantPackage/TenantPackageForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-form-item label="套餐名" prop="name">
         <el-input v-model="formData.name" placeholder="请输入套餐名" />
@@ -16,27 +16,27 @@
             全选/全不选:
             <el-switch
               v-model="treeNodeAll"
-              inline-prompt
               active-text="是"
               inactive-text="否"
+              inline-prompt
               @change="handleCheckedTreeNodeAll"
             />
             全部展开/折叠:
             <el-switch
               v-model="menuExpand"
-              inline-prompt
               active-text="展开"
               inactive-text="折叠"
+              inline-prompt
               @change="handleCheckedTreeExpand"
             />
           </template>
           <el-tree
             ref="treeRef"
+            :data="menuOptions"
+            :props="defaultProps"
+            empty-text="加载中,请稍候"
             node-key="id"
             show-checkbox
-            :props="defaultProps"
-            :data="menuOptions"
-            empty-text="加载中,请稍候"
           />
         </el-card>
       </el-form-item>
@@ -56,18 +56,19 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts" name="TenantPackageForm">
+<script lang="ts" name="SystemTenantPackageForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import { defaultProps, handleTree } from '@/utils/tree'
 import * as TenantPackageApi from '@/api/system/tenantPackage'
 import * as MenuApi from '@/api/system/menu'
 import { ElTree } from 'element-plus'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/user/DeptTree.vue b/src/views/system/user/DeptTree.vue
index 87ffaf9a..c7bc14ba 100644
--- a/src/views/system/user/DeptTree.vue
+++ b/src/views/system/user/DeptTree.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="head-container">
-    <el-input v-model="deptName" placeholder="请输入部门名称" clearable class="mb-20px">
+    <el-input v-model="deptName" class="mb-20px" clearable placeholder="请输入部门名称">
       <template #prefix>
         <Icon icon="ep:search" />
       </template>
@@ -8,20 +8,20 @@
   </div>
   <div class="head-container">
     <el-tree
+      ref="treeRef"
       :data="deptList"
-      :props="defaultProps"
-      node-key="id"
       :expand-on-click-node="false"
       :filter-node-method="filterNode"
-      ref="treeRef"
+      :props="defaultProps"
       default-expand-all
       highlight-current
+      node-key="id"
       @node-click="handleNodeClick"
     />
   </div>
 </template>
 
-<script setup lang="ts" name="UserDeptTree">
+<script lang="ts" name="SystemUserDeptTree" setup>
 import { ElTree } from 'element-plus'
 import * as DeptApi from '@/api/system/dept'
 import { defaultProps, handleTree } from '@/utils/tree'
diff --git a/src/views/system/user/UserAssignRoleForm.vue b/src/views/system/user/UserAssignRoleForm.vue
index e0259b7d..a8e8fae3 100644
--- a/src/views/system/user/UserAssignRoleForm.vue
+++ b/src/views/system/user/UserAssignRoleForm.vue
@@ -1,6 +1,6 @@
 <template>
-  <Dialog title="分配角色" v-model="dialogVisible">
-    <el-form ref="formRef" :model="formData" label-width="80px" v-loading="formLoading">
+  <Dialog v-model="dialogVisible" title="分配角色">
+    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
       <el-form-item label="用户名称">
         <el-input v-model="formData.username" :disabled="true" />
       </el-form-item>
@@ -14,15 +14,16 @@
       </el-form-item>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="SystemUserAssignRoleForm" setup>
 import * as PermissionApi from '@/api/system/permission'
 import * as UserApi from '@/api/system/user'
 import * as RoleApi from '@/api/system/role'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/user/UserForm.vue b/src/views/system/user/UserForm.vue
index 3afcbd1f..47dec515 100644
--- a/src/views/system/user/UserForm.vue
+++ b/src/views/system/user/UserForm.vue
@@ -1,11 +1,11 @@
 <template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible">
+  <Dialog v-model="dialogVisible" :title="dialogTitle">
     <el-form
       ref="formRef"
+      v-loading="formLoading"
       :model="formData"
       :rules="formRules"
       label-width="80px"
-      v-loading="formLoading"
     >
       <el-row>
         <el-col :span="12">
@@ -16,11 +16,11 @@
         <el-col :span="12">
           <el-form-item label="归属部门" prop="deptId">
             <el-tree-select
-              node-key="id"
               v-model="formData.deptId"
               :data="deptList"
               :props="defaultProps"
               check-strictly
+              node-key="id"
               placeholder="请选择归属部门"
             />
           </el-form-item>
@@ -29,12 +29,12 @@
       <el-row>
         <el-col :span="12">
           <el-form-item label="手机号码" prop="mobile">
-            <el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
+            <el-input v-model="formData.mobile" maxlength="11" placeholder="请输入手机号码" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="邮箱" prop="email">
-            <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
+            <el-input v-model="formData.email" maxlength="50" placeholder="请输入邮箱" />
           </el-form-item>
         </el-col>
       </el-row>
@@ -49,8 +49,8 @@
             <el-input
               v-model="formData.password"
               placeholder="请输入用户密码"
-              type="password"
               show-password
+              type="password"
             />
           </el-form-item>
         </el-col>
@@ -84,24 +84,25 @@
       <el-row>
         <el-col :span="24">
           <el-form-item label="备注">
-            <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
+            <el-input v-model="formData.remark" placeholder="请输入内容" type="textarea" />
           </el-form-item>
         </el-col>
       </el-row>
     </el-form>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script lang="ts" setup>
+<script lang="ts" name="SystemUserForm" setup>
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { CommonStatusEnum } from '@/utils/constants'
 import { defaultProps, handleTree } from '@/utils/tree'
 import * as PostApi from '@/api/system/post'
 import * as DeptApi from '@/api/system/dept'
 import * as UserApi from '@/api/system/user'
+
 const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
diff --git a/src/views/system/user/UserImportForm.vue b/src/views/system/user/UserImportForm.vue
index f03345e9..9890c00c 100644
--- a/src/views/system/user/UserImportForm.vue
+++ b/src/views/system/user/UserImportForm.vue
@@ -1,31 +1,32 @@
 <template>
-  <Dialog title="用户导入" v-model="dialogVisible" width="400">
+  <Dialog v-model="dialogVisible" title="用户导入" width="400">
     <el-upload
       ref="uploadRef"
-      :action="importUrl + '?updateSupport=' + updateSupport"
-      :headers="uploadHeaders"
       v-model:file-list="fileList"
-      drag
-      accept=".xlsx, .xls"
-      :limit="1"
-      :on-success="submitFormSuccess"
-      :on-exceed="handleExceed"
-      :on-error="submitFormError"
+      :action="importUrl + '?updateSupport=' + updateSupport"
       :auto-upload="false"
       :disabled="formLoading"
+      :headers="uploadHeaders"
+      :limit="1"
+      :on-error="submitFormError"
+      :on-exceed="handleExceed"
+      :on-success="submitFormSuccess"
+      accept=".xlsx, .xls"
+      drag
     >
       <Icon icon="ep:upload" />
       <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
       <template #tip>
         <div class="el-upload__tip text-center">
           <div class="el-upload__tip">
-            <el-checkbox v-model="updateSupport" /> 是否更新已经存在的用户数据
+            <el-checkbox v-model="updateSupport" />
+            是否更新已经存在的用户数据
           </div>
           <span>仅允许导入 xls、xlsx 格式文件。</span>
           <el-link
-            type="primary"
             :underline="false"
             style="font-size: 12px; vertical-align: baseline"
+            type="primary"
             @click="importTemplate"
           >
             下载模板
@@ -34,15 +35,16 @@
       </template>
     </el-upload>
     <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
     </template>
   </Dialog>
 </template>
-<script lang="ts" setup>
+<script lang="ts" name="SystemUserImportForm" setup>
 import * as UserApi from '@/api/system/user'
 import { getAccessToken, getTenantId } from '@/utils/auth'
 import download from '@/utils/download'
+
 const message = useMessage() // 消息弹窗
 
 const dialogVisible = ref(false) // 弹窗的是否展示

From 2bef7f707c6c8f262679398fddb8c88f761a213e Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Fri, 14 Apr 2023 21:46:34 +0800
Subject: [PATCH 02/15] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B2=A1=E5=BF=85?=
 =?UTF-8?q?=E8=A6=81=E7=9A=84lang=3D"tsx"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/views/bpm/task/done/index.vue | 53 ++++++++++++++++-------------
 src/views/bpm/task/todo/index.vue | 55 +++++++++++++++++--------------
 2 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/src/views/bpm/task/done/index.vue b/src/views/bpm/task/done/index.vue
index ae3352d9..42d09c03 100644
--- a/src/views/bpm/task/done/index.vue
+++ b/src/views/bpm/task/done/index.vue
@@ -2,35 +2,41 @@
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form
-      class="-mb-15px"
-      :model="queryParams"
       ref="queryFormRef"
       :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
       label-width="68px"
     >
       <el-form-item label="任务名称" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输入任务名称"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请输入任务名称"
+          @keyup.enter="handleQuery"
         />
       </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
           class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
       </el-form-item>
     </el-form>
   </ContentWrap>
@@ -38,24 +44,24 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list">
-      <el-table-column label="任务编号" align="center" prop="id" width="300px" />
-      <el-table-column label="任务名称" align="center" prop="name" />
-      <el-table-column label="所属流程" align="center" prop="processInstance.name" />
-      <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
-      <el-table-column label="状态" align="center" prop="result">
+      <el-table-column align="center" label="任务编号" prop="id" width="300px" />
+      <el-table-column align="center" label="任务名称" prop="name" />
+      <el-table-column align="center" label="所属流程" prop="processInstance.name" />
+      <el-table-column align="center" label="流程发起人" prop="processInstance.startUserNickname" />
+      <el-table-column align="center" label="状态" prop="result">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.BPM_PROCESS_INSTANCE_RESULT" :value="scope.row.result" />
         </template>
       </el-table-column>
-      <el-table-column label="原因" align="center" prop="reason" />
+      <el-table-column align="center" label="原因" prop="reason" />
       <el-table-column
-        label="创建时间"
+        :formatter="dateFormatter"
         align="center"
+        label="创建时间"
         prop="createTime"
         width="180"
-        :formatter="dateFormatter"
       />
-      <el-table-column label="操作" align="center">
+      <el-table-column align="center" label="操作">
         <template #default="scope">
           <el-button link type="primary" @click="openDetail(scope.row)">详情</el-button>
           <el-button link type="primary" @click="handleAudit(scope.row)">流程</el-button>
@@ -64,9 +70,9 @@
     </el-table>
     <!-- 分页 -->
     <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
       v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
       @pagination="getList"
     />
   </ContentWrap>
@@ -74,11 +80,12 @@
   <!-- 表单弹窗:详情 -->
   <TaskDetail ref="detailRef" @success="getList" />
 </template>
-<script setup lang="tsx" name="BpmTodoTask">
+<script lang="ts" name="BpmTodoTask" setup>
 import { DICT_TYPE } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import * as TaskApi from '@/api/bpm/task'
 import TaskDetail from './TaskDetail.vue'
+
 const { push } = useRouter() // 路由
 
 const loading = ref(true) // 列表的加载中
diff --git a/src/views/bpm/task/todo/index.vue b/src/views/bpm/task/todo/index.vue
index 0bdc3850..ef2976e0 100644
--- a/src/views/bpm/task/todo/index.vue
+++ b/src/views/bpm/task/todo/index.vue
@@ -2,35 +2,41 @@
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form
-      class="-mb-15px"
-      :model="queryParams"
       ref="queryFormRef"
       :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
       label-width="68px"
     >
       <el-form-item label="任务名称" prop="name">
         <el-input
           v-model="queryParams.name"
-          placeholder="请输入任务名称"
-          clearable
-          @keyup.enter="handleQuery"
           class="!w-240px"
+          clearable
+          placeholder="请输入任务名称"
+          @keyup.enter="handleQuery"
         />
       </el-form-item>
       <el-form-item label="创建时间" prop="createTime">
         <el-date-picker
           v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
           :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
           class="!w-240px"
+          end-placeholder="结束日期"
+          start-placeholder="开始日期"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
         />
       </el-form-item>
       <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          搜索
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          重置
+        </el-button>
       </el-form-item>
     </el-form>
   </ContentWrap>
@@ -38,24 +44,24 @@
   <!-- 列表 -->
   <ContentWrap>
     <el-table v-loading="loading" :data="list">
-      <el-table-column label="任务编号" align="center" prop="id" width="300px" />
-      <el-table-column label="任务名称" align="center" prop="name" />
-      <el-table-column label="所属流程" align="center" prop="processInstance.name" />
-      <el-table-column label="流程发起人" align="center" prop="processInstance.startUserNickname" />
+      <el-table-column align="center" label="任务编号" prop="id" width="300px" />
+      <el-table-column align="center" label="任务名称" prop="name" />
+      <el-table-column align="center" label="所属流程" prop="processInstance.name" />
+      <el-table-column align="center" label="流程发起人" prop="processInstance.startUserNickname" />
       <el-table-column
-        label="创建时间"
+        :formatter="dateFormatter"
         align="center"
+        label="创建时间"
         prop="createTime"
         width="180"
-        :formatter="dateFormatter"
       />
       <el-table-column label="任务状态" prop="suspensionState">
         <template #default="scope">
-          <el-tag type="success" v-if="scope.row.suspensionState === 1">激活</el-tag>
-          <el-tag type="warning" v-if="scope.row.suspensionState === 2">挂起</el-tag>
+          <el-tag v-if="scope.row.suspensionState === 1" type="success">激活</el-tag>
+          <el-tag v-if="scope.row.suspensionState === 2" type="warning">挂起</el-tag>
         </template>
       </el-table-column>
-      <el-table-column label="操作" align="center">
+      <el-table-column align="center" label="操作">
         <template #default="scope">
           <el-button link type="primary" @click="handleAudit(scope.row)">审批进度</el-button>
         </template>
@@ -63,19 +69,20 @@
     </el-table>
     <!-- 分页 -->
     <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
       v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
       @pagination="getList"
     />
   </ContentWrap>
 </template>
 
-<script setup lang="tsx" name="BpmDoneTask">
+<script lang="ts" name="BpmDoneTask" setup>
 import { dateFormatter } from '@/utils/formatTime'
-const { push } = useRouter() // 路由
 import * as TaskApi from '@/api/bpm/task'
 
+const { push } = useRouter() // 路由
+
 const loading = ref(true) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据

From d62e607292a2bd12eafe5ad97fafcc726c99a019 Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Fri, 14 Apr 2023 21:47:58 +0800
Subject: [PATCH 03/15] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=BB=91=E5=AE=9A?=
 =?UTF-8?q?=E7=AC=AC=E4=B8=89=E6=96=B9=E8=B7=B3=E8=BD=AC=E6=89=AB=E7=A0=81?=
 =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/views/Profile/components/UserSocial.vue | 43 ++++++++++++++++-----
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/views/Profile/components/UserSocial.vue b/src/views/Profile/components/UserSocial.vue
index da88d993..5d1664ea 100644
--- a/src/views/Profile/components/UserSocial.vue
+++ b/src/views/Profile/components/UserSocial.vue
@@ -1,30 +1,30 @@
 <template>
   <el-table :data="socialUsers" :show-header="false">
-    <el-table-column type="seq" title="序号" width="60" fixed="left" />
-    <el-table-column label="社交平台" align="left" width="120">
+    <el-table-column fixed="left" title="序号" type="seq" width="60" />
+    <el-table-column align="left" label="社交平台" width="120">
       <template #default="{ row }">
-        <img class="h-5 align-middle" :src="row.img" alt="" />
+        <img :src="row.img" alt="" class="h-5 align-middle" />
         <p class="mr-5">{{ row.title }}</p>
       </template>
     </el-table-column>
-    <el-table-column label="操作" align="center">
+    <el-table-column align="center" label="操作">
       <template #default="{ row }">
         <template v-if="row.openid">
           已绑定
-          <XTextButton type="primary" class="mr-5" @click="unbind(row)" title="(解绑)" />
+          <XTextButton class="mr-5" title="(解绑)" type="primary" @click="unbind(row)" />
         </template>
         <template v-else>
           未绑定
-          <XTextButton type="primary" class="mr-5" @click="bind(row)" title="(绑定)" />
+          <XTextButton class="mr-5" title="(绑定)" type="primary" @click="bind(row)" />
         </template>
       </template>
     </el-table-column>
   </el-table>
 </template>
-<script setup lang="ts">
+<script lang="ts" name="UserSocial" setup>
 import { SystemUserSocialTypeEnum } from '@/utils/constants'
 import { getUserProfile, ProfileVO } from '@/api/system/user/profile'
-import { socialAuthRedirect, socialUnbind } from '@/api/system/user/socialUser'
+import { socialAuthRedirect, socialBind, socialUnbind } from '@/api/system/user/socialUser'
 
 const message = useMessage()
 const socialUsers = ref<any[]>([])
@@ -46,11 +46,25 @@ const initSocial = async () => {
     }
   }
 }
+const route = useRoute()
+const bindSocial = () => {
+  // 社交绑定
+  const type = route.query.type
+  const code = route.query.code
+  const state = route.query.state
+  if (!code) {
+    return
+  }
+  socialBind(type, code, state).then(() => {
+    message.success('绑定成功')
+    initSocial()
+  })
+}
 const bind = (row) => {
   const redirectUri = location.origin + '/user/profile?type=' + row.type
   // 进行跳转
   socialAuthRedirect(row.type, encodeURIComponent(redirectUri)).then((res) => {
-    window.location.href = res.data
+    window.location.href = res
   })
 }
 const unbind = async (row) => {
@@ -64,4 +78,15 @@ const unbind = async (row) => {
 onMounted(async () => {
   await initSocial()
 })
+
+watch(
+  () => route,
+  (newRoute) => {
+    bindSocial()
+    console.log(newRoute)
+  },
+  {
+    immediate: true
+  }
+)
 </script>

From 7564c43f16167a93f477085d30be958e17c3c628 Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Fri, 14 Apr 2023 22:06:27 +0800
Subject: [PATCH 04/15] =?UTF-8?q?=E6=94=B9editor=E4=B8=BAeditor=5F?=
 =?UTF-8?q?=E4=B8=80=E7=82=B9=E5=B0=8F=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../mp/components/wx-editor/WxEditor.vue      | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/views/mp/components/wx-editor/WxEditor.vue b/src/views/mp/components/wx-editor/WxEditor.vue
index 882924c0..7f42c5ee 100644
--- a/src/views/mp/components/wx-editor/WxEditor.vue
+++ b/src/views/mp/components/wx-editor/WxEditor.vue
@@ -1,5 +1,5 @@
 <script name="WxEditor" setup>
-import { ref, reactive } from 'vue'
+import { reactive, ref } from 'vue'
 import { getAccessToken } from '@/utils/auth'
 import { Editor } from '@/components/Editor'
 
@@ -83,21 +83,21 @@ const uploadError = () => {
     <div v-loading="loading" element-loading-text="请稍等,图片上传中">
       <!-- 图片上传组件辅助-->
       <el-upload
+        :action="actionUrl"
+        :before-upload="beforeUpload"
+        :data="uploadData"
+        :headers="headers"
+        :on-error="uploadError"
+        :on-success="uploadSuccess"
+        :show-file-list="false"
         class="avatar-uploader"
         name="file"
-        :action="actionUrl"
-        :headers="headers"
-        :show-file-list="false"
-        :data="uploadData"
-        :on-success="uploadSuccess"
-        :on-error="uploadError"
-        :before-upload="beforeUpload"
       />
       <Editor
-        editor-id="wxEditor"
         ref="quillEditorRef"
         :modelValue="content"
-        @change="(editor) => onEditorChange(editor.getText())"
+        editor-id="wxEditor"
+        @change="(editor_) => onEditorChange(editor_.getText())"
       />
     </div>
   </div>

From b26bba9939eac1d386f68706934ed5ae3944989c Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Fri, 14 Apr 2023 22:40:05 +0800
Subject: [PATCH 05/15] =?UTF-8?q?=E7=A7=BB=E9=99=A4vex=20hooks=E8=87=AA?=
 =?UTF-8?q?=E5=8A=A8=E5=AF=BC=E5=85=A5=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=89=93?=
 =?UTF-8?q?=E5=8C=85=E6=8A=A5=E9=94=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 build/vite/index.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build/vite/index.ts b/build/vite/index.ts
index 288ec93b..574a0d61 100644
--- a/build/vite/index.ts
+++ b/build/vite/index.ts
@@ -19,10 +19,12 @@ import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
 
 export function createVitePlugins() {
   const root = process.cwd()
+
   // 路径查找
   function pathResolve(dir: string) {
     return resolve(root, '.', dir)
   }
+
   return [
     Vue(),
     VueJsx(),
@@ -45,8 +47,6 @@ export function createVitePlugins() {
         {
           '@/hooks/web/useI18n': ['useI18n'],
           '@/hooks/web/useMessage': ['useMessage'],
-          '@/hooks/web/useXTable': ['useXTable'],
-          '@/hooks/web/useVxeCrudSchemas': ['useVxeCrudSchemas'],
           '@/hooks/web/useTable': ['useTable'],
           '@/hooks/web/useCrudSchemas': ['useCrudSchemas'],
           '@/utils/formRules': ['required'],

From 18742b8cc70b365c8b089d6d86a74452b724a01b Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 09:13:25 +0800
Subject: [PATCH 06/15] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20css=20=E7=9A=84?=
 =?UTF-8?q?=E5=BC=95=E5=85=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/main.ts               |  7 -------
 src/styles/index.scss     |  1 -
 src/styles/variables.scss |  2 --
 src/styles/vxe.css        | 30 ------------------------------
 src/utils/env.ts          |  8 --------
 5 files changed, 48 deletions(-)
 delete mode 100644 src/styles/vxe.css
 delete mode 100644 src/utils/env.ts

diff --git a/src/main.ts b/src/main.ts
index 8dd1fff0..0fc15c2c 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -37,8 +37,6 @@ import App from './App.vue'
 
 import './permission'
 
-import { isDevMode } from '@/utils/env'
-
 import { MyPD } from '@/components/bpmnProcessDesigner/package/index.js'
 import '@/components/bpmnProcessDesigner/package/theme/index.scss'
 import 'bpmn-js/dist/assets/diagram-js.css'
@@ -53,11 +51,6 @@ import '@/plugins/tongji' // 百度统计
 
 import Logger from '@/utils/Logger'
 
-// 本地开发模式 全局引入 element-plus 样式,加快第一次进入速度
-if (isDevMode()) {
-  import('element-plus/dist/index.css')
-}
-
 // 创建实例
 const setupAll = async () => {
   const app = createApp(App)
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 39c4c4da..2781c12e 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -1,5 +1,4 @@
 @import './var.css';
-@import './vxe.css';
 @import 'element-plus/theme-chalk/dark/css-vars.css';
 
 .reset-margin [class*='el-icon'] + span {
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
index ffa78c9f..00b66f1f 100644
--- a/src/styles/variables.scss
+++ b/src/styles/variables.scss
@@ -2,5 +2,3 @@
 $namespace: v;
 // el命名空间
 $elNamespace: el;
-// vxe命名空间
-$vxeNamespace: vxe;
diff --git a/src/styles/vxe.css b/src/styles/vxe.css
deleted file mode 100644
index 30bdd58d..00000000
--- a/src/styles/vxe.css
+++ /dev/null
@@ -1,30 +0,0 @@
-/*滚动条整体部分*/
-.xtable-scrollbar ::-webkit-scrollbar {
-  width: 10px;
-  height: 10px;
-}
-/*滚动条的轨道*/
-.xtable-scrollbar ::-webkit-scrollbar-track {
-  background-color: #ffffff;
-}
-/*滚动条里面的小方块,能向上向下移动*/
-.xtable-scrollbar ::-webkit-scrollbar-thumb {
-  background-color: #bfbfbf;
-  border-radius: 5px;
-  border: 1px solid #f1f1f1;
-  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
-}
-.xtable-scrollbar ::-webkit-scrollbar-thumb:hover {
-  background-color: #a8a8a8;
-}
-.xtable-scrollbar ::-webkit-scrollbar-thumb:active {
-  background-color: #787878;
-}
-/*边角,即两个滚动条的交汇处*/
-.xtable-scrollbar ::-webkit-scrollbar-corner {
-  background-color: #ffffff;
-}
-/*移除 vxe-grid 右侧外框*/
-.vxe-button.size--medium.type--button.is--circle {
-  border: 0;
-}
diff --git a/src/utils/env.ts b/src/utils/env.ts
deleted file mode 100644
index ea271813..00000000
--- a/src/utils/env.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export const isDevMode = () => {
-  const dev = import.meta.env.VITE_DEV
-  if (dev && dev === 'true') {
-    return true
-  } else {
-    return false
-  }
-}

From 168f751a24a124e181e1fcc61a432082fbd862d8 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 09:19:37 +0800
Subject: [PATCH 07/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Vue3=20=E7=AE=A1?=
 =?UTF-8?q?=E7=90=86=E5=90=8E=E5=8F=B0=E6=96=B0=E5=A2=9E=E7=A7=9F=E6=88=B7?=
 =?UTF-8?q?=E6=97=B6=EF=BC=8C=E6=9C=AA=E6=A0=A1=E9=AA=8C=E8=B4=A6=E5=8F=B7?=
 =?UTF-8?q?=E3=80=81=E5=AF=86=E7=A0=81=E6=98=AF=E5=90=A6=E4=B8=BA=E7=A9=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/views/system/tenant/TenantForm.vue | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/views/system/tenant/TenantForm.vue b/src/views/system/tenant/TenantForm.vue
index ec19b487..5af895e7 100644
--- a/src/views/system/tenant/TenantForm.vue
+++ b/src/views/system/tenant/TenantForm.vue
@@ -105,7 +105,9 @@ const formRules = reactive({
   status: [{ required: true, message: '租户状态不能为空', trigger: 'blur' }],
   accountCount: [{ required: true, message: '账号额度不能为空', trigger: 'blur' }],
   expireTime: [{ required: true, message: '过期时间不能为空', trigger: 'blur' }],
-  domain: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }]
+  domain: [{ required: true, message: '绑定域名不能为空', trigger: 'blur' }],
+  username: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
+  password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }]
 })
 const formRef = ref() // 表单 Ref
 const packageList = ref([]) // 租户套餐

From de5b1216cd147efcaf7e310eca2fb06053592af8 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 10:28:23 +0800
Subject: [PATCH 08/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AD=97=E5=85=B8?=
 =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=92=8C=E7=B1=BB=E5=9E=8B=E7=9A=84=20status?=
 =?UTF-8?q?=20=E6=9C=AA=E6=A0=A1=E9=AA=8C=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/system/dict/DictTypeForm.vue      | 3 ++-
 src/views/system/dict/data/DictDataForm.vue | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/views/system/dict/DictTypeForm.vue b/src/views/system/dict/DictTypeForm.vue
index bb0deb17..8cfc1b57 100644
--- a/src/views/system/dict/DictTypeForm.vue
+++ b/src/views/system/dict/DictTypeForm.vue
@@ -58,7 +58,8 @@ const formData = ref({
 })
 const formRules = reactive({
   name: [{ required: true, message: '字典名称不能为空', trigger: 'blur' }],
-  type: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }]
+  type: [{ required: true, message: '字典类型不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
 })
 const formRef = ref() // 表单 Ref
 
diff --git a/src/views/system/dict/data/DictDataForm.vue b/src/views/system/dict/data/DictDataForm.vue
index dc2f6057..337ee348 100644
--- a/src/views/system/dict/data/DictDataForm.vue
+++ b/src/views/system/dict/data/DictDataForm.vue
@@ -82,7 +82,8 @@ const formData = ref({
 const formRules = reactive({
   label: [{ required: true, message: '数据标签不能为空', trigger: 'blur' }],
   value: [{ required: true, message: '数据键值不能为空', trigger: 'blur' }],
-  sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }]
+  sort: [{ required: true, message: '数据顺序不能为空', trigger: 'blur' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
 })
 const formRef = ref() // 表单 Ref
 

From 776eb3a7b0c619ec3b3b1ef3aece36d95781c96c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=92=B1=E5=93=A5=E4=B8=B6?= <385454831@qq.com>
Date: Sat, 15 Apr 2023 12:25:11 +0800
Subject: [PATCH 09/15] =?UTF-8?q?=E9=87=8D=E6=9E=84VUE3=E3=80=90=E7=AB=99?=
 =?UTF-8?q?=E5=86=85=E4=BF=A1-=E6=A8=A1=E6=9D=BF=E7=AE=A1=E7=90=86?=
 =?UTF-8?q?=E3=80=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/system/notify/template/index.ts       |   9 +-
 .../notify/template/NotifyTemplateForm.vue    | 140 ++++++
 src/views/system/notify/template/index.vue    | 446 ++++++++++--------
 .../system/notify/template/template.data.ts   |  85 ----
 4 files changed, 407 insertions(+), 273 deletions(-)
 create mode 100644 src/views/system/notify/template/NotifyTemplateForm.vue
 delete mode 100644 src/views/system/notify/template/template.data.ts

diff --git a/src/api/system/notify/template/index.ts b/src/api/system/notify/template/index.ts
index 66530a90..f2bf5d27 100644
--- a/src/api/system/notify/template/index.ts
+++ b/src/api/system/notify/template/index.ts
@@ -1,13 +1,14 @@
 import request from '@/config/axios'
 
 export interface NotifyTemplateVO {
-  id: number
+  id: number | null
   name: string
+  nickname: string
   code: string
   content: string
-  type: number
+  type: number | null
   params: string
-  status: number
+  status: number | null
   remark: string
 }
 
@@ -19,7 +20,7 @@ export interface NotifyTemplatePageReqVO extends PageParam {
 }
 
 export interface NotifySendReqVO {
-  userId: number
+  userId: number | null
   templateCode: string
   templateParams: Map<String, Object>
 }
diff --git a/src/views/system/notify/template/NotifyTemplateForm.vue b/src/views/system/notify/template/NotifyTemplateForm.vue
new file mode 100644
index 00000000..d600a59c
--- /dev/null
+++ b/src/views/system/notify/template/NotifyTemplateForm.vue
@@ -0,0 +1,140 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="140px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="模版编码" prop="code">
+        <el-input v-model="formData.code" placeholder="请输入模版编码" />
+      </el-form-item>
+      <el-form-item label="模板名称" prop="name">
+        <el-input v-model="formData.name" placeholder="请输入模版名称" />
+      </el-form-item>
+      <el-form-item label="发件人名称" prop="nickname">
+        <el-input v-model="formData.nickname" placeholder="请输入发件人名称" />
+      </el-form-item>
+      <el-form-item label="模板内容" prop="content">
+        <el-input type="textarea" v-model="formData.content" placeholder="请输入模板内容" />
+      </el-form-item>
+      <el-form-item label="类型" prop="type">
+        <el-select v-model="formData.type" placeholder="请选择类型">
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="开启状态" prop="status">
+        <el-radio-group v-model="formData.status">
+          <el-radio
+            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
+            :key="dict.value"
+            :label="parseInt(dict.value as string)"
+          >
+            {{ dict.label }}
+          </el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" placeholder="请输入备注" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import * as NotifyTemplateApi from '@/api/system/notify/template'
+import { CommonStatusEnum } from '@/utils/constants'
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型
+const formData = ref<NotifyTemplateApi.NotifyTemplateVO>({
+  id: null,
+  name: '',
+  nickname: '',
+  code: '',
+  content: '',
+  type: null,
+  params: '',
+  status: CommonStatusEnum.ENABLE,
+  remark: ''
+})
+const formRules = reactive({
+  type: [{ required: true, message: '消息类型不能为空', trigger: 'change' }],
+  status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }],
+  code: [{ required: true, message: '模板编码不能为空', trigger: 'blur' }],
+  name: [{ required: true, message: '模板名称不能为空', trigger: 'blur' }],
+  nickname: [{ required: true, message: '发件人姓名不能为空', trigger: 'blur' }],
+  content: [{ required: true, message: '模板内容不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = type
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await NotifyTemplateApi.getNotifyTemplateApi(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  formLoading.value = true
+  try {
+    const data = formData.value as NotifyTemplateApi.NotifyTemplateVO
+    if (formType.value === 'create') {
+      await NotifyTemplateApi.createNotifyTemplateApi(data)
+      message.success('新增成功')
+    } else {
+      await NotifyTemplateApi.updateNotifyTemplateApi(data)
+      message.success('修改成功')
+    }
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: null,
+    name: '',
+    nickname: '',
+    code: '',
+    content: '',
+    type: null,
+    params: '',
+    status: CommonStatusEnum.ENABLE,
+    remark: ''
+  }
+  formRef.value?.resetFields()
+}
+</script>
diff --git a/src/views/system/notify/template/index.vue b/src/views/system/notify/template/index.vue
index 45c1be6d..9d37befb 100644
--- a/src/views/system/notify/template/index.vue
+++ b/src/views/system/notify/template/index.vue
@@ -1,87 +1,169 @@
 <template>
+  <doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" />
+
   <ContentWrap>
-    <!-- 列表 -->
-    <XTable @register="registerTable">
-      <template #toolbar_buttons>
-        <!-- 操作:新增 -->
-        <XButton
+    <!-- 搜索工作栏 -->
+    <el-form
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
+    >
+      <el-form-item label="模板名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入模板名称"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="模板编号" prop="code">
+        <el-input
+          v-model="queryParams.code"
+          placeholder="请输入模版编码"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择开启状态"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
           type="primary"
-          preIcon="ep:zoom-in"
-          :title="t('action.add')"
+          plain
+          @click="openForm('create')"
           v-hasPermi="['system:notify-template:create']"
-          @click="handleCreate()"
-        />
-      </template>
-      <template #actionbtns_default="{ row }">
-        <!-- 操作:测试站内信 -->
-        <XTextButton
-          preIcon="ep:cpu"
-          :title="t('action.test')"
-          v-hasPermi="['system:notify-template:send-notify']"
-          @click="handleSendNotify(row)"
-        />
-        <!-- 操作:修改 -->
-        <XTextButton
-          preIcon="ep:edit"
-          :title="t('action.edit')"
-          v-hasPermi="['system:notify-template:update']"
-          @click="handleUpdate(row.id)"
-        />
-        <!-- 操作:详情 -->
-        <XTextButton
-          preIcon="ep:view"
-          :title="t('action.detail')"
-          v-hasPermi="['system:notify-template:query']"
-          @click="handleDetail(row.id)"
-        />
-        <!-- 操作:删除 -->
-        <XTextButton
-          preIcon="ep:delete"
-          :title="t('action.del')"
-          v-hasPermi="['system:notify-template:delete']"
-          @click="deleteData(row.id)"
-        />
-      </template>
-    </XTable>
+        >
+          <Icon icon="ep:plus" class="mr-5px" />新增
+        </el-button>
+      </el-form-item>
+    </el-form>
   </ContentWrap>
 
-  <!-- 添加/修改的弹窗 -->
-  <Dialog id="templateModel" :loading="modelLoading" v-model="dialogVisible" :title="dialogTitle">
-    <!-- 表单:添加/修改 -->
-    <Form
-      ref="formRef"
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-    />
-    <!-- 表单:详情 -->
-    <Descriptions
-      v-if="actionType === 'detail'"
-      :schema="allSchemas.detailSchema"
-      :data="detailData"
-    />
-    <template #footer>
-      <!-- 按钮:保存 -->
-      <XButton
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :title="t('action.save')"
-        :loading="actionLoading"
-        @click="submitForm()"
+  <!-- 列表 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column
+        label="模板编码"
+        align="center"
+        prop="code"
+        width="120"
+        :show-overflow-tooltip="true"
+      />
+      <el-table-column
+        label="模板名称"
+        align="center"
+        prop="name"
+        width="120"
+        :show-overflow-tooltip="true"
+      />
+      <el-table-column label="类型" align="center" prop="type">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.type" />
+        </template>
+      </el-table-column>
+      <el-table-column label="发送人名称" align="center" prop="nickname" />
+      <el-table-column
+        label="模板内容"
+        align="center"
+        prop="content"
+        width="200"
+        :show-overflow-tooltip="true"
       />
-      <!-- 按钮:关闭 -->
-      <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
-    </template>
-  </Dialog>
 
-  <!-- 测试站内信的弹窗 -->
-  <Dialog id="sendTest" v-model="sendVisible" title="测试">
-    <el-form :model="sendForm" :rules="sendRules" label-width="200px" label-position="top">
+      <el-table-column label="开启状态" align="center" prop="status" width="80">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        width="180"
+        :formatter="dateFormatter"
+      />
+      <el-table-column label="操作" align="center" width="210" fixed="right">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openForm('update', scope.row.id)"
+            v-hasPermi="['system:notify-template:update']"
+          >
+            修改
+          </el-button>
+          <el-button
+            link
+            type="primary"
+            @click="openSendForm(scope.row)"
+            v-hasPermi="['system:notify-template:send-notify']"
+          >
+            测试
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['system:notify-template:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <Dialog v-model="dialogFormVisible" title="测试发送" :max-height="500">
+    <el-form
+      ref="sendFormRef"
+      :model="sendFormData"
+      :rules="sendFormRules"
+      label-width="140px"
+      v-loading="formLoading"
+    >
       <el-form-item label="模板内容" prop="content">
-        <el-input type="textarea" v-model="sendForm.content" readonly />
+        <el-input v-model="sendFormData.content" readonly />
       </el-form-item>
       <el-form-item label="接收人" prop="userId">
-        <el-select v-model="sendForm.userId" placeholder="请选择接收人">
+        <el-select v-model="sendFormData.userId" placeholder="请选择接收人">
           <el-option
             v-for="item in userOption"
             :key="item.id"
@@ -91,159 +173,155 @@
         </el-select>
       </el-form-item>
       <el-form-item
-        v-for="param in sendForm.params"
+        v-for="param in sendFormData.params"
         :key="param"
         :label="'参数 {' + param + '}'"
         :prop="'templateParams.' + param"
       >
         <el-input
-          v-model="sendForm.templateParams[param]"
+          v-model="sendFormData.templateParams[param]"
           :placeholder="'请输入 ' + param + ' 参数'"
         />
       </el-form-item>
     </el-form>
-    <!-- 操作按钮 -->
     <template #footer>
-      <XButton
-        type="primary"
-        :title="t('action.test')"
-        :loading="actionLoading"
-        @click="sendTest()"
-      />
-      <XButton :title="t('dialog.close')" @click="sendVisible = false" />
+      <span class="dialog-footer">
+        <el-button @click="dialogFormVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm"> 确定 </el-button>
+      </span>
     </template>
   </Dialog>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <NotifyTemplateForm ref="formRef" @success="getList" />
 </template>
-<script setup lang="ts" name="SystemNotifyTemplate">
-import { FormExpose } from '@/components/Form'
-// 业务相关的 import
-import { rules, allSchemas } from './template.data'
+<script setup lang="ts" name="NotifySmsTemplate">
+import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
 import * as NotifyTemplateApi from '@/api/system/notify/template'
 import { getSimpleUserList, UserVO } from '@/api/system/user'
+import NotifyTemplateForm from './NotifyTemplateForm.vue'
 
-const { t } = useI18n() // 国际化
 const message = useMessage() // 消息弹窗
 
-// 列表相关的变量
-const [registerTable, { reload, deleteData }] = useXTable({
-  allSchemas: allSchemas,
-  getListApi: NotifyTemplateApi.getNotifyTemplatePageApi,
-  deleteApi: NotifyTemplateApi.deleteNotifyTemplateApi
+const loading = ref(false) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+const queryFormRef = ref() // 搜索的表单
+
+const formLoading = ref(false)
+const dialogFormVisible = ref(false)
+const sendFormRef = ref() // 表单 Ref
+const queryParams = reactive({
+  pageNo: 1,
+  pageSize: 10,
+  name: undefined,
+  status: undefined,
+  code: undefined,
+  createTime: []
 })
 
-// 弹窗相关的变量
-const dialogVisible = ref(false) // 是否显示弹出层
-const dialogTitle = ref('edit') // 弹出层标题
-const modelLoading = ref(false) // 弹出层loading
-const actionType = ref('') // 操作按钮的类型
-const actionLoading = ref(false) // 按钮 Loading
-const formRef = ref<FormExpose>() // 表单 Ref
-const detailData = ref() // 详情 Ref
-
-// 设置标题
-const setDialogTile = (type: string) => {
-  modelLoading.value = true
-  dialogTitle.value = t('action.' + type)
-  actionType.value = type
-  dialogVisible.value = true
-}
-
-// 新增操作
-const handleCreate = () => {
-  setDialogTile('create')
-  modelLoading.value = false
-}
-
-// 修改操作
-const handleUpdate = async (rowId: number) => {
-  setDialogTile('update')
-  // 设置数据
-  const res = await NotifyTemplateApi.getNotifyTemplateApi(rowId)
-  unref(formRef)?.setValues(res)
-  modelLoading.value = false
-}
-
-// 详情操作
-const handleDetail = async (rowId: number) => {
-  setDialogTile('detail')
-  const res = await NotifyTemplateApi.getNotifyTemplateApi(rowId)
-  detailData.value = res
-  modelLoading.value = false
-}
-
-// 提交按钮
-const submitForm = async () => {
-  const elForm = unref(formRef)?.getElFormRef()
-  if (!elForm) return
-  elForm.validate(async (valid) => {
-    if (valid) {
-      actionLoading.value = true
-      // 提交请求
-      try {
-        const data = unref(formRef)?.formModel as NotifyTemplateApi.NotifyTemplateVO
-        if (actionType.value === 'create') {
-          await NotifyTemplateApi.createNotifyTemplateApi(data)
-          message.success(t('common.createSuccess'))
-        } else {
-          await NotifyTemplateApi.updateNotifyTemplateApi(data)
-          message.success(t('common.updateSuccess'))
-        }
-        dialogVisible.value = false
-      } finally {
-        actionLoading.value = false
-        // 刷新列表
-        await reload()
-      }
-    }
-  })
-}
-
-// ========== 测试相关 ==========
-const sendForm = ref({
+const sendFormData = ref({
   content: '',
   params: {},
-  userId: 0,
+  userId: null,
   templateCode: '',
   templateParams: {}
 })
-const sendRules = ref({
-  userId: [{ required: true, message: '用户编号不能为空', trigger: 'blur' }],
+
+const sendFormRules = ref({
+  userId: [{ required: true, message: '用户编号不能为空', trigger: 'change' }],
   templateCode: [{ required: true, message: '模版编号不能为空', trigger: 'blur' }],
   templateParams: {}
 })
-const sendVisible = ref(false)
+
 const userOption = ref<UserVO[]>([])
 
-const handleSendNotify = (row: any) => {
-  sendForm.value.content = row.content
-  sendForm.value.params = row.params
-  sendForm.value.templateCode = row.code
-  sendForm.value.templateParams = row.params.reduce(function (obj, item) {
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await NotifyTemplateApi.getNotifyTemplatePageApi(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
+
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
+
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await NotifyTemplateApi.deleteNotifyTemplateApi(id)
+    message.success('删除成功')
+    // 刷新列表
+    await getList()
+  } catch {}
+}
+
+const openSendForm = (row: any) => {
+  sendFormData.value.content = row.content
+  sendFormData.value.params = row.params
+  sendFormData.value.templateCode = row.code
+  sendFormData.value.templateParams = row.params.reduce(function (obj, item) {
     obj[item] = undefined
     return obj
   }, {})
-  sendRules.value.templateParams = row.params.reduce(function (obj, item) {
+  sendFormRules.value.templateParams = row.params.reduce(function (obj, item) {
     obj[item] = { required: true, message: '参数 ' + item + ' 不能为空', trigger: 'change' }
     return obj
   }, {})
-  sendVisible.value = true
+  dialogFormVisible.value = true
 }
 
-const sendTest = async () => {
-  const data: NotifyTemplateApi.NotifySendReqVO = {
-    userId: sendForm.value.userId,
-    templateCode: sendForm.value.templateCode,
-    templateParams: sendForm.value.templateParams as unknown as Map<string, Object>
+/** 提交表单 */
+const submitForm = async () => {
+  // 校验表单
+  if (!sendFormRef) return
+  const valid = await sendFormRef.value.validate()
+  if (!valid) return
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data: NotifyTemplateApi.NotifySendReqVO = {
+      userId: sendFormData.value.userId,
+      templateCode: sendFormData.value.templateCode,
+      templateParams: sendFormData.value.templateParams as unknown as Map<string, Object>
+    }
+    const res = await NotifyTemplateApi.sendNotifyApi(data)
+    if (res) {
+      message.success('提交发送成功!发送结果,见消息记录编号:' + res)
+    }
+    dialogFormVisible.value = false
+  } finally {
+    formLoading.value = false
   }
-  const res = await NotifyTemplateApi.sendNotifyApi(data)
-  if (res) {
-    message.success('提交发送成功!发送结果,见发送日志编号:' + res)
-  }
-  sendVisible.value = false
 }
 
-// ========== 初始化 ==========
+/** 初始化 **/
 onMounted(() => {
+  getList()
   getSimpleUserList().then((data) => {
     userOption.value = data
   })
diff --git a/src/views/system/notify/template/template.data.ts b/src/views/system/notify/template/template.data.ts
deleted file mode 100644
index ae8c7b07..00000000
--- a/src/views/system/notify/template/template.data.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
-
-// 表单校验
-export const rules = reactive({
-  name: [required],
-  code: [required],
-  content: [required],
-  type: [required],
-  status: [required]
-})
-
-// CrudSchema
-const crudSchemas = reactive<VxeCrudSchema>({
-  primaryKey: 'id',
-  primaryTitle: '编号',
-  primaryType: null,
-  action: true,
-  actionWidth: '260', // 3个按钮默认200,如有删减对应增减即可
-  columns: [
-    {
-      title: '模版编码',
-      field: 'code',
-      isSearch: true
-    },
-    {
-      title: '模板名称',
-      field: 'name',
-      isSearch: true
-    },
-    {
-      title: '发件人名称',
-      field: 'nickname'
-    },
-    {
-      title: '类型',
-      field: 'type',
-      dictType: DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE,
-      dictClass: 'number'
-    },
-    {
-      title: '模版内容',
-      field: 'content',
-      table: {
-        width: 300
-      },
-      form: {
-        component: 'Input',
-        componentProps: {
-          type: 'textarea',
-          rows: 4
-        },
-        colProps: {
-          span: 24
-        }
-      }
-    },
-    {
-      title: '状态',
-      field: 'status',
-      dictType: DICT_TYPE.COMMON_STATUS,
-      dictClass: 'number',
-      isSearch: true
-    },
-    {
-      title: '备注',
-      field: 'remark'
-    },
-    {
-      title: '创建时间',
-      field: 'createTime',
-      isForm: false,
-      formatter: 'formatDate',
-      search: {
-        show: true,
-        itemRender: {
-          name: 'XDataTimePicker'
-        }
-      },
-      table: {
-        width: 180
-      }
-    }
-  ]
-})
-export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

From 5910d53d8f42e565c3a5e14dc1048ad7063e9d95 Mon Sep 17 00:00:00 2001
From: puhui999 <puhui999@163.com>
Date: Sat, 15 Apr 2023 13:43:38 +0800
Subject: [PATCH 10/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=AE=E5=BC=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .gitignore           | 2 +-
 src/types/.gitignore | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)
 delete mode 100644 src/types/.gitignore

diff --git a/.gitignore b/.gitignore
index ac15926b..0f033cc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,6 @@ dist-ssr
 /dist*
 *-lock.*
 pnpm-debug
-
+auto-*.d.ts
 .idea
 .history
diff --git a/src/types/.gitignore b/src/types/.gitignore
deleted file mode 100644
index a00fe5dd..00000000
--- a/src/types/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-auto-*.d.ts

From 389c73d834ad710c1398581314cb96787078b954 Mon Sep 17 00:00:00 2001
From: dhb52 <dhb52@126.com>
Date: Sat, 15 Apr 2023 15:59:33 +0800
Subject: [PATCH 11/15] =?UTF-8?q?refactor:=20MP=E6=B6=88=E6=81=AF=E7=AE=A1?=
 =?UTF-8?q?=E7=90=86-=E6=8B=86=E5=88=86=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/views/mp/material/components/Upload.vue   |  70 +++
 .../mp/material/components/UploadVideo.vue    | 127 ++++++
 .../mp/material/components/VideoTable.vue     |  61 +++
 .../mp/material/components/VoiceTable.vue     |  53 +++
 .../mp/material/components/Waterfall.vue      |  83 ++++
 src/views/mp/material/components/upload.ts    |  73 +++
 src/views/mp/material/index.vue               | 424 ++----------------
 7 files changed, 507 insertions(+), 384 deletions(-)
 create mode 100644 src/views/mp/material/components/Upload.vue
 create mode 100644 src/views/mp/material/components/UploadVideo.vue
 create mode 100644 src/views/mp/material/components/VideoTable.vue
 create mode 100644 src/views/mp/material/components/VoiceTable.vue
 create mode 100644 src/views/mp/material/components/Waterfall.vue
 create mode 100644 src/views/mp/material/components/upload.ts

diff --git a/src/views/mp/material/components/Upload.vue b/src/views/mp/material/components/Upload.vue
new file mode 100644
index 00000000..541dbc20
--- /dev/null
+++ b/src/views/mp/material/components/Upload.vue
@@ -0,0 +1,70 @@
+<template>
+  <el-upload
+    :action="UPLOAD_URL"
+    :headers="HEADERS"
+    multiple
+    :limit="1"
+    :file-list="fileList"
+    :data="uploadData"
+    :on-progress="() => (uploading = true)"
+    :before-upload="beforeUpload"
+    :on-success="handleUploadSuccess"
+  >
+    <el-button type="primary" plain :loading="uploading" :disabled="uploading">
+      {{ uploading ? '正在上传' : '点击上传' }}
+    </el-button>
+    <template #tip>
+      <span class="el-upload__tip" style="margin-left: 5px">
+        <slot></slot>
+      </span>
+    </template>
+  </el-upload>
+</template>
+
+<script setup lang="ts">
+import type { UploadProps, UploadUserFile } from 'element-plus'
+import {
+  HEADERS,
+  UPLOAD_URL,
+  UploadData,
+  MaterialType,
+  beforeImageUpload,
+  beforeVoiceUpload
+} from './upload'
+
+const message = useMessage()
+
+const props = defineProps<{ type: boolean }>()
+
+const fileList = ref<UploadUserFile[]>([])
+const emit = defineEmits<{
+  (e: 'uploaded', v: void)
+}>()
+
+const uploadData: UploadData = reactive({
+  type: MaterialType.Image,
+  title: '',
+  introduction: ''
+})
+const uploading = ref(false)
+
+const beforeUpload = props.type == MaterialType.Image ? beforeImageUpload : beforeVoiceUpload
+
+const handleUploadSuccess: UploadProps['onSuccess'] = (res: any) => {
+  if (res.code !== 0) {
+    message.alertError('上传出错:' + res.msg)
+    return false
+  }
+
+  // 清空上传时的各种数据
+  fileList.value = []
+  uploadData.title = ''
+  uploadData.introduction = ''
+
+  message.notifySuccess('上传成功')
+  uploading.value = false
+  emit('uploaded')
+}
+</script>
+
+<style scoped></style>
diff --git a/src/views/mp/material/components/UploadVideo.vue b/src/views/mp/material/components/UploadVideo.vue
new file mode 100644
index 00000000..5da7d980
--- /dev/null
+++ b/src/views/mp/material/components/UploadVideo.vue
@@ -0,0 +1,127 @@
+<template>
+  <el-dialog title="新建视频" v-model="showDialog" width="600px" destroy-on-close>
+    <el-upload
+      :action="UPLOAD_URL"
+      :headers="HEADERS"
+      multiple
+      :limit="1"
+      :file-list="fileList"
+      :data="uploadData"
+      :before-upload="beforeVideoUpload"
+      :on-progress="() => (uploading = true)"
+      :on-success="handleUploadSuccess"
+      ref="uploadVideoRef"
+      :auto-upload="false"
+      class="mb-5"
+    >
+      <template #trigger>
+        <el-button type="primary" plain>选择视频</el-button>
+      </template>
+      <span class="el-upload__tip" style="margin-left: 10px"
+        >格式支持 MP4,文件大小不超过 10MB</span
+      >
+    </el-upload>
+    <el-divider />
+    <el-form :model="uploadData" :rules="uploadRules" ref="uploadFormRef" v-loading="uploading">
+      <el-form-item label="标题" prop="title">
+        <el-input
+          v-model="uploadData.title"
+          placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"
+        />
+      </el-form-item>
+      <el-form-item label="描述" prop="introduction">
+        <el-input
+          :rows="3"
+          type="textarea"
+          v-model="uploadData.introduction"
+          placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button @click="showDialog = false">取 消</el-button>
+      <el-button type="primary" @click="submitVideo" :loading="uploading" :disabled="uploading"
+        >提 交</el-button
+      >
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import type {
+  FormInstance,
+  FormRules,
+  UploadInstance,
+  UploadProps,
+  UploadUserFile
+} from 'element-plus'
+import { HEADERS, UploadData, UPLOAD_URL, beforeVideoUpload, MaterialType } from './upload'
+
+const message = useMessage()
+
+const uploadRules: FormRules = {
+  title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
+  introduction: [{ required: true, message: '请输入描述', trigger: 'blur' }]
+}
+
+const props = defineProps({
+  modelValue: {
+    type: Boolean,
+    default: false
+  }
+})
+const emit = defineEmits<{
+  (e: 'update:modelValue', v: boolean)
+  (e: 'uploaded', v: void)
+}>()
+
+const showDialog = computed({
+  get() {
+    return props.modelValue
+  },
+  set(val) {
+    emit('update:modelValue', val)
+  }
+})
+
+const uploading = ref(false)
+
+const fileList = ref<UploadUserFile[]>([])
+
+const uploadData: UploadData = reactive({
+  type: MaterialType.Video,
+  title: '',
+  introduction: ''
+})
+
+const uploadFormRef = ref<FormInstance>()
+const uploadVideoRef = ref<UploadInstance>()
+
+const submitVideo = () => {
+  uploadFormRef.value?.validate((valid) => {
+    if (!valid) {
+      return false
+    }
+    uploadVideoRef.value?.submit()
+  })
+}
+
+const handleUploadSuccess: UploadProps['onSuccess'] = (res: any) => {
+  uploading.value = false
+  if (res.code !== 0) {
+    message.error('上传出错:' + res.msg)
+    return false
+  }
+
+  // 清空上传时的各种数据
+  fileList.value = []
+  uploadData.title = ''
+  uploadData.introduction = ''
+
+  showDialog.value = false
+  message.notifySuccess('上传成功')
+  emit('uploaded')
+}
+</script>
+
+<style scoped></style>
diff --git a/src/views/mp/material/components/VideoTable.vue b/src/views/mp/material/components/VideoTable.vue
new file mode 100644
index 00000000..3bd2fe00
--- /dev/null
+++ b/src/views/mp/material/components/VideoTable.vue
@@ -0,0 +1,61 @@
+<template>
+  <el-table :data="props.list" stripe border v-loading="props.loading" style="margin-top: 10px">
+    <el-table-column label="编号" align="center" prop="mediaId" />
+    <el-table-column label="文件名" align="center" prop="name" />
+    <el-table-column label="标题" align="center" prop="title" />
+    <el-table-column label="介绍" align="center" prop="introduction" />
+    <el-table-column label="视频" align="center">
+      <template #default="scope">
+        <WxVideoPlayer v-if="scope.row.url" :url="scope.row.url" />
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="上传时间"
+      align="center"
+      :formatter="dateFormatter"
+      prop="createTime"
+      width="180"
+    >
+      <template #default="scope">
+        <span>{{ scope.row.createTime }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column label="操作" align="center" fixed="right">
+      <template #default="scope">
+        <el-button type="primary" link @click="handleDownload(scope.row.url)">
+          <Icon icon="ep:download" />下载
+        </el-button>
+        <el-button
+          type="primary"
+          link
+          @click="emit('delete', scope.row.id)"
+          v-hasPermi="['mp:material:delete']"
+        >
+          <Icon icon="ep:delete" />删除
+        </el-button>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script setup lang="ts">
+import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps<{
+  list: any[]
+  loading: boolean
+}>()
+
+const emit = defineEmits<{
+  (e: 'delete', v: number)
+  (e: 'download', v: string)
+}>()
+
+// 下载文件
+const handleDownload = (url: string) => {
+  window.open(url, '_blank')
+}
+</script>
+
+<style scoped></style>
diff --git a/src/views/mp/material/components/VoiceTable.vue b/src/views/mp/material/components/VoiceTable.vue
new file mode 100644
index 00000000..44bd01da
--- /dev/null
+++ b/src/views/mp/material/components/VoiceTable.vue
@@ -0,0 +1,53 @@
+<template>
+  <el-table :data="props.list" stripe border v-loading="props.loading" style="margin-top: 10px">
+    <el-table-column label="编号" align="center" prop="mediaId" />
+    <el-table-column label="文件名" align="center" prop="name" />
+    <el-table-column label="语音" align="center">
+      <template #default="scope">
+        <WxVoicePlayer v-if="scope.row.url" :url="scope.row.url" />
+      </template>
+    </el-table-column>
+    <el-table-column
+      label="上传时间"
+      align="center"
+      prop="createTime"
+      :formatter="dateFormatter"
+      width="180"
+    >
+      <template #default="scope">
+        <span>{{ scope.row.createTime }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+      <template #default="scope">
+        <el-button type="primary" link @click="emit('delete', scope.row.id)">
+          <Icon icon="ep:download" />下载
+        </el-button>
+        <el-button
+          type="primary"
+          link
+          @click="emit('delete', scope.row.id)"
+          v-hasPermi="['mp:material:delete']"
+        >
+          <Icon icon="ep:delete" />删除
+        </el-button>
+      </template>
+    </el-table-column>
+  </el-table>
+</template>
+
+<script setup lang="ts">
+import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'
+import { dateFormatter } from '@/utils/formatTime'
+
+const props = defineProps<{
+  list: any[]
+  loading: boolean
+}>()
+
+const emit = defineEmits<{
+  (e: 'delete', v: number)
+}>()
+</script>
+
+<style scoped></style>
diff --git a/src/views/mp/material/components/Waterfall.vue b/src/views/mp/material/components/Waterfall.vue
new file mode 100644
index 00000000..118fc7bd
--- /dev/null
+++ b/src/views/mp/material/components/Waterfall.vue
@@ -0,0 +1,83 @@
+<template>
+  <div class="waterfall" v-loading="props.loading">
+    <div class="waterfall-item" v-for="item in props.list" :key="item.id">
+      <a target="_blank" :href="item.url">
+        <img class="material-img" :src="item.url" />
+        <div class="item-name">{{ item.name }}</div>
+      </a>
+      <el-row justify="center">
+        <el-button
+          type="danger"
+          circle
+          @click="emit('delete', item.id)"
+          v-hasPermi="['mp:material:delete']"
+        >
+          <Icon icon="ep:delete" />
+        </el-button>
+      </el-row>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+const props = defineProps<{
+  list: any[]
+  loading: boolean
+}>()
+
+const emit = defineEmits<{
+  (e: 'delete', v: number)
+}>()
+</script>
+
+<style lang="scss" scoped>
+/*瀑布流样式*/
+.waterfall {
+  width: 100%;
+  column-gap: 10px;
+  column-count: 5;
+  margin-top: 10px;
+  /* 芋道源码:增加 10px,避免顶着上面 */
+}
+
+.waterfall-item {
+  padding: 10px;
+  margin-bottom: 10px;
+  break-inside: avoid;
+  border: 1px solid #eaeaea;
+}
+
+.material-img {
+  width: 100%;
+}
+
+p {
+  line-height: 30px;
+}
+
+@media (min-width: 992px) and (max-width: 1300px) {
+  .waterfall {
+    column-count: 3;
+  }
+
+  p {
+    color: red;
+  }
+}
+
+@media (min-width: 768px) and (max-width: 991px) {
+  .waterfall {
+    column-count: 2;
+  }
+
+  p {
+    color: orange;
+  }
+}
+
+@media (max-width: 767px) {
+  .waterfall {
+    column-count: 1;
+  }
+}
+</style>
diff --git a/src/views/mp/material/components/upload.ts b/src/views/mp/material/components/upload.ts
new file mode 100644
index 00000000..37441f5b
--- /dev/null
+++ b/src/views/mp/material/components/upload.ts
@@ -0,0 +1,73 @@
+import type { UploadProps, UploadRawFile } from 'element-plus'
+import { getAccessToken } from '@/utils/auth'
+
+const message = useMessage()
+
+const HEADERS = { Authorization: 'Bearer ' + getAccessToken() }
+const UPLOAD_URL = 'http://127.0.0.1:8000/upload/' //import.meta.env.VITE_BASE_URL + '/admin-api/mp/material/upload-permanent'
+
+enum MaterialType {
+  Image = 'image',
+  Voice = 'voice',
+  Video = 'video'
+}
+
+interface UploadData {
+  type: MaterialType
+  title: string
+  introduction: string
+}
+
+const beforeUpload = (rawFile: UploadRawFile, materialType: MaterialType): boolean => {
+  let allowTypes: string[] = []
+  let maxSizeMB = 0
+  let name = ''
+
+  switch (materialType) {
+    case MaterialType.Image:
+      allowTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/jpg']
+      maxSizeMB = 2
+      name = '图片'
+      break
+    case MaterialType.Voice:
+      allowTypes = ['audio/mp3', 'audio/mpeg', 'audio/wma', 'audio/wav', 'audio/amr']
+      maxSizeMB = 2
+      name = '图片'
+      break
+    case MaterialType.Video:
+      allowTypes = ['video/mp4']
+      maxSizeMB = 10
+      name = '视频'
+  }
+
+  if (!allowTypes.includes(rawFile.type)) {
+    message.error(`上传${name}格式不对!`)
+    return false
+  }
+
+  if (rawFile.size / 1024 / 1024 > maxSizeMB) {
+    message.error(`上传${name}大小不能超过${maxSizeMB}M!`)
+    return false
+  }
+
+  return true
+}
+
+const beforeImageUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
+  beforeUpload(rawFile, MaterialType.Image)
+
+const beforeVoiceUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
+  beforeUpload(rawFile, MaterialType.Voice)
+
+const beforeVideoUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
+  beforeUpload(rawFile, MaterialType.Video)
+
+export {
+  HEADERS,
+  UPLOAD_URL,
+  MaterialType,
+  UploadData,
+  beforeImageUpload,
+  beforeVoiceUpload,
+  beforeVideoUpload
+}
diff --git a/src/views/mp/material/index.vue b/src/views/mp/material/index.vue
index c6d8055d..dd54cf19 100644
--- a/src/views/mp/material/index.vue
+++ b/src/views/mp/material/index.vue
@@ -12,47 +12,18 @@
   <ContentWrap>
     <el-tabs v-model="type" @tab-change="onTabChange">
       <!-- tab 1:图片  -->
-      <el-tab-pane name="image">
+      <el-tab-pane :name="MaterialType.Image">
         <template #label>
           <span> <Icon icon="ep:picture" />图片 </span>
         </template>
-        <div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
-          <el-upload
-            :action="uploadUrl"
-            :headers="headers"
-            multiple
-            :limit="1"
-            :file-list="fileList"
-            :data="uploadData"
-            :before-upload="beforeImageUpload"
-            :on-success="handleUploadSuccess"
-          >
-            <el-button type="primary" plain>点击上传</el-button>
-            <template #tip>
-              <span class="el-upload__tip" style="margin-left: 5px">
-                支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M
-              </span>
-            </template>
-          </el-upload>
-        </div>
-        <div class="waterfall" v-loading="loading">
-          <div class="waterfall-item" v-for="item in list" :key="item.id">
-            <a target="_blank" :href="item.url">
-              <img class="material-img" :src="item.url" />
-              <div class="item-name">{{ item.name }}</div>
-            </a>
-            <el-row justify="center">
-              <el-button
-                type="danger"
-                circle
-                @click="handleDelete(item)"
-                v-hasPermi="['mp:material:delete']"
-              >
-                <Icon icon="ep:delete" />
-              </el-button>
-            </el-row>
-          </div>
-        </div>
+        <Upload
+          v-hasPermi="['mp:material:upload-permanent']"
+          :type="MaterialType.Image"
+          @uploaded="getList"
+        >
+          支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M
+        </Upload>
+        <Waterfall :loading="loading" :list="list" @delete="handleDelete" />
         <!-- 分页组件 -->
         <Pagination
           :total="total"
@@ -63,67 +34,20 @@
       </el-tab-pane>
 
       <!-- tab 2:语音  -->
-      <el-tab-pane name="voice">
+      <el-tab-pane :name="MaterialType.Voice">
         <template #label>
           <span> <Icon icon="ep:microphone" />语音 </span>
         </template>
-        <div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
-          <el-upload
-            :action="uploadUrl"
-            :headers="headers"
-            multiple
-            :limit="1"
-            :file-list="fileList"
-            :data="uploadData"
-            :on-success="handleUploadSuccess"
-            :before-upload="beforeVoiceUpload"
-          >
-            <el-button type="primary" plain>点击上传</el-button>
-            <template #tip>
-              <span class="el-upload__tip" style="margin-left: 5px">
-                格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s
-              </span>
-            </template>
-          </el-upload>
-        </div>
+        <Upload
+          v-hasPermi="['mp:material:upload-permanent']"
+          :type="MaterialType.Voice"
+          @uploaded="getList"
+        >
+          格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s
+        </Upload>
 
         <!-- 列表 -->
-        <el-table :data="list" stripe border v-loading="loading" style="margin-top: 10px">
-          <el-table-column label="编号" align="center" prop="mediaId" />
-          <el-table-column label="文件名" align="center" prop="name" />
-          <el-table-column label="语音" align="center">
-            <template #default="scope">
-              <WxVoicePlayer v-if="scope.row.url" :url="scope.row.url" />
-            </template>
-          </el-table-column>
-          <el-table-column
-            label="上传时间"
-            align="center"
-            prop="createTime"
-            :formatter="dateFormatter"
-            width="180"
-          >
-            <template #default="scope">
-              <span>{{ scope.row.createTime }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-            <template #default="scope">
-              <el-button type="primary" link plain @click="handleDownload(scope.row)">
-                <Icon icon="ep:download" />下载
-              </el-button>
-              <el-button
-                type="primary"
-                link
-                plain
-                @click="handleDelete(scope.row)"
-                v-hasPermi="['mp:material:delete']"
-              >
-                <Icon icon="ep:delete" />删除
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
+        <VoiceTable :list="list" :loading="loading" @delete="handleDelete" />
         <!-- 分页组件 -->
         <Pagination
           :total="total"
@@ -134,105 +58,22 @@
       </el-tab-pane>
 
       <!-- tab 3:视频 -->
-      <el-tab-pane name="video">
+      <el-tab-pane :name="MaterialType.Video">
         <template #label>
           <span> <Icon icon="ep:video-play" /> 视频 </span>
         </template>
-        <div class="add_but" v-hasPermi="['mp:material:upload-permanent']">
-          <el-button type="primary" plain @click="handleAddVideo">新建视频</el-button>
-        </div>
-        <!-- 新建视频的弹窗 -->
-        <el-dialog
-          title="新建视频"
-          v-model="dialogVideoVisible"
-          width="600px"
-          v-loading="addMaterialLoading"
+        <el-button
+          v-hasPermi="['mp:material:upload-permanent']"
+          type="primary"
+          plain
+          @click="showCreateVideo = true"
+          >新建视频</el-button
         >
-          <el-upload
-            :action="uploadUrl"
-            :headers="headers"
-            multiple
-            :limit="1"
-            :file-list="fileList"
-            :data="uploadData"
-            :before-upload="beforeVideoUpload"
-            :on-success="handleUploadSuccess"
-            ref="uploadVideoRef"
-            :auto-upload="false"
-          >
-            <template #trigger>
-              <el-button size="small" type="primary">选择视频</el-button>
-            </template>
-            <span class="el-upload__tip" style="margin-left: 10px"
-              >格式支持 MP4,文件大小不超过 10MB</span
-            >
-          </el-upload>
-          <el-form :model="uploadData" :rules="uploadRules" ref="uploadFormRef" label-width="80px">
-            <el-row>
-              <el-form-item label="标题" prop="title">
-                <el-input
-                  v-model="uploadData.title"
-                  placeholder="标题将展示在相关播放页面,建议填写清晰、准确、生动的标题"
-                />
-              </el-form-item>
-            </el-row>
-            <el-row>
-              <el-form-item label="描述" prop="introduction">
-                <el-input
-                  :rows="3"
-                  type="textarea"
-                  v-model="uploadData.introduction"
-                  placeholder="介绍语将展示在相关播放页面,建议填写简洁明确、有信息量的内容"
-                />
-              </el-form-item>
-            </el-row>
-          </el-form>
-          <template #footer>
-            <el-button @click="cancelVideo">取 消</el-button>
-            <el-button type="primary" @click="submitVideo">提 交</el-button>
-          </template>
-        </el-dialog>
+        <!-- 新建视频的弹窗 -->
+        <UploadVideo v-model="showCreateVideo" />
 
         <!-- 列表 -->
-        <el-table :data="list" stripe border v-loading="loading" style="margin-top: 10px">
-          <el-table-column label="编号" align="center" prop="mediaId" />
-          <el-table-column label="文件名" align="center" prop="name" />
-          <el-table-column label="标题" align="center" prop="title" />
-          <el-table-column label="介绍" align="center" prop="introduction" />
-          <el-table-column label="视频" align="center">
-            <template #default="scope">
-              <WxVideoPlayer v-if="scope.row.url" :url="scope.row.url" />
-            </template>
-          </el-table-column>
-          <el-table-column
-            label="上传时间"
-            align="center"
-            :formatter="dateFormatter"
-            prop="createTime"
-            width="180"
-          >
-            <template #default="scope">
-              <span>{{ scope.row.createTime }}</span>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" align="center" fixed="right">
-            <template #default="scope">
-              <el-button type="primary" link plain @click="handleDownload(scope.row)">
-                <Icon icon="ep:download" />下载
-              </el-button>
-              <el-button
-                type="primary"
-                link
-                size="small"
-                plain
-                @click="handleDelete(scope.row)"
-                v-hasPermi="['mp:material:delete']"
-              >
-                <Icon icon="ep:delete" />删除
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
+        <VideoTable :list="list" :loading="loading" @delete="handleDelete" />
         <!-- 分页组件 -->
         <Pagination
           :total="total"
@@ -246,39 +87,19 @@
 </template>
 
 <script lang="ts" setup name="MpMaterial">
-import WxVoicePlayer from '@/views/mp/components/wx-voice-play/main.vue'
-import WxVideoPlayer from '@/views/mp/components/wx-video-play/main.vue'
 import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue'
+import Waterfall from './components/Waterfall.vue'
+import VoiceTable from './components/VoiceTable.vue'
+import VideoTable from './components/VideoTable.vue'
+import Upload from './components/Upload.vue'
+import UploadVideo from './components/UploadVideo.vue'
+import { MaterialType } from './components/upload'
 import * as MpMaterialApi from '@/api/mp/material'
-import * as authUtil from '@/utils/auth'
-import { dateFormatter } from '@/utils/formatTime'
-import type {
-  FormInstance,
-  FormRules,
-  TabPaneName,
-  UploadInstance,
-  UploadProps,
-  UploadRawFile,
-  UploadUserFile
-} from 'element-plus'
-
-const BASE_URL = import.meta.env.VITE_BASE_URL
-const uploadUrl = BASE_URL + '/admin-api/mp/material/upload-permanent'
-const headers = { Authorization: 'Bearer ' + authUtil.getAccessToken() }
 
 const message = useMessage()
 
-const uploadFormRef = ref<FormInstance>()
-const uploadVideoRef = ref<UploadInstance>()
-
-const uploadRules: FormRules = {
-  title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
-  introduction: [{ required: true, message: '请输入描述', trigger: 'blur' }]
-}
-
 // 素材类型
-type MaterialType = 'image' | 'voice' | 'video'
-const type = ref<MaterialType>('image')
+const type = ref<MaterialType>(MaterialType.Image)
 const loading = ref(false) // 遮罩层
 const list = ref<any[]>([]) // 总条数
 const total = ref(0) // 数据列表
@@ -296,22 +117,8 @@ const queryParams: QueryParams = reactive({
   permanent: true
 })
 
-const fileList = ref<UploadUserFile[]>([])
-
-interface UploadData {
-  type: MaterialType
-  title: string
-  introduction: string
-}
-const uploadData: UploadData = reactive({
-  type: 'image',
-  title: '',
-  introduction: ''
-})
-
 // === 视频上传,独有变量 ===
-const dialogVideoVisible = ref(false)
-const addMaterialLoading = ref(false)
+const showCreateVideo = ref(false)
 
 /** 侦听公众号变化 **/
 const onAccountChanged = (id?: number) => {
@@ -341,10 +148,7 @@ const handleQuery = () => {
   getList()
 }
 
-const onTabChange = (tabName: TabPaneName) => {
-  // 设置 type
-  uploadData.type = tabName as MaterialType
-
+const onTabChange = () => {
   // 提前情况数据,避免tab切换后显示垃圾数据
   list.value = []
   total.value = 0
@@ -353,160 +157,12 @@ const onTabChange = (tabName: TabPaneName) => {
   handleQuery()
 }
 
-// ======================== 文件上传 ========================
-const beforeUpload = (rawFile: UploadRawFile, category: 'image' | 'audio' | 'video'): boolean => {
-  let allowTypes: string[] = []
-  let maxSizeMB = 0
-  let name = ''
-
-  switch (category) {
-    case 'image':
-      allowTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/jpg']
-      maxSizeMB = 2
-      name = '图片'
-      break
-    case 'audio':
-      allowTypes = ['audio/mp3', 'audio/mpeg', 'audio/wma', 'audio/wav', 'audio/amr']
-      maxSizeMB = 2
-      name = '图片'
-      break
-    case 'video':
-      allowTypes = ['video/mp4']
-      maxSizeMB = 10
-      name = '视频'
-  }
-
-  if (!allowTypes.includes(rawFile.type)) {
-    message.error(`上传${name}格式不对!`)
-    return false
-  }
-  // 校验大小
-  if (rawFile.size / 1024 / 1024 > maxSizeMB) {
-    message.error(`上传${name}大小不能超过${maxSizeMB}M!`)
-    return false
-  }
-  loading.value = true
-  return true
-}
-
-const beforeImageUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
-  beforeUpload(rawFile, 'image')
-
-const beforeVoiceUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
-  beforeUpload(rawFile, 'audio')
-
-const beforeVideoUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) =>
-  beforeUpload(rawFile, 'video')
-
-const handleUploadSuccess: UploadProps['onSuccess'] = (response: any) => {
-  loading.value = false
-  addMaterialLoading.value = false
-  if (response.code !== 0) {
-    message.error('上传出错:' + response.msg)
-    return false
-  }
-
-  // 清空上传时的各种数据
-  dialogVideoVisible.value = false
-  fileList.value = []
-  uploadData.title = ''
-  uploadData.introduction = ''
-
-  // 加载数据
-  getList()
-}
-
-// 下载文件
-const handleDownload = (row: any) => {
-  window.open(row.url, '_blank')
-}
-
-// 提交 video 新建的表单
-const submitVideo = () => {
-  uploadFormRef.value?.validate((valid) => {
-    if (!valid) {
-      return false
-    }
-    uploadVideoRef.value?.submit()
-  })
-}
-
-// 弹出 video 新建的表单
-const handleAddVideo = () => {
-  resetVideo()
-  dialogVideoVisible.value = true
-}
-
-/** 取消按钮 */
-const cancelVideo = () => {
-  dialogVideoVisible.value = false
-  resetVideo()
-}
-
-/** 表单重置 */
-const resetVideo = () => {
-  fileList.value = []
-  uploadData.title = ''
-  uploadData.introduction = ''
-  uploadFormRef.value?.resetFields()
-}
-
 // ======================== 其它操作 ========================
-const handleDelete = async (item: any) => {
+const handleDelete = async (id: number) => {
   await message.confirm('此操作将永久删除该文件, 是否继续?')
-  await MpMaterialApi.deletePermanentMaterial(item.id)
+  await MpMaterialApi.deletePermanentMaterial(id)
   message.alertSuccess('删除成功')
 }
 </script>
 
-<style lang="scss" scoped>
-/*瀑布流样式*/
-.waterfall {
-  width: 100%;
-  column-gap: 10px;
-  column-count: 5;
-  margin-top: 10px;
-  /* 芋道源码:增加 10px,避免顶着上面 */
-}
-
-.waterfall-item {
-  padding: 10px;
-  margin-bottom: 10px;
-  break-inside: avoid;
-  border: 1px solid #eaeaea;
-}
-
-.material-img {
-  width: 100%;
-}
-
-p {
-  line-height: 30px;
-}
-
-@media (min-width: 992px) and (max-width: 1300px) {
-  .waterfall {
-    column-count: 3;
-  }
-
-  p {
-    color: red;
-  }
-}
-
-@media (min-width: 768px) and (max-width: 991px) {
-  .waterfall {
-    column-count: 2;
-  }
-
-  p {
-    color: orange;
-  }
-}
-
-@media (max-width: 767px) {
-  .waterfall {
-    column-count: 1;
-  }
-}
-</style>
+<style lang="scss" scoped></style>

From 4dabb710c557345ed5e3c391ebd8e77eb818deb3 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 16:03:12 +0800
Subject: [PATCH 12/15] =?UTF-8?q?=E4=BC=98=E5=8C=96=20OA=20=E8=AF=B7?=
 =?UTF-8?q?=E5=81=87=EF=BC=8Ccreate=20=E5=92=8C=20detail=20=E4=BD=BF?=
 =?UTF-8?q?=E7=94=A8=E7=8B=AC=E7=AB=8B=E8=B7=AF=E7=94=B1=EF=BC=8C=E5=8F=AF?=
 =?UTF-8?q?=E6=8E=A5=E5=85=A5=E5=B7=A5=E4=BD=9C=E6=B5=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/router/modules/remaining.ts   |  14 +++-
 src/views/bpm/oa/leave/create.vue | 113 ++++++++++++------------------
 src/views/bpm/oa/leave/detail.vue |  34 +++++----
 src/views/bpm/oa/leave/index.vue  |  20 +++---
 4 files changed, 88 insertions(+), 93 deletions(-)

diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts
index 8886e388..d3b18d9c 100644
--- a/src/router/modules/remaining.ts
+++ b/src/router/modules/remaining.ts
@@ -313,7 +313,19 @@ const remainingRouter: AppRouteRecordRaw[] = [
           hidden: true,
           canTo: true,
           title: '发起 OA 请假',
-          activeMenu: 'bpm/oa/leave/create'
+          activeMenu: '/bpm/oa/leave'
+        }
+      },
+      {
+        path: '/bpm/oa/leave/detail',
+        component: () => import('@/views/bpm/oa/leave/detail.vue'),
+        name: 'OALeaveDetail',
+        meta: {
+          noCache: true,
+          hidden: true,
+          canTo: true,
+          title: '查看 OA 请假',
+          activeMenu: '/bpm/oa/leave'
         }
       }
     ]
diff --git a/src/views/bpm/oa/leave/create.vue b/src/views/bpm/oa/leave/create.vue
index 321ec609..13c49419 100644
--- a/src/views/bpm/oa/leave/create.vue
+++ b/src/views/bpm/oa/leave/create.vue
@@ -1,56 +1,55 @@
 <template>
-  <Dialog title="发起 OA 请假流程" v-model="dialogVisible">
-    <el-form
-      ref="formRef"
-      :model="formData"
-      :rules="formRules"
-      label-width="80px"
-      v-loading="formLoading"
-    >
-      <el-form-item label="请假类型" prop="type">
-        <el-select v-model="formData.type" placeholder="请选择请假类型" clearable>
-          <el-option
-            v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="开始时间" prop="startTime">
-        <el-date-picker
-          clearable
-          v-model="formData.startTime"
-          type="datetime"
-          value-format="x"
-          placeholder="请选择开始时间"
+  <el-form
+    ref="formRef"
+    :model="formData"
+    :rules="formRules"
+    label-width="80px"
+    v-loading="formLoading"
+  >
+    <el-form-item label="请假类型" prop="type">
+      <el-select v-model="formData.type" placeholder="请选择请假类型" clearable>
+        <el-option
+          v-for="dict in getIntDictOptions(DICT_TYPE.BPM_OA_LEAVE_TYPE)"
+          :key="dict.value"
+          :label="dict.label"
+          :value="dict.value"
         />
-      </el-form-item>
-      <el-form-item label="结束时间" prop="endTime">
-        <el-date-picker
-          clearable
-          v-model="formData.endTime"
-          type="datetime"
-          value-format="x"
-          placeholder="请选择结束时间"
-        />
-      </el-form-item>
-      <el-form-item label="原因" prop="reason">
-        <el-input v-model="formData.reason" type="textarea" placeholder="请输请假原因" />
-      </el-form-item>
-    </el-form>
-    <template #footer>
+      </el-select>
+    </el-form-item>
+    <el-form-item label="开始时间" prop="startTime">
+      <el-date-picker
+        clearable
+        v-model="formData.startTime"
+        type="datetime"
+        value-format="x"
+        placeholder="请选择开始时间"
+      />
+    </el-form-item>
+    <el-form-item label="结束时间" prop="endTime">
+      <el-date-picker
+        clearable
+        v-model="formData.endTime"
+        type="datetime"
+        value-format="x"
+        placeholder="请选择结束时间"
+      />
+    </el-form-item>
+    <el-form-item label="原因" prop="reason">
+      <el-input v-model="formData.reason" type="textarea" placeholder="请输请假原因" />
+    </el-form-item>
+    <el-form-item>
       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
-      <el-button @click="dialogVisible = false">取 消</el-button>
-    </template>
-  </Dialog>
+    </el-form-item>
+  </el-form>
 </template>
 <script setup lang="ts">
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import * as LeaveApi from '@/api/bpm/leave'
+import { useTagsViewStore } from '@/store/modules/tagsView'
 const message = useMessage() // 消息弹窗
+const { delView } = useTagsViewStore() // 视图操作
+const { currentRoute } = useRouter() // 路由
 
-const dialogVisible = ref(false) // 弹窗的是否展示
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const formData = ref({
   type: undefined,
@@ -66,15 +65,7 @@ const formRules = reactive({
 })
 const formRef = ref() // 表单 Ref
 
-/** 打开弹窗 */
-const open = async () => {
-  dialogVisible.value = true
-  resetForm()
-}
-defineExpose({ open }) // 提供 open 方法,用于打开弹窗
-
 /** 提交表单 */
-const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
 const submitForm = async () => {
   // 校验表单
   if (!formRef) return
@@ -85,23 +76,11 @@ const submitForm = async () => {
   try {
     const data = formData.value as unknown as LeaveApi.LeaveVO
     await LeaveApi.createLeave(data)
-    message.success('新增成功')
-    dialogVisible.value = false
-    // 发送操作成功的事件
-    emit('success')
+    message.success('发起成功')
+    // 关闭当前 Tab
+    delView(unref(currentRoute))
   } finally {
     formLoading.value = false
   }
 }
-
-/** 重置表单 */
-const resetForm = () => {
-  formData.value = {
-    type: undefined,
-    reason: undefined,
-    startTime: undefined,
-    endTime: undefined
-  }
-  formRef.value?.resetFields()
-}
 </script>
diff --git a/src/views/bpm/oa/leave/detail.vue b/src/views/bpm/oa/leave/detail.vue
index 838be149..2efc37fb 100644
--- a/src/views/bpm/oa/leave/detail.vue
+++ b/src/views/bpm/oa/leave/detail.vue
@@ -1,40 +1,48 @@
 <template>
-  <Dialog title="详情" v-model="dialogVisible" :scroll="true" :max-height="200">
+  <ContentWrap>
     <el-descriptions border :column="1">
       <el-descriptions-item label="请假类型">
         <dict-tag :type="DICT_TYPE.BPM_OA_LEAVE_TYPE" :value="detailData.type" />
       </el-descriptions-item>
       <el-descriptions-item label="开始时间">
-        {{ formatDate(detailData.startTime) }}
+        {{ formatDate(detailData.startTime, 'YYYY-MM-DD') }}
       </el-descriptions-item>
       <el-descriptions-item label="结束时间">
-        {{ formatDate(detailData.endTime) }}
+        {{ formatDate(detailData.endTime, 'YYYY-MM-DD') }}
       </el-descriptions-item>
       <el-descriptions-item label="原因">
         {{ detailData.reason }}
       </el-descriptions-item>
     </el-descriptions>
-  </Dialog>
+  </ContentWrap>
 </template>
-<script setup lang="ts">
+<script setup lang="ts" name="OALeaveCreate">
 import { DICT_TYPE } from '@/utils/dict'
 import { formatDate } from '@/utils/formatTime'
+import { propTypes } from '@/utils/propTypes'
 import * as LeaveApi from '@/api/bpm/leave'
+const { query } = useRoute() // 查询参数
 
-const dialogVisible = ref(false) // 弹窗的是否展示
+const props = defineProps({
+  id: propTypes.number.def(undefined)
+})
 const detailLoading = ref(false) // 表单的加载中
-const detailData = ref() // 详情数据
+const detailData = ref({}) // 详情数据
+const queryId = query.id as unknown as number // 从 URL 传递过来的 id 编号
 
-/** 打开弹窗 */
-const open = async (data: LeaveApi.LeaveVO) => {
-  dialogVisible.value = true
-  // 设置数据
+/** 获得数据 */
+const getInfo = async () => {
   detailLoading.value = true
   try {
-    detailData.value = data
+    detailData.value = await LeaveApi.getLeave(queryId || props.id)
   } finally {
     detailLoading.value = false
   }
 }
-defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+defineExpose({ open: getInfo }) // 提供 open 方法,用于打开弹窗
+
+/** 初始化 **/
+onMounted(() => {
+  getInfo()
+})
 </script>
diff --git a/src/views/bpm/oa/leave/index.vue b/src/views/bpm/oa/leave/index.vue
index ebf10d72..901b6038 100644
--- a/src/views/bpm/oa/leave/index.vue
+++ b/src/views/bpm/oa/leave/index.vue
@@ -137,19 +137,12 @@
       @pagination="getList"
     />
   </ContentWrap>
-
-  <!-- 表单弹窗:详情 -->
-  <LeaveDetail ref="detailRef" />
-  <!-- 表单弹窗:添加 -->
-  <LeaveForm ref="formRef" @success="getList" />
 </template>
 <script setup lang="ts" name="BpmOALeave">
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import * as LeaveApi from '@/api/bpm/leave'
 import * as ProcessInstanceApi from '@/api/bpm/processInstance'
-import LeaveDetail from './detail.vue'
-import LeaveForm from './create.vue'
 const message = useMessage() // 消息弹窗
 const router = useRouter() // 路由
 const { t } = useI18n() // 国际化
@@ -192,15 +185,18 @@ const resetQuery = () => {
 }
 
 /** 添加操作 */
-const formRef = ref()
 const handleCreate = () => {
-  formRef.value.open()
+  router.push({ name: 'OALeaveCreate' })
 }
 
 /** 详情操作 */
-const detailRef = ref()
-const handleDetail = (data: LeaveApi.LeaveVO) => {
-  detailRef.value.open(data)
+const handleDetail = (row: LeaveApi.LeaveVO) => {
+  router.push({
+    name: 'OALeaveDetail',
+    query: {
+      id: row.id
+    }
+  })
 }
 
 /** 取消请假操作 */

From abf9b50c2f9a4ceb19066b7e722336a7bff05759 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 16:37:11 +0800
Subject: [PATCH 13/15] =?UTF-8?q?REVIEW=20=E7=B4=A0=E6=9D=90=E7=AE=A1?=
 =?UTF-8?q?=E7=90=86=E7=9A=84=E9=87=8D=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/views/mp/components/img.png               | Bin 15404 -> 0 bytes
 .../{Waterfall.vue => ImageTable.vue}         |   0
 .../components/{Upload.vue => UploadFile.vue} |   3 --
 .../mp/material/components/UploadVideo.vue    |   2 -
 .../mp/material/components/VideoTable.vue     |   2 -
 .../mp/material/components/VoiceTable.vue     |   2 -
 src/views/mp/material/components/upload.ts    |  16 ++++----
 src/views/mp/material/index.vue               |  37 +++++++-----------
 8 files changed, 21 insertions(+), 41 deletions(-)
 delete mode 100644 src/views/mp/components/img.png
 rename src/views/mp/material/components/{Waterfall.vue => ImageTable.vue} (100%)
 rename src/views/mp/material/components/{Upload.vue => UploadFile.vue} (98%)

diff --git a/src/views/mp/components/img.png b/src/views/mp/components/img.png
deleted file mode 100644
index c25a6e762f3a84c5a7f05c6383de843937725fcf..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 15404
zcmcJ0Wn5HU_^k>ef`9@70*a!55(CmDf*>lXv@i%F-7s{gG$I`{AnnjKz(@(wF_iSs
zG2|dEeGkU#i|_y5`@0|R2S0c?bM}e7*R!6r)(&_s_k@Umn&8ZtGepmxN+_H;bG94!
zM~Qz9IO2MFLGR2Np^aw}VoDCLR$$JMk$%MdhAav_g4%70lJy~Z!TIz(xzUTXy9zG;
z;UB~3jfUTA1-QB_Uc>A~Jz1LD<Thiwo|%`hnN=EZ1XVNRL<OVWyc6Tb;*R>pwoAun
z%(ZbQ8eg43TomPC$m6M53mbGc^RQd*ox*F_iWiQc6^~!R7PIfzB`$+lLA5W0^2VKx
z_epLLoqsk-0Y?vg(v%Ln(7U#`GJ1G8S`p=-Bj~nJdvw$*Wcy}#E}AzDr6frQR=S~>
z!ERpVvfIPYsadff`79rOYsuU!3puRNt{5&I{dPdqAY5-BqZ~6j{^_fh-z&CauTS{y
zj{Z2W+z)N<QQe64;Ev0(iO=>m<VX{djS;NsVRaRTX)g3_Sl?7pGtcX6OEz??LKJb_
zyO%2R&E0)#+TCsQ%5H>EqD(qzfJ6tg9F+h4b8q4AbnqQo4grCSBm`6PSd(w#M}yNc
z<wZ|WdM{?v2QBYn>RO71if7iO8D)x87)%6H{FTY>8W@-lRYUq72NQC<@_p~i{}~QZ
z3|e``!{S#L!3>f9jBK2FZ;ic}Ad0!cM@y)>jY5_{(<bYY#=9+jQKl;`LE&uHePGFE
z^{&3bh&sKY7qjFlM~`Wz8<8}l5Y|tSOwK^abmI)%C4!%CJqwl~mwAET-p-B!=Imm5
z8$3jaQE;XvwNb+mPlH#2_l`XD@;u8SA&aqW5m)&5ZLzxC(f$oY1buEW8o9`d4t3r%
zDc+lp4NMFYW`j4SU^D@8%GrIUyloXKAy4lpWcT^o$$x;nJ6kAWy+3)osV?e)Rh}c$
z*Ra&m{H%l*H<rOS4ejn>?>~UQXi=Y|{#<o_o3lM8EvihimQYpvZCxBhVDJ#^8<*ZE
zm#N;)5D_P1mD@dZ_YOVBQdofv=vGW8Sz)4xYdjgYzFwkGjg_204ReF82ePr-Kq?IK
zXF{zky&Fp|8pi$5%a18aNfRn{B}}k@uc3Ix?@mKn^f>HWA~&cX7dpPoBT#X3TQ+~d
zu}XY9RNxW@FYPI}GHbp$H}9tqMAU&P>%8iFmLVZNszjMPiq9(+Y(6P5!vt*un<-&I
zcgyYb+R+mV2MuV~6#cJnOF?3_-M6+;S0ALb^VL*fpxH9K?&mzKS{f656Kx`{>AALQ
zg*ztUS_LqnuHRdRN(V57=h)qT{}iFl;7(2Owv<#1?RweWx*I7T#u6RWxA#1Zyd2eh
zZU=JV%#QeFzTgB1gJgw`s^?eaTgz@_vl<5!vWAVz3{HkHXjbgHR4Xxevz@mAaY|mA
z1?zEAAjj?}q8K9E^ioC_7K~KN=fS$Hmu*0!#1wG>{#>OfhC016t8OH|*Y{d}p_qYO
z>Mj*}{|b^Rd5|EbnB+Md5as{p1NQhT@uS;wdft4WFr71$liavgX9Qyi4Oy<#k6u_~
zqJ#<IeiJgU-idgZP$kPxCieC`tnGYB6#f*}`+GzX>iW5PaBJgkkR_+rrSpIN&JK0`
z%mL^LZecwRrco*z*8d2-nLFe8Tv&0`(9S7W>TQyH^9KmqHA+l$%+k9X?m9!aQiibR
z4_zV?6a2(!=h3fgqd!lT+nC>^YRlWCj*^KzR9SBssxvMd0>g8XAta4SXe%o$4NX6+
zE11}5cdGXAb{F!C7wT$LI^@fOQ*l*vK>V=iooE!VO5oa4{+D8y8^I5e(^KG~tg{Tl
zoK*QxX<6J6ZcACm-5W$2F)|Mrrvi=?GhTXck7~Cop!q<<u!ir%)@^!7i42P{Gm4Rr
zsr0c)FV~fM9SS}ak&i-ye*UZ2$vtVgOwNef=b{A3kjLMc?1P~!2@FCxmU{1?($0&U
z8p~g?V;L*m?Hx@YCxVSi6yq}3MqQOMzy?~mnQ@a65Y@!92KVD}3axd?LWo68y%9J?
zcy^uWO7C&Jp{7Czj)EG9Tccx9ruoyrH9=KiayGRgi}FU9Dr#=1lowH=5K9I)6*8@J
zrTS>Tks=}%<O_3uO@nVQ%T=N*{n@1VtNK@pBaNVt3wBO)5U3Ded^VzDwmot^c4=Rl
z=>wzzxaDOi3rS77_Jk+IEbWaWl#LCUaS7^mwWAQl<DO7nh?*$=oOHnz6JK^a_@*>b
zvjPQX37mVkaaG8VA7U;VFQY8j(f5e^qXPwu1uNnYyyJOrol`bfj^%8jJ*d)@VN^u=
zI-=aKf1E~agOlIZ+_-QwTYvVsgMyy<MHnIR2}Z{X4qUszKd?AjHEQK%A%;fIRh@sc
zK2dzBAXATCPc&N4coNLkU0EDlZiSWHp(O-PKblE__<gQ|=qW$TG4Xerf8zjk6^w*L
zk@n1G40#k^DrHJ~YOHKKH^C~`e`m>aEfzj?We5pjN-dONHGlq5=jX^EL3?~*tGt|q
zP&^ZsUaR7FZ>>R&l`SrELGC6Nkm%a&H2M92y#?ZSPPr!?((ZRGGbMF1QL_`<kS~Qp
zad&RPv=$JHkGHJoQ?LhnX9NdGZLpVT0%vs)BII|@=RrPxJ_OG^wWLDHvchIdudBll
zn|A~Us81lKiO2?frGX3+N<I&k?)v%P)646DIe_4I=fR*4xe}M{>FSffHXyHH-2X2J
z^64r#plu|v-uy8S)A0T*@yB8BJycQMBsO^r^I)x)Ms_0!F+^kYi4P;Re0sy~`~3bJ
zI{6;^KmyHm2Qcn;Hi7Z|mZpv|Mrc4VO{I0H8?esBFvL$--@9ynk1)`}@{DNmJKgL;
zMuu!qPR?BM*{8UF0OKQ>jDl>6qmh~NNptT~AXmJ78`5D+6{r#u4En5^8_i6%mn~@7
z=WV&?$)Hx4@TYf3(N=%3Y6-V#_<<biym%?wt;<*Vr)j<UyO6comTqp<3UJ-xm+MU3
z6hZ`M3|{5?H%}(d^(mQ(d2l_k3SZN0JRv?>Vs;QHT8cqujEqU{@@{xj^7H1{Gk;Ep
ziI+$_m*$sASil{pz~+>FQw#kJ)ls3$64I*1WU;7fw4En1yFs(<5M1h8FI~leTed6>
zX(A|1I&c2G`4vB(LgkSqrsk-M{C?=u9^KNd)gAY}HKwGagGu+X3UJ~@Dbfh5^825W
z-G-4=yh)u&K#@Dbt8a;53Tn^+#c<7uY6RT;vA*WP82<SoYyf0PPA6VwUp`7OGOOeA
zl*iOpW3gTkn`v9dT~dBk*_kCUC}wY<>wXz|9aYP-r?u_rbSuKu1F`x!f>qZ07@>z1
z?ztmsX0Ix@dbO}FHupx@?~n*BLurB<n4?<bxC|H>83(n5Bklyy%4hc4Q2&_}w*EMi
zt*-=P3TgUgdo?@svIb-X8Jm!JdfJHU48-j{`hw9_k4`pAlrNHVS=ZEE`HlaOwD^<C
z!&-LtT{?_{>!eiA=Fq-SO?j0dTwRR-RkhU%^BW*Igo+bOV@Ub>j1d5n8SckdI1cYt
zV%`!Iq<n3~2p+nPY2Cx~l3~lh-l1Au8`@bYDd9F&oAqaw-IGhYff+lZ5nF!dCnHE<
z4{BB><~+~ih6?t++FNkzvB~k0fsn=k#Uq*bEYH?jku0NAB}d$Y<z>YXgO0M5^U|2`
zn^C6p?<Z`tFI<DcV6N9;K~(${dCM?}ZJ9Ac7Bhdk{vCR*sPxas%hCeFL_qx^k&~Ia
z^(@&po5aq|&O|`)X@-L3<oJ;ZrdDI);B&Gs3=+{Ya|RPm4-l2j0EX}p5;_60lM5os
zjwyNi7WZ-Lom`$}udoe{bXb#pHutZf<ZDLWRDJ7AxUI_b)>4P`o%SM{#C>;Rr-Cb=
z<w%nOv0Nn?mLML8o*7zo-&-I-F<x*S8WF{)d!eq!Z=zk?3US{BO~gUqx@D!84&geZ
zuB~b^2REpXZ(X3b>CXyoBB}Iil#14(K!=KBihuzwJ&QLVbFSQ&W*G|mWMndpZaJ8J
zCvv#?1!82kF<J1Y0J4z($kG$_Sh$e|)7oV?p?EgK4E(9ZGR)4%k~u9geQhFTWz5T(
z;!siVurshQiHpm^>H|c8|Nh0dca+C>Z7^RtHX|u=cRV28TqZjrW4qtC)zMETtKGsN
zyL&1mHlQg6qz+Oom*o62&!wA9z$^6<gYD0#*66&3u{@?2JL=9%I%-Pa_0O*ZzK99V
z4_XAAbn97foQ@G(*K$`p0~O^JKylCNcnLNeJAUdkl-Ecntm0eJu`_1c*`hyNGO|a}
zZH40p8qqgD{T$Hp(h{Xvy?d{0<y*Gj0Ac<x5(zdpGJ=12lB>dXBjTp`CZ9+0DeQ&D
zhKdae>})Rdt~t1<lT3l9?_cDUsF9-_mcq5#5j$vkjQMfp1u7pH1o<&UBgy|D3WM)e
zY3(ped-&s1okCRHYZw3Tf7pt`!m0@Ag!%Z7u^X+nZp564m3arlYTx<SGLJWU-H+C8
zuQSo=Bx{-B;QYJ~^h}^PFem1OoGr#iyqg}E?@m{d&?S7Y?c5o2d6)Dy_*PRV^7!!G
zh2sOvlNovbdN0&t;t5K5x1Hr()r3{SZjcQ~Z^P9sBMCe@G=4m_)IZBU8HV}pn3wvC
z=b;^XW%Kyw(aA5X3U_Asv;=zdV2}%<3KN23QwbL!G4A`dlp?UDW>3`YIpCi7#%v;3
zhy@2Oh9ZQ_Q5~8`i<3u3U-rlHT@I)WFp~6F#sG5c^Cix%8|i<2dKpYw#F`3uk8^X_
zbq`ro=6p0}G5L`pkv~Q;t)Ul|uRbzf33QoZ*KO$pP;7e0N7%W6r28-rfj2$rCH*8$
z6r<c-`(l;lSvS%KwCfE<TF1jDkR_V<hrX4%(GT(fx~@g?xM%|@mCnh>rwWQ;c=iZG
z?|t(s=n4pK7vS<^C_ek+hNB}sI&@l*qTaB3*2lp3wt|F7c83S#{ocA(5&KF^3YyfZ
zhnajeN20KyVYk{>XQp+kQCEdyZdn~Jd`P<1<ZT5pze~!-3RIPJZH}jx5<2vQ8m0h1
z2Og4#*e7A96&c+8(f#56Bh{!BwusOcD+Oj^5a~4`lY7e_-@ARNxVOk)lu0uIPKMmS
zy5^Zb^>Nx0@&;(hOm5w{A1bl21T>a-xu~HAUH?u&ZajWILEBFyC6S%%P@r^BM-N8x
z$HW5Qqc$N^?)VOxFu-?t{j0<xjb#?o^jVlB%ac?BmC#t;vnA86Bv~7~9k^9FrL;UZ
zgSzyFTs_242=!cd(1g7WR{LD7nqB(9N8LJw@vPc;8R7Q|akA`YCA`#eaMe|?fQTYo
z2?Z74x_|#QRkY8YXS3ErhPTcFg_FkOQ_Iy0Fd^<x--I0$@{<MvhTEqV_|Ct3u=NT+
zm0pmjhcJ_s91@Kdd)emo8P9{8e0sO^o!Q6`D#nKT@UgMGjH#CM-wJHZ?+60j?VwY1
zh#|L><n-G2fHyPffLVK~bo-D@U=r>Qp;n<6`BnjNec-bnZ@gs&rsuCt>)WP?ouZ^a
za2wa*?(`2&$iGBn35;_vc1}<=SoE&4>Gq=UwSarp`w|$ITyq|p;u{aRSz*#oGkbCN
zk~>hSo)>r7ul$(l3}kJ5s}@?jZFC?riw_XZ=hdZU*4_{A`Wv9q!$%!ot3A8A#Fup6
z+}4gHx50Iy)+K>3lv$aV>q&l&EK09|*#YFxF%K3x_Ya$Y1V3xUtoU$b*pR%a_(k?b
zKR=*ez`vfsFn;B?s)uEdY}X};RJo<PVn&|XU|H%|FmuTT?Q|T^zc%()D*5sb>pl1=
zqcWPg+P=O|n(?CX`|y<_;^MN;sIsG+*bZbDatb#Esa~OhlDYRT-3H#v(y=`%1x--<
z7|oo$rDEZVxV!&xbj=29Z!>bVwzg%`QITVI4`6uk@j(-`iwL>xlLV^f_g~^5I6b;q
zJw|yHDPoT^x{$6Z8&TUsi_jE(cdBLZUiM`$Ee<Aer25-C1J#<5@*Os94T2vaor#iV
zD|PP6p(T*dYG)hbj~NuGLYqV?Sk8w5Kg_G-nffTi=f08q@Yro5zXrKC88yPBNHP2a
zJ|`NH%YK#@zaq~XNhQLP;`&AMXu{~>#`(y|w?VX|(+l9bn&>g)*6oH$_x*zvx@ub%
zZC>_Y!@`0aNej!xlCuVoXP=?+wpD_j?OFMHa2I#Y=d#vM()-m93dZQf?yPp^X~HKS
zaN}OP4;6^<1}X(qL(`%xdVNU3*u1*O)O^s*V~2wZf>BV~s6Ko}1`E1*yYV$Y-_6Hw
zHu{F0GKa7^{U#7D#j|t|QviYr7O5#IDS3YPxiLaLF+c$>;r`~_p7c-LYp%ItQN`GK
z=L)Xltiu%geH{wfYt70V5i4>%^)lvdTx@)NidH6}@2?dz<6e49bTVA+cm5b}H;GGl
z<k9%%l?#ljKJL$|E7qoi=D|SS=t6=;4FV<_6U?m}#7?S?$0?}&BOsKoWh8*Dx{%dH
zJ<Fwh>@=0#58N4R@H20{!T;H_|AXbfDZI~8+1T-s_Y>BC@%W!zhvl>^A9Csg#P4?W
zQxT_w7C<tLUjflRxco~9SpQytMAXzcmyybUPEMZlpI$Lev^;?B`yKCmt2y4ivP(u>
z_yGWRH8t?CW6_dK#feM+)P7o~jOneBiVHMd8q!V`@l3Q2F>ae>$A{eyAJV(m-J-Ao
zS#yLUoWU@m>ouF&?#Hza;!3e)(Kg88*Ojk+>LkA(lh`Ul(<bi?SUvp9tg+vkQ#bIQ
zH2!%{f_{cOE!g}3y8(@qvaiBcAPiwprbZ02y`5IIi_ue0K`&ZNwAVeU8a!LXQSV`{
ztgF>0lF!%q^m`nfGV^5fMqNMU%i~d2!u7kSm!%7Yec$UDJli{GM3G%rJD@F$NNCJ$
zKkVq@c$E+Ibf*VaDwilv8)jJdO^pU-!9q|Vhxx$AWTm+6B<8x5p8F*!X0gNgF(_{I
z>p?#hMpqMA+>q#hg+Xg4j=hIFE-|#~M!$z$Ce;Mk$?l75g8gPTwFA*%P+5}XTea-)
z8tBNPiBJB(gMWXgO1$HhD_3aoRkvG_?Z@A~Qp(%&On+?TUWlb-vc0Ck@radK&-0w(
z0|ajf<Z`y#3O?jDde1AfAR(0<Me}XKMBDA=OF5cv#RM>xbAkim0~0k5tZ$-xSe$3T
zam?bjo>Pjp8lN3T+5!Vwo9|9V-p;Vc278!h$*qv<-=?w1HiNZQDjRsSd|p8rIufA5
z_YAc{TNS?zhu8*BjN=Z<7b_u4`2|(aob;CHWGhzikPv3^##dwRKH|Uxf2qNh$3SO{
z3(H=8GoN_<Ic9i-Ag}YrHA{lnhVJpJuXUX!crL~A8sfuPe)ip#^`tE;e(#_cPqf+L
z{qZ264)8Tg;Qk=lmr9~OLgHNISIS|K4w@X=u0&Uy;iPl=FCW=!M<t2t3~*=<dy3!2
zpw)~Jz3ToZL|qbo#6&;u>{(|AhEn=lIewx*jFg>85VGQNd-;B3A?c1j+FGmVp<+8y
z$-uhCi&r3~kE{x5k>#?bDC%5<LI|C2=e)^9M^%QTG9i5R#lz^JtATB0`16wOJ82A_
zSK+c${)-kLF(&`B;(i1t+Cg5v!z}pPq9~8j@z`OsBTdX+n`DI-D*fGpU8c2<<8(gs
zQQxfe9H{30%LEcPDz(IJEICJzp5pj9eJ!4f;R%z11V*lW>1#Si(GyFy0n(VaKs_D#
zG&<ywEPfs)9jE4&sid=)T<h*U^R4-6TZ6Id-KPZL3j%KCR^~S&nR%VJ>MohBvGCgr
zet<AVTa1lYug5$D507<0_t{(Q0i}|Yl;6%=l%UO5Kl>%@;+o2Jju{+)u8o#b9&Ijc
z(X0rK%Prbs*MFUAZ_cf1V&4{bZ}$Gc&VXC<g~ndwc(>VpQ`0~`&+4{WcG364wjW>y
z72vxmo52j5GrmQwq}v*3`#J1ka3-YFOzV47arU?wdOv!oG;++F@aNfre277;a<TPY
zVK`^mSNpt`A7^jyjqh!&@*VFbWYfJux^gy{#86#30a8yIjJZu`VF3z3yY9DU1De#5
zUPbS{*BPsEJ=!K2|8!NmJ;)Z2RtV%^Lf1kVbgaA|MGa{b(5(9v+JYK5R>zYxD-^m*
zg7$$Iz|0Q;HF?O60H3TrRwyPVerIJT{yXwKP)AM{y!%h2IbYieK=Q|l0LT-9AJWM$
z!2Sb7d#zH%BV(1O-z0Yq;tuGc04M+V(gh$kqY`Xk?$0Ya?J;h(QI+I^UN)<XYc4;{
zsO|Z60%lU1k}i#42LS1|$m)n58XSD}uS+$)jIj*____9uW@z($oS!1@kCH-blSf8t
z0<grv)7Krig(?X`Jzf^YSpSR4Ezzc&D36T8nic_L3LEuE@H?EKOk<{r7*ooN!y{JO
zN%)H1cnIHu?MO4c<UH|r#iO4G^$Fxx!PIC1{6gH*14C%J&urHtP21S3UgWJQE#a~j
z%QoWfCByTSoZ2@lFj*TfUqWO*^RBAxkfml5@n6@uc&cE5{rE5EEk{A(GK#;}$oCyp
zw<->k#C8|<@5I2BZ&5^Xa@DMwXOB%6&`f&<K4BF*{V2EwfGJ{~m$Qo3Tq2hCiA~!S
zzhL{T24<aTaDmao3ayq~Q;vLiTZ5e?V1hiu70)IQ(3k&>=)@s!CR@h@RChj<MtlgA
zhsy+jWEq$&^BBBPdIQ|;L8vW))0OGV73n)=bRyP(k|BgKcE&$Z0Y=Ja%tW+$jGYPR
zjwWfv1!5jq#NYc=HmE^mQ$t*M`b%NE(lB!yK@5P#)(Mqns6gm_l;xSmDw=Dke7_Oz
z4+)s3n>W{6ordq%xDHG|;5PUGL3)&u)`swnp7euTSM#AP-tvT9JKqmUuEsw2XvR6{
z@VpCY<3B>kt1xf16;AwISSR2DDkMrpDA(7ao}V;PW7cVdT=DxMvb6k!$}h3}Y1e}}
zFGTnGGk{<;_>Dy@Rgw&3(R(T(x&!J<2pjsV195?sPME~FHj1Ez${W6qY8_;}F6nVz
z0~AdEbE{dm=mBM)U(=#=fb&I!0uyFHJ*44YW1X8025lo5P#_zYJTx>k{fpzf(MSPG
zL3Arj^NqZCg(n^sdF#SdBhvGE*5Gm<Ay@dz{D_SZmDI~ok36;gY1YpQVHg$R67;ne
z4D;`wPuCY(V(ZsC_D58Y*8QYMXyPG-d?Zsu%WfbnGyj)=DeV4b#@qvjxyo}vAqctr
zA!D{#(pz*LLMT+9ne(K4(yN;8>W!5<+aDytu6#j4Qh&4Sju6IF<d#aNhE{7wdpn9k
zg&MZ4lj82TQgBTk<MyO%g^o_EroVEeESF$g{Ylu1+JAHEhGHm0yl{8fMV&6bHD{B$
zfgC&o5M*?`@?X5V*z8`_1<F@#T8^PNn^~Gpdz0HleFjpaDhxE6CeE)5AjtK8|5Pmc
zprh>QV85g0Xl~I@)jUaNZJ0q)@`NY?{2J|NX$GtKYNlLVJt|WSF&Bj0m_P%s{PxO!
zx%KB*$|ZnsUWE$Ub5cv!PvQAyy#j2yu1%M!B7SMY5f5&_qRnMv1h}<NI^=dY+!ztx
zq3<}5btOQ;7%{x|Jty|{Sk1!<yYv(z)uB$`<88q3ddG#aw%kY70uG~HMI}elQ$5Zg
zlMp*D%4tPn5<mmA-W9&Gw9uO=FexV^Lmt%dDB1Gs5}2Z|(xPTSSETF=Kx}Z=lD=4)
ziv~&<NY5g+_aqH$5sA{R)n=?uw^2lInaEnmzXHz%ijvBdgVC=);6=?o7fB*KUU~l|
z)!AUR?m{OKs%F2^8kXc8%#_G)pH=_?F(f`M8V-@5?=y}%FuF@c@Qc6`3)&mTuP#?P
zT9DkJoSb{NBjRE@b>ZQ-^Tq==YR<QR*@91#w1js@i!oYe)k_i;fXdymvm4jsoh`J#
zujMlO>41Uu5r1PBGCXh8MMR4^YCig$Am!wLWRxdf=-F|%Z|4P7BY}#Q3<i;{$jQqW
z*8v?8Bdv*j4m9Xe1JKFf$BZ@thx++@0nf1T4HVY4q(TH};=edO7;||=<PbbG^1ywy
z%<?O#JhaU$TwQo{Hw$st(H6r_H#R^#2Xf!C)B=Q*^NNw|c#5h^4@cdtlr^EC^&z|C
zhN8@jRPF|Tc6+mBS~O(h?|PsxNje#B9Meo0sy-C}f$V54uexv4c2qCKX0}o=D<@70
znQ8S&mfJACzZqq8BGYu2Rxi4!^y5I=h%`t0U5vxm4=Ed8&IgEe^##v#BX0s;$L}WN
z`jlw7V?H#SAT%&)Z>N}@dmR3gyI#$Hk*%)t;vUz=O1&|)f~;9&83h^fx`@~B4rmjw
zE|&m+?{J<$S60)A-nc8GTy{Q~=xndEqq48$)g0OvqnQ@ehD{-TdqG@5R3^mMdDX0C
zZ!AAVUcotKyV@Jl5}xP^wj{<v7qhw}TO;{HZRvrMj)h4lZSOE_de5KqRws4gmpK1F
zsu5EXKh%i!Sth>%$nN1;b4Fk6h}Q$Xu>t%Gr;StYSrca#zVF^%4s&4UAsFS`v&vj<
z8`s{5u2m_CVT{Eao2Zn^sP&e`r{}03LGLsJkMA}dQmSni{RI2p26pvS6lCN1>&1kf
zBc==F0-QYTqq+s%dF2q<ky;_GLazKQIyddIfJp_VUP(dwYj228-Nh2i7L9XALZ@E}
z){qQG!20yH0T%e50}d0vnDfTyR~!Xy%_ZI#%oh>2*GL}};_MF&_J{F`7UCI1_Y2Yx
zT8YdS6hg3ZNYg^K_N5nh$%C8jG(TsI0NPo6>+(Mp;#K)sBPa9Ooa4uNx~snnMCzco
zf-pc_e$YF-M{u2DRrdDJb_TV&h&ARwaLX97Maft+f6IrODYOtW8+XU+W<G5bis<QU
zWS1#VHrK6J<*jeOEN0)cX0XX4`pGN*ZI2=nKXMDgq~PirtK9KRvyb#S=aXEzk<lL@
zS9I@K&Y^#2RX#E+_9I)LZ<(6Bsp5!<PYi9sv~Gor1@;|%xpjXK$&)P#Jk1oD94tZI
zbSLYj0C}QPoW`P%y`5F6YG)H%7e~Q?dE6AyTG(v~QXQiP)b`8uBxrv7ROisg_U4jX
z>|E}p{fn$jhr_Q5{sHQjKta65(qZnrQB+Gax?!*$WC;Kf|EZWrTke($C7C3QMgwig
z6WE(yf(nty%<41dO_<fpmb^m>?=x;XDAxHle&d>qBXSHq|9P4oT(fnwLno}WJ0>q;
zzRf!+ql>nj0~2F!sNd1lvM6Km-PPrc0OjN$D*AFR6%$|lACcO_7SzM^KkEaWoGP?$
z0aII-xmf9?Nq$*HNTcy<(3SP<=BQ;D%_Vup@OvLeZ3H!$qvT+Mk7ob|y2r{2S`i+y
z&CnFW5PPJ3whf#1`@f|(<ScVEZ9qCr<pQcYCDQg+pTbP=ftm8{7f4=$u`CRCU^dbf
z0?h9LpHsu%E@}BF-q5~^!AZJ<3}bG-vbs8!TTfOhUj|afE?2wkuGc<ZnXozN@phf%
zFN+jZs;L^0e?jxW)C`zEWXASMSulpETZa-9Oy>u*p)qsRl-_Ebe?>p)&z;7~Om^nC
z6`G3V87(EpN>}b85+=pIWPNiACZDR$v|l_tztu7afiHFOoX_*Tk=e#P0Lf(6!{z)Z
zG;*RKvpCO!`}CA@zPbX9Jp#@Hf95;Ge@`3P(^siJp0??KKZ&QD_obHB47H(W@NDi)
zpi_HQX8Z@Lz)bvrBlRAlH`h@y^~6@gL#o$7H1oyMwW}YkCGw5?9^e|wR})}`VuqBp
zQ?;IuRN_s8ml<x^onHOo(`w~K_Ncz9jG7?TnU8AW4qXoH>>2`;0Bo!f^d;w=?Qp*N
zvmyEAVq^bm)pvs8=Qd@}th*(#8zHLBJC74t=Q)Z;%afPCJ(>y9kn{{z`vvX4JQiYE
zCv%Y+HLs?}-+<oRQbXe{i*g}W1hL0@wuBkn+JoG@za-UA+_-}9&hwOU`>-Ehg?ane
zHTD8kQBiDW&2CS%+bTn(`L5-Z2n`}P;e`=xeQn<PVk+$7(h`$5aQ_0vKLi-?t4@`Q
zKZ@J`Q-+5GO2d+Cr%t$r?@Aq(QOx2plBkjy2ism?vH1sW7SN&`l9xsR34X6EToIF}
zY`rEC$XQ&_Z=8>kOM&E`M0HMp@Mpsh2<R*Ok%IQNuO;27p8;X9;mTXHU+`ci7k_A^
zf5I!tD~t$l1%6IgY~t54>bkh}km6Yz@(eoCABlt?%|6H~8*Eq_-xt^Q;T$g%Ud9`(
zI4K6HJpcP*7*xod@rt<sSGq9o&WGjB_ZggRKqT#w20k6{KUev8N~HN~KQe-_4TjZG
z7%}*E;YV})-&{fcX@aW)jMA@>D+S&v0@U}DFoEm|VqG@#XgpgpJ?H#zw|r>ChwHu7
zmk<b&WYQWy`89BAnTpIFvhZdy#7y*`^ug<qLuyfs0xwF-C*mDFm`h56HWT$*GbUI9
z&)PE#?@}c>0|Lm&Fd@aDC2|0GK4U9rpO68vBA^xHU;*}PSvhE)OPP7d_N#g@@%Nt)
zu;~IQjSO3<)0PXZoQP@HNwxSLGmwW0Dg3zTe<esBpogY>rFh{2qBu@33IC0+EKh@4
zpxItqzI<X)YI{**gXnJEZG6JhQ<3%pk;elo(1?aigwZj)-&d6a>nCYoy~v&PNOr&$
zF3X!e)Vz}P6@4b;71Q<y+S9?VrOOxUqN=Px)9hKLna1u~v-egS+UC`k_S-i3yzi#y
zG8RnrhjO%8N9aM0x#cz`Ex5M?FKFVNUWS6TaVI$^mL(c|&Mnxd2vON4gz`Y(^DYnA
z5@Ac#l7aoz!HHIbX`R9F=<7V7w;SxgJNV!6GQb*QamIi(4b;W5)D__L0qbfAF^sy-
z0=UBUj1`8u@4g1(?Z5EmbQ?`k@e!^vPE@{mCbDFBtnPDyY9(Y#_9DMxg6SB8cCRez
zYV{cjNsJfJ2><3r;t`1no$S#QR#$`}ps3~kXsZpWtzoR9q#3$@al+XUO1As%!Q}=n
z`<7RneCVg|+fXxGvQiVHxfkX}U)PhKTJ!^|mDYKt@W&ba%Gob6=6KvcdEf}D_77y%
zhW4~<dh2nkC9R|SL{vQOJBjg5h3B@Sz=hzPem^guroFlq?NvJcnUv=KFMj<iqVj%{
z3Wapok)b*@CgruzWFXquNUwV7uj9mGn4T5w_i^~AgG7MkeCE{He;wFYKWc^GioFsz
zh0-TkqZ|CH3$=hAx|6Vvm)5NG=~vN4METmV&c7+c|E+C-1^F%q>!~`0NHMmn@j!EU
z1!<z{T<GKEC{<`+a`y!;LP#$D>s)9a--t=v-I0rI;aQ2A?48|qH8Vy<J!UE;nIax2
z1nys~u0Vw7>7?%L@?K947X7VVp)8$c@WPM9<(mGVRxT7Kt;<XqpQ~@nSl`ASdpF-K
zhaDv+t-v3ymSthe+P-P;OhR*VFX&{W>f)Wbss|2WpM-~F``-!!=nh;~J9fSsHB(KY
zk=@|jQ8t5&$fmjK8i}R|xOLU2Cc~l`A7P8pcp&)VNgTo6&~0tTzBADsv71M>@(93{
zag0IeIaT}Zotp2TY<H#kBP$L@NU8_N$9D;cuQTI-7Cuh51HKlg@&dOiVfW2ZQ4S$K
z?g&kDK9#JEp}HyK%tCOO7@Ld3Px$Fr45?zO*=>!pTY(Cl2|qWmcD5sn*GnAZ6sm~H
zpctt#Rw4FfQl5*p0U)Va243~5?QzK=SfCiK$&&7}UrzNyR0agT9ee?Mj(KpW)igQ;
zD?l-dgx5)07?sv|(m*xM%_85-gK18(3xf404m=1@%5c+K3|X%P(U4~y3i7=)+*;g?
zT|@f9eYaEyVJ1Njkw6CNKb@sx)6@b=HFw406~LIjRoijc?`He$_Xqk=aD`fmBlp?&
zV7Kk6=b#A{yITfMW!mOqcJmAn<!D1DJ=Hg;x>uxI)w~AB4a!>+9x*tbJPLr)dZ8jI
z+a>XJa-V5gG{qbleACp;5#d@|t-U8al<ajfQ<i8?)2e`d;N9;|Fm8o1_Z}%e7FRNU
zYl1hBwrt$0sBDKOu%XVD=Byv?a(R{!q78bVcRW<OB7e_J@3tn)0_tCt*1t{YAbB(k
zxbog?59uAS;H?EEVb$DR`^fP_O)Zu=1sjV2x?i~dqdRSL@L`?<deb2ITh0?-g(v?7
z-lLBNmo64XTr)9|wtA`Ln=_AiamcAnZ%^QFt+4TNmci=f;<z`bpR+)tmH81q&^P}Q
zi2*uhK6V>3w?*V5y!HMBPj!Vq^p?<fEA14nHX)`ZDVTDqA#qbNnol5kj!U2MIq4Xg
zH?|bMuIqeI9_oprNq<~e?KP)T5yJ&|bSK*1KadA-G{;qFw#j1_4rRo>##_Xk%Bi1`
z(Ny}nZ8Ha9D1^(gxj=o@A?C78UNt<$F*?^^U%7O5HkkhuBw)J^OfmK-Ai97;#>-+&
zviinH$%xh%a!bp!x7?t<6sQto-s>f!8uR0k-l=Hr7-zy9-~AX}3ciZD=j<*vr_s$X
z!^O;E7SH|p<sWk9M&0wY#TW|_K(*B$*BKcV@1^*<<2w`|83RM&s*Ity3^Efg4ja!r
z@fr==ji&a|xHeY71vQ}^XxpuZN5yP31o_SV=fQvU!CiV;_A(lUrXA9`y7`)b)354_
z9&s@irzTn5xRE&^j$=-|=|}8TEHCdA^|Axo<Y6T_>%aTzTG@u>ozu7Mn(p={-)dv`
z`Pb`aI<%Vn-9qANC3HNe1OTvZ$+t%2lSS;czff3`P#&7iYMmB{78az${S&8qEJ+xH
zN>8XXS8-52{n`GfPCK|5a{E2L#Yq<Qre7<N8~0&7@leDL-duw1JKYV3bt*GQA(2RH
zB<nL$fbd;TqT<86rSGnr(t#@x;Ca^<44Iayu_g*Tk^(U6PxnvfzLT(q3t+rHyvH!#
z!e*d<ao483Oy96a6eF1_7ZV-5zU!-)Dfi+F=?E!?bOQ)z;;!Muponna3`M<44Zp~x
z0&D*|FhUdc2o%?vMwo4~g6hfX2_K~c;>Aq{|0D`8eF+b{0|$ecNH3oBu%klGlp+r1
zmPezQsHFp1U16&QwB@HU(|o-Y*GaszL6_7rb(zJ(F8abLNt4{mTiIU`|4oAcSJLTn
zF<9+zCa%Fb>(<mk;#R#g=X}7edkFx%pFxlFiuuK&9I4xy2Kp#anINK`#TIl6CP&l2
z8ay=gQt)57P`^1!`N--Bal}542P)mPy0eqk6?{}TSn%CN@Yre@oIaqNJY=k5@Q5)E
zFKuW_(n5feD^voqlpC_xo^5B&8AUyT21JK0q`&9C*rOKPFs1$OT``-y>z;;r{n%)(
zR>@rC>Z)!L+Q=+tHhk@=t}*k=9P`coY{)G@kT^-G!Y0%zni`Qu-YA5RKhLj{v6X{d
zwa_gs=rOW&%9XQsL>7)Murlr?8S|Us3B?>S<5B{lRtf_kN+AeP{%4|6e{vXb=kjG(
z$x{bG5uU5k1D^up51Fmgy`gQuwvS(Juv^~pN@9&cH$gif6%vl{eUtA)>6`kUFLfQ7
z=qtZnQd{rIMiZ>KNyA6g6n7O*T2UhmX3+<geLy+FF<43@B+S|RE1|svCYnvHfa&zq
z(5pVe411t#L%s1n0}(E>nvZ<R_Y;j_9vi_{czm)G@d8CKC*&(#iWT=u7qhrRZgFnl
zxSq!j<30VxyyBzZUu8A4yr4e9J`sOF_~KYU)b(MB2lp?Vt`CgKf~2H1o8`_hxw8J^
z;(#q=KE{IK<h}3oL}9$}@JeuEh4=n4wWjrg;+u6(HfItW!F?Q2A<hC<@1hU8f^70l
zde=1jk(70IS`SH2s!mx_b}~6~r7k%Cao!IB>yMb|8J4M%@}NhV&T6z_>utFUj@_Xq
z(hl9MgJ__r#4}|Zvd`<2d2`+g#M>;>*5;vt5Wapr<tHq+QCchU-vKH$d~<zB{{iJ%
z*@^0r(1rmP7X`t2sa%ydt`~qHY$5ZfML+Sy(Um}VJ)3ehJZqGE^)gvuiYE$DAC>`^
zDdmKx<FXkH=W?6@O7;WSA*cTGquTRZhCfP*5Js-8a8O2P&nEa0lty32*f`J)2Koa#
z*W;5`4p4EH8-RxeX?2xF>{U3>-~ORf=8Q!Zch$wIbU1zbKIYXRQ*jmV%npSb;f}n)
zSeYKX(Z?8J<KTA?f%zx(+W)@Sds-tJ$XYt`dM=DY3$~Jj9Iif>(AmCPJ;XO`S<_eY
zp_;utI-L#sg=9{{IOp=D%wFt6IX9(2Exb|Cy!7~-&9YTh*lL2h<1MX92Sc}8PfqWF
zIU(ETV+sanKZ3#dm`^QZ_QN!G&uJ8D7e+EN?3d6g9!881dMDVhRe=bh<~L@pq%B6J
z%F+)%q1@;H1m%w>-12ZF0{6Oqd6d6)xIC6TZvl12T}^!P7sM-lt4D6?-xL<vJB`?Y
z=i7s{i5Tc0$Ol3z|J(gLjH<N%%JTmdyeof2gnnM|w`=!@s{it9PiQ$H<m{b4@xlSr
zhr*;EMeChZgQNRzQLYcjTTmDPZP92j5*&T!A}lCY?R0AYa{bxqIrQ^8>S|!tD5+ZQ
zFe=`J4#1|1V3JRPyt_I(>jX)~c}Hk{*uOvS{>^{(cXxe7SB+MPPq?ggOPnQRv${s%
zPCRq8sz!+2iSZ)e68>%+ECQt0;l1hU=`L=QU*U>h3+hXO*EG@!>~`=`qu-rhW9qC%
zo0L{qDgnC~e(W47y7_BYVXn00yl93AAf<&+C62+ryqGbZ97MifRyV1NmP?xwRJ<aa
zQ~SNgI8%{rE*vhCF=%MROEGn1J6{ONqfLS<F&m(uaj~%+m!uzsr&%LSOIAF8Tc2E#
zD287uV$N?B5qK2)AA1-@hPMYN29XgPCb^AM<af1k6!>3Yc}<4G1j)lviV?*f=_MBF
zc|UwD_1wn(VpECK7o61Zn&fG3W8_$C6q&0`gs-z>TCpWU>L}$v^ymn}XIn}6n|IK#
z;!N{o9r7P%a?42c#N%7sEw|DI6yMw#SCe4<1@I%ld+YMHwzJ#5yZxa=S7&$baD~Nv
z_e=Up$bGxK<wq5%v*;j={dx2opEnpuNJziBUiF~b(q?>azXB+kvb6VQ1Jc@E|72g}
zghrFC5avc(bq(z&Gxmdp-X*?a`)U}i1*SFYx5UX)&&C66eX=nsc{DiwsZG#c@yfzz
zhfqap7j{%iSS&q9c5Hk&m_>!5caLRx^=RTktIKW6FOzqt>X0)vQ|7Ms__(-)G}Mf2
zhJ!BZ^_H%J9Sf_w+gs+*IF=D6->#3Ay1Td>s&9ZyG+JW?WBz2G>>Q@R%;40U>D#)n
zHW3CTtZBE7O18i9m0sHd)B`ynR&tj&2`2x<yQEZkn~b_4a!(Cn{(INwdu!04GCnBO
z^WTXOiUKx0TG$e>v6B+z%U4}qbv_-{7xdD9@ue9#%(>li85|m?P^R31mwp+`b}1+U
z?ESYR`qB{C`?Lh8mrN+-hocSg-E~MO1{3YEXTTm$d0_|^_;rU=AcSo-nXPi&*|2E@
z>Eq5;1zCC$=y<%nJMz$FN#(QY*qU`7&17qS9rA0MekZVkm{3rfut&WcTdh;3VMvS8
z(pV)r4Of*Ms3RijYDD8_B>9(0cXzuLsr3BOV-gAh+}Q1o=3-zM@R?_i<s|YRX?y)I
D*J2vT

diff --git a/src/views/mp/material/components/Waterfall.vue b/src/views/mp/material/components/ImageTable.vue
similarity index 100%
rename from src/views/mp/material/components/Waterfall.vue
rename to src/views/mp/material/components/ImageTable.vue
diff --git a/src/views/mp/material/components/Upload.vue b/src/views/mp/material/components/UploadFile.vue
similarity index 98%
rename from src/views/mp/material/components/Upload.vue
rename to src/views/mp/material/components/UploadFile.vue
index 541dbc20..3ab62224 100644
--- a/src/views/mp/material/components/Upload.vue
+++ b/src/views/mp/material/components/UploadFile.vue
@@ -20,7 +20,6 @@
     </template>
   </el-upload>
 </template>
-
 <script setup lang="ts">
 import type { UploadProps, UploadUserFile } from 'element-plus'
 import {
@@ -66,5 +65,3 @@ const handleUploadSuccess: UploadProps['onSuccess'] = (res: any) => {
   emit('uploaded')
 }
 </script>
-
-<style scoped></style>
diff --git a/src/views/mp/material/components/UploadVideo.vue b/src/views/mp/material/components/UploadVideo.vue
index 5da7d980..816711d1 100644
--- a/src/views/mp/material/components/UploadVideo.vue
+++ b/src/views/mp/material/components/UploadVideo.vue
@@ -123,5 +123,3 @@ const handleUploadSuccess: UploadProps['onSuccess'] = (res: any) => {
   emit('uploaded')
 }
 </script>
-
-<style scoped></style>
diff --git a/src/views/mp/material/components/VideoTable.vue b/src/views/mp/material/components/VideoTable.vue
index 3bd2fe00..81472959 100644
--- a/src/views/mp/material/components/VideoTable.vue
+++ b/src/views/mp/material/components/VideoTable.vue
@@ -57,5 +57,3 @@ const handleDownload = (url: string) => {
   window.open(url, '_blank')
 }
 </script>
-
-<style scoped></style>
diff --git a/src/views/mp/material/components/VoiceTable.vue b/src/views/mp/material/components/VoiceTable.vue
index 44bd01da..6f37e1a0 100644
--- a/src/views/mp/material/components/VoiceTable.vue
+++ b/src/views/mp/material/components/VoiceTable.vue
@@ -49,5 +49,3 @@ const emit = defineEmits<{
   (e: 'delete', v: number)
 }>()
 </script>
-
-<style scoped></style>
diff --git a/src/views/mp/material/components/upload.ts b/src/views/mp/material/components/upload.ts
index 37441f5b..239665a2 100644
--- a/src/views/mp/material/components/upload.ts
+++ b/src/views/mp/material/components/upload.ts
@@ -1,10 +1,9 @@
 import type { UploadProps, UploadRawFile } from 'element-plus'
 import { getAccessToken } from '@/utils/auth'
-
-const message = useMessage()
-
-const HEADERS = { Authorization: 'Bearer ' + getAccessToken() }
-const UPLOAD_URL = 'http://127.0.0.1:8000/upload/' //import.meta.env.VITE_BASE_URL + '/admin-api/mp/material/upload-permanent'
+const message = useMessage() // 消息
+const HEADERS = { Authorization: 'Bearer ' + getAccessToken() } // 请求头
+// const UPLOAD_URL = 'http://127.0.0.1:8000/upload/' // 上传地址
+const UPLOAD_URL = import.meta.env.VITE_BASE_URL + '/admin-api/mp/material/upload-permanent' // 上传地址
 
 enum MaterialType {
   Image = 'image',
@@ -22,7 +21,6 @@ const beforeUpload = (rawFile: UploadRawFile, materialType: MaterialType): boole
   let allowTypes: string[] = []
   let maxSizeMB = 0
   let name = ''
-
   switch (materialType) {
     case MaterialType.Image:
       allowTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/jpg']
@@ -38,18 +36,18 @@ const beforeUpload = (rawFile: UploadRawFile, materialType: MaterialType): boole
       allowTypes = ['video/mp4']
       maxSizeMB = 10
       name = '视频'
+      break
   }
-
+  // 格式不正确
   if (!allowTypes.includes(rawFile.type)) {
     message.error(`上传${name}格式不对!`)
     return false
   }
-
+  // 大小不正确
   if (rawFile.size / 1024 / 1024 > maxSizeMB) {
     message.error(`上传${name}大小不能超过${maxSizeMB}M!`)
     return false
   }
-
   return true
 }
 
diff --git a/src/views/mp/material/index.vue b/src/views/mp/material/index.vue
index dd54cf19..4d8d3707 100644
--- a/src/views/mp/material/index.vue
+++ b/src/views/mp/material/index.vue
@@ -16,14 +16,15 @@
         <template #label>
           <span> <Icon icon="ep:picture" />图片 </span>
         </template>
-        <Upload
+        <UploadFile
           v-hasPermi="['mp:material:upload-permanent']"
           :type="MaterialType.Image"
           @uploaded="getList"
         >
           支持 bmp/png/jpeg/jpg/gif 格式,大小不超过 2M
-        </Upload>
-        <Waterfall :loading="loading" :list="list" @delete="handleDelete" />
+        </UploadFile>
+        <!-- 列表 -->
+        <ImageTable :loading="loading" :list="list" @delete="handleDelete" />
         <!-- 分页组件 -->
         <Pagination
           :total="total"
@@ -38,14 +39,13 @@
         <template #label>
           <span> <Icon icon="ep:microphone" />语音 </span>
         </template>
-        <Upload
+        <UploadFile
           v-hasPermi="['mp:material:upload-permanent']"
           :type="MaterialType.Voice"
           @uploaded="getList"
         >
           格式支持 mp3/wma/wav/amr,文件大小不超过 2M,播放长度不超过 60s
-        </Upload>
-
+        </UploadFile>
         <!-- 列表 -->
         <VoiceTable :list="list" :loading="loading" @delete="handleDelete" />
         <!-- 分页组件 -->
@@ -71,7 +71,6 @@
         >
         <!-- 新建视频的弹窗 -->
         <UploadVideo v-model="showCreateVideo" />
-
         <!-- 列表 -->
         <VideoTable :list="list" :loading="loading" @delete="handleDelete" />
         <!-- 分页组件 -->
@@ -85,21 +84,18 @@
     </el-tabs>
   </ContentWrap>
 </template>
-
 <script lang="ts" setup name="MpMaterial">
 import WxAccountSelect from '@/views/mp/components/wx-account-select/main.vue'
-import Waterfall from './components/Waterfall.vue'
+import ImageTable from './components/ImageTable.vue'
 import VoiceTable from './components/VoiceTable.vue'
 import VideoTable from './components/VideoTable.vue'
-import Upload from './components/Upload.vue'
+import UploadFile from './components/UploadFile.vue'
 import UploadVideo from './components/UploadVideo.vue'
 import { MaterialType } from './components/upload'
 import * as MpMaterialApi from '@/api/mp/material'
+const message = useMessage() // 消息
 
-const message = useMessage()
-
-// 素材类型
-const type = ref<MaterialType>(MaterialType.Image)
+const type = ref<MaterialType>(MaterialType.Image) // 素材类型
 const loading = ref(false) // 遮罩层
 const list = ref<any[]>([]) // 总条数
 const total = ref(0) // 数据列表
@@ -116,9 +112,7 @@ const queryParams: QueryParams = reactive({
   accountId: undefined,
   permanent: true
 })
-
-// === 视频上传,独有变量 ===
-const showCreateVideo = ref(false)
+const showCreateVideo = ref(false) // 是否新建视频的弹窗
 
 /** 侦听公众号变化 **/
 const onAccountChanged = (id?: number) => {
@@ -126,7 +120,6 @@ const onAccountChanged = (id?: number) => {
   getList()
 }
 
-// ======================== 列表查询 ========================
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
@@ -148,21 +141,19 @@ const handleQuery = () => {
   getList()
 }
 
+/** 处理 table 切换 */
 const onTabChange = () => {
-  // 提前情况数据,避免tab切换后显示垃圾数据
+  // 提前情况数据,避免 tab 切换后显示垃圾数据
   list.value = []
   total.value = 0
-
   // 从第一页开始查询
   handleQuery()
 }
 
-// ======================== 其它操作 ========================
+/** 处理删除操作 */
 const handleDelete = async (id: number) => {
   await message.confirm('此操作将永久删除该文件, 是否继续?')
   await MpMaterialApi.deletePermanentMaterial(id)
   message.alertSuccess('删除成功')
 }
 </script>
-
-<style lang="scss" scoped></style>

From e3660e0b20f4515e1c524b079cfc8f6937e288ef Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 17:07:41 +0800
Subject: [PATCH 14/15] =?UTF-8?q?REVIEW=20=E7=AB=99=E5=86=85=E4=BF=A1?=
 =?UTF-8?q?=E6=A8=A1=E7=89=88=E7=9A=84=E5=8F=91=E9=80=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/api/system/notify/template/index.ts       |  23 ++--
 .../notify/template/NotifyTemplateForm.vue    |  13 +-
 .../template/NotifyTemplateSendForm.vue       | 127 ++++++++++++++++++
 src/views/system/notify/template/index.vue    | 117 ++--------------
 4 files changed, 152 insertions(+), 128 deletions(-)
 create mode 100644 src/views/system/notify/template/NotifyTemplateSendForm.vue

diff --git a/src/api/system/notify/template/index.ts b/src/api/system/notify/template/index.ts
index f2bf5d27..50196e85 100644
--- a/src/api/system/notify/template/index.ts
+++ b/src/api/system/notify/template/index.ts
@@ -1,24 +1,17 @@
 import request from '@/config/axios'
 
 export interface NotifyTemplateVO {
-  id: number | null
+  id?: number
   name: string
   nickname: string
   code: string
   content: string
-  type: number | null
+  type: number
   params: string
-  status: number | null
+  status: number
   remark: string
 }
 
-export interface NotifyTemplatePageReqVO extends PageParam {
-  name?: string
-  code?: string
-  status?: number
-  createTime?: Date[]
-}
-
 export interface NotifySendReqVO {
   userId: number | null
   templateCode: string
@@ -26,22 +19,22 @@ export interface NotifySendReqVO {
 }
 
 // 查询站内信模板列表
-export const getNotifyTemplatePageApi = async (params: NotifyTemplatePageReqVO) => {
+export const getNotifyTemplatePage = async (params: PageParam) => {
   return await request.get({ url: '/system/notify-template/page', params })
 }
 
 // 查询站内信模板详情
-export const getNotifyTemplateApi = async (id: number) => {
+export const getNotifyTemplate = async (id: number) => {
   return await request.get({ url: '/system/notify-template/get?id=' + id })
 }
 
 // 新增站内信模板
-export const createNotifyTemplateApi = async (data: NotifyTemplateVO) => {
+export const createNotifyTemplate = async (data: NotifyTemplateVO) => {
   return await request.post({ url: '/system/notify-template/create', data })
 }
 
 // 修改站内信模板
-export const updateNotifyTemplateApi = async (data: NotifyTemplateVO) => {
+export const updateNotifyTemplate = async (data: NotifyTemplateVO) => {
   return await request.put({ url: '/system/notify-template/update', data })
 }
 
@@ -51,6 +44,6 @@ export const deleteNotifyTemplateApi = async (id: number) => {
 }
 
 // 发送站内信
-export const sendNotifyApi = (data: NotifySendReqVO) => {
+export const sendNotify = (data: NotifySendReqVO) => {
   return request.post({ url: '/system/notify-template/send-notify', data })
 }
diff --git a/src/views/system/notify/template/NotifyTemplateForm.vue b/src/views/system/notify/template/NotifyTemplateForm.vue
index d600a59c..55e51ebd 100644
--- a/src/views/system/notify/template/NotifyTemplateForm.vue
+++ b/src/views/system/notify/template/NotifyTemplateForm.vue
@@ -25,7 +25,7 @@
             v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE)"
             :key="dict.value"
             :label="dict.label"
-            :value="parseInt(dict.value)"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -34,7 +34,7 @@
           <el-radio
             v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
             :key="dict.value"
-            :label="parseInt(dict.value as string)"
+            :label="dict.value as string"
           >
             {{ dict.label }}
           </el-radio>
@@ -81,6 +81,7 @@ const formRules = reactive({
 })
 const formRef = ref() // 表单 Ref
 
+/** 打开弹窗 */
 const open = async (type: string, id?: number) => {
   dialogVisible.value = true
   dialogTitle.value = type
@@ -90,7 +91,7 @@ const open = async (type: string, id?: number) => {
   if (id) {
     formLoading.value = true
     try {
-      formData.value = await NotifyTemplateApi.getNotifyTemplateApi(id)
+      formData.value = await NotifyTemplateApi.getNotifyTemplate(id)
     } finally {
       formLoading.value = false
     }
@@ -107,12 +108,12 @@ const submitForm = async () => {
   if (!valid) return
   formLoading.value = true
   try {
-    const data = formData.value as NotifyTemplateApi.NotifyTemplateVO
+    const data = formData.value as unknown as NotifyTemplateApi.NotifyTemplateVO
     if (formType.value === 'create') {
-      await NotifyTemplateApi.createNotifyTemplateApi(data)
+      await NotifyTemplateApi.createNotifyTemplate(data)
       message.success('新增成功')
     } else {
-      await NotifyTemplateApi.updateNotifyTemplateApi(data)
+      await NotifyTemplateApi.updateNotifyTemplate(data)
       message.success('修改成功')
     }
     dialogVisible.value = false
diff --git a/src/views/system/notify/template/NotifyTemplateSendForm.vue b/src/views/system/notify/template/NotifyTemplateSendForm.vue
new file mode 100644
index 00000000..9e292a8d
--- /dev/null
+++ b/src/views/system/notify/template/NotifyTemplateSendForm.vue
@@ -0,0 +1,127 @@
+<template>
+  <Dialog v-model="dialogVisible" title="测试发送" :max-height="500">
+    <el-form
+      ref="formRef"
+      v-loading="formLoading"
+      :model="formData"
+      :rules="formRules"
+      label-width="140px"
+    >
+      <el-form-item label="模板内容" prop="content">
+        <el-input
+          v-model="formData.content"
+          placeholder="请输入模板内容"
+          readonly
+          type="textarea"
+        />
+      </el-form-item>
+      <el-form-item label="接收人" prop="userId">
+        <el-select v-model="formData.userId" placeholder="请选择接收人">
+          <el-option
+            v-for="item in userOption"
+            :key="item.id"
+            :label="item.nickname"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item
+        v-for="param in formData.params"
+        :key="param"
+        :label="'参数 {' + param + '}'"
+        :prop="'templateParams.' + param"
+      >
+        <el-input
+          v-model="formData.templateParams[param]"
+          :placeholder="'请输入 ' + param + ' 参数'"
+        />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
+      <el-button @click="dialogVisible = false">取 消</el-button>
+    </template>
+  </Dialog>
+</template>
+<script lang="ts" name="SystemNotifyTemplateSendForm" setup>
+import * as SmsTemplateApi from '@/api/system/sms/smsTemplate'
+import * as UserApi from '@/api/system/user'
+import * as NotifyTemplateApi from '@/api/system/notify/template'
+const message = useMessage() // 消息弹窗
+
+const dialogVisible = ref(false) // 弹窗的是否展示
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formData = ref({
+  content: '',
+  params: {},
+  userId: null,
+  templateCode: '',
+  templateParams: new Map()
+})
+const formRules = reactive({
+  userId: [{ required: true, message: '用户编号不能为空', trigger: 'change' }],
+  templateCode: [{ required: true, message: '模版编号不能为空', trigger: 'blur' }],
+  templateParams: {}
+})
+const formRef = ref() // 表单 Ref
+const userOption = ref<UserApi.UserVO[]>([])
+
+const open = async (id: number) => {
+  dialogVisible.value = true
+  resetForm()
+  // 设置数据
+  formLoading.value = true
+  try {
+    const data = await NotifyTemplateApi.getNotifyTemplate(id)
+    // 设置动态表单
+    formData.value.content = data.content
+    formData.value.params = data.params
+    formData.value.templateCode = data.code
+    formData.value.templateParams = data.params.reduce((obj, item) => {
+      obj[item] = '' // 给每个动态属性赋值,避免无法读取
+      return obj
+    }, {})
+    formRules.templateParams = data.params.reduce((obj, item) => {
+      obj[item] = { required: true, message: '参数 ' + item + ' 不能为空', trigger: 'blur' }
+      return obj
+    }, {})
+  } finally {
+    formLoading.value = false
+  }
+  // 加载用户列表
+  userOption.value = await UserApi.getSimpleUserList()
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+
+/** 提交表单 */
+const submitForm = async () => {
+  // 校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as SmsTemplateApi.SendSmsReqVO
+    const logId = await SmsTemplateApi.sendSms(data)
+    if (logId) {
+      message.success('提交发送成功!发送结果,见发送日志编号:' + logId)
+    }
+    dialogVisible.value = false
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    content: '',
+    params: {},
+    mobile: '',
+    templateCode: '',
+    templateParams: new Map()
+  }
+  formRef.value?.resetFields()
+}
+</script>
diff --git a/src/views/system/notify/template/index.vue b/src/views/system/notify/template/index.vue
index 9d37befb..6d1938ad 100644
--- a/src/views/system/notify/template/index.vue
+++ b/src/views/system/notify/template/index.vue
@@ -1,8 +1,8 @@
 <template>
   <doc-alert title="站内信配置" url="https://doc.iocoder.cn/notify/" />
 
+  <!-- 搜索工作栏 -->
   <ContentWrap>
-    <!-- 搜索工作栏 -->
     <el-form
       class="-mb-15px"
       :model="queryParams"
@@ -99,7 +99,6 @@
         width="200"
         :show-overflow-tooltip="true"
       />
-
       <el-table-column label="开启状态" align="center" prop="status" width="80">
         <template #default="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
@@ -151,67 +150,22 @@
     />
   </ContentWrap>
 
-  <Dialog v-model="dialogFormVisible" title="测试发送" :max-height="500">
-    <el-form
-      ref="sendFormRef"
-      :model="sendFormData"
-      :rules="sendFormRules"
-      label-width="140px"
-      v-loading="formLoading"
-    >
-      <el-form-item label="模板内容" prop="content">
-        <el-input v-model="sendFormData.content" readonly />
-      </el-form-item>
-      <el-form-item label="接收人" prop="userId">
-        <el-select v-model="sendFormData.userId" placeholder="请选择接收人">
-          <el-option
-            v-for="item in userOption"
-            :key="item.id"
-            :label="item.nickname"
-            :value="item.id"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item
-        v-for="param in sendFormData.params"
-        :key="param"
-        :label="'参数 {' + param + '}'"
-        :prop="'templateParams.' + param"
-      >
-        <el-input
-          v-model="sendFormData.templateParams[param]"
-          :placeholder="'请输入 ' + param + ' 参数'"
-        />
-      </el-form-item>
-    </el-form>
-    <template #footer>
-      <span class="dialog-footer">
-        <el-button @click="dialogFormVisible = false">取消</el-button>
-        <el-button type="primary" @click="submitForm"> 确定 </el-button>
-      </span>
-    </template>
-  </Dialog>
-
   <!-- 表单弹窗:添加/修改 -->
   <NotifyTemplateForm ref="formRef" @success="getList" />
+  <!-- 表单弹窗:测试发送 -->
+  <NotifyTemplateSendForm ref="sendFormRef" />
 </template>
 <script setup lang="ts" name="NotifySmsTemplate">
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import * as NotifyTemplateApi from '@/api/system/notify/template'
-import { getSimpleUserList, UserVO } from '@/api/system/user'
 import NotifyTemplateForm from './NotifyTemplateForm.vue'
-
+import NotifyTemplateSendForm from './NotifyTemplateSendForm.vue'
 const message = useMessage() // 消息弹窗
 
 const loading = ref(false) // 列表的加载中
 const total = ref(0) // 列表的总页数
 const list = ref([]) // 列表的数据
-const queryFormRef = ref() // 搜索的表单
-
-const formLoading = ref(false)
-const dialogFormVisible = ref(false)
-const sendFormRef = ref() // 表单 Ref
 const queryParams = reactive({
   pageNo: 1,
   pageSize: 10,
@@ -220,28 +174,13 @@ const queryParams = reactive({
   code: undefined,
   createTime: []
 })
-
-const sendFormData = ref({
-  content: '',
-  params: {},
-  userId: null,
-  templateCode: '',
-  templateParams: {}
-})
-
-const sendFormRules = ref({
-  userId: [{ required: true, message: '用户编号不能为空', trigger: 'change' }],
-  templateCode: [{ required: true, message: '模版编号不能为空', trigger: 'blur' }],
-  templateParams: {}
-})
-
-const userOption = ref<UserVO[]>([])
+const queryFormRef = ref() // 搜索的表单
 
 /** 查询列表 */
 const getList = async () => {
   loading.value = true
   try {
-    const data = await NotifyTemplateApi.getNotifyTemplatePageApi(queryParams)
+    const data = await NotifyTemplateApi.getNotifyTemplatePage(queryParams)
     list.value = data.list
     total.value = data.total
   } finally {
@@ -280,50 +219,14 @@ const handleDelete = async (id: number) => {
   } catch {}
 }
 
-const openSendForm = (row: any) => {
-  sendFormData.value.content = row.content
-  sendFormData.value.params = row.params
-  sendFormData.value.templateCode = row.code
-  sendFormData.value.templateParams = row.params.reduce(function (obj, item) {
-    obj[item] = undefined
-    return obj
-  }, {})
-  sendFormRules.value.templateParams = row.params.reduce(function (obj, item) {
-    obj[item] = { required: true, message: '参数 ' + item + ' 不能为空', trigger: 'change' }
-    return obj
-  }, {})
-  dialogFormVisible.value = true
-}
-
-/** 提交表单 */
-const submitForm = async () => {
-  // 校验表单
-  if (!sendFormRef) return
-  const valid = await sendFormRef.value.validate()
-  if (!valid) return
-  // 提交请求
-  formLoading.value = true
-  try {
-    const data: NotifyTemplateApi.NotifySendReqVO = {
-      userId: sendFormData.value.userId,
-      templateCode: sendFormData.value.templateCode,
-      templateParams: sendFormData.value.templateParams as unknown as Map<string, Object>
-    }
-    const res = await NotifyTemplateApi.sendNotifyApi(data)
-    if (res) {
-      message.success('提交发送成功!发送结果,见消息记录编号:' + res)
-    }
-    dialogFormVisible.value = false
-  } finally {
-    formLoading.value = false
-  }
+/** 发送站内信按钮 */
+const sendFormRef = ref() // 表单 Ref
+const openSendForm = (row: NotifyTemplateApi.NotifyTemplateVO) => {
+  sendFormRef.value.open(row.id)
 }
 
 /** 初始化 **/
 onMounted(() => {
   getList()
-  getSimpleUserList().then((data) => {
-    userOption.value = data
-  })
 })
 </script>

From 06974ca3c084715d31d36341c230f342cb0ea143 Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Sat, 15 Apr 2023 17:28:33 +0800
Subject: [PATCH 15/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?=
 =?UTF-8?q?=E4=BC=9A=E6=8A=A5=E9=94=99=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/mp/components/wx-editor/WxEditor.vue | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 src/views/mp/components/wx-editor/WxEditor.vue

diff --git a/src/views/mp/components/wx-editor/WxEditor.vue b/src/views/mp/components/wx-editor/WxEditor.vue
deleted file mode 100644
index e69de29b..00000000