Selaa lähdekoodia

完善页面配置必填校验

csk 1 kuukausi sitten
vanhempi
commit
8ef7a1877f

+ 38 - 14
工作空间/产研/权益/汇丰全行/产品原型/pc-demo/src/views/PageAssembly.vue

@@ -156,7 +156,7 @@
 
         <!-- 图片模块 -->
         <template v-if="block.type === 'image'">
-          <div class="block-header"><el-icon><PictureRounded /></el-icon> 图片模块</div>
+          <div class="block-header"><el-icon><PictureRounded /></el-icon> 图片模块 <span class="required-star">*</span></div>
           <div class="block-body">
             <div class="image-upload-area">
               <div class="upload-box upload-box-wide" @click="triggerBlockUpload(bIdx)">
@@ -235,7 +235,8 @@
                 <el-form class="button-form" label-position="top">
                   <el-row :gutter="16">
                     <el-col :span="8">
-                      <el-form-item label="按钮文案">
+                      <el-form-item>
+                        <template #label>按钮文案 <span class="required-star">*</span></template>
                         <el-input v-model="btn.text" size="small" @input="isModified = true" />
                       </el-form-item>
                     </el-col>
@@ -267,17 +268,20 @@
                         <el-radio label="dragon">龙腾</el-radio>
                       </el-radio-group>
                     </el-form-item>
-                    <el-form-item v-if="btn.linkType === 'h5'" label="配置链接">
+                    <el-form-item v-if="btn.linkType === 'h5'">
+                      <template #label>配置链接 <span class="required-star">*</span></template>
                       <el-input v-model="btn.linkH5" size="small" placeholder="例如:https://hsbc.com" @input="handleButtonJumpFieldChange(btn)" />
                     </el-form-item>
                     <el-row v-if="btn.linkType === 'miniProgram'" :gutter="16">
                       <el-col :span="12">
-                        <el-form-item label="AppID">
+                        <el-form-item>
+                          <template #label>AppID <span class="required-star">*</span></template>
                           <el-input v-model="btn.miniAppId" size="small" placeholder="例如:wx1234567890abcdef" @input="handleButtonJumpFieldChange(btn)" />
                         </el-form-item>
                       </el-col>
                       <el-col :span="12">
-                        <el-form-item label="页面路径">
+                        <el-form-item>
+                          <template #label>页面路径 <span class="required-star">*</span></template>
                           <el-input v-model="btn.miniAppPath" size="small" placeholder="例如:pages/index/index" @input="handleButtonJumpFieldChange(btn)" />
                         </el-form-item>
                       </el-col>
@@ -286,10 +290,12 @@
                   <!-- 弹窗配置 -->
                   <div v-if="btn.actionType === 'dialog' && btn.dialog" class="dialog-config">
                     <div class="dialog-config-title"><el-icon><Document /></el-icon> 弹窗内容配置</div>
-                    <el-form-item label="弹窗标题">
+                    <el-form-item>
+                      <template #label>弹窗标题 <span class="required-star">*</span></template>
                       <el-input v-model="btn.dialog.title" size="small" placeholder="弹窗标题" @input="isModified = true" />
                     </el-form-item>
-                    <el-form-item label="弹窗描述">
+                    <el-form-item>
+                      <template #label>弹窗描述 <span class="required-star">*</span></template>
                       <div class="dialog-desc-editor">
                         <quill-editor
                           v-model:content="btn.dialog.desc"
@@ -301,13 +307,13 @@
                     </el-form-item>
                     <div class="dialog-button-config">
                       <div class="confirm-config-header">
-                        <span>左侧取消按钮配置</span>
+                        <span>左侧取消按钮配置 <span class="required-star">*</span></span>
                       </div>
                       <el-input v-model="btn.dialog.cancelText" size="small" placeholder="取消" @input="isModified = true" />
                     </div>
                     <div class="dialog-button-config confirm-button-config">
                       <div class="confirm-config-header">
-                        <span>右侧确认按钮配置</span>
+                        <span>右侧确认按钮配置 <span class="required-star">*</span></span>
                         <el-checkbox v-model="btn.dialog.showConfirm" @change="isModified = true">展示</el-checkbox>
                       </div>
                       <el-input v-if="btn.dialog.showConfirm" v-model="btn.dialog.confirmText" size="small" placeholder="确认" @input="isModified = true" />
@@ -322,17 +328,20 @@
                           <el-radio label="dragon">龙腾</el-radio>
                         </el-radio-group>
                       </el-form-item>
-                      <el-form-item v-if="btn.dialog.confirmLinkType === 'h5'" label="配置链接">
+                      <el-form-item v-if="btn.dialog.confirmLinkType === 'h5'">
+                        <template #label>配置链接 <span class="required-star">*</span></template>
                         <el-input v-model="btn.dialog.confirmLinkH5" size="small" placeholder="例如:https://hsbc.com" @input="handleDialogJumpFieldChange(btn.dialog)" />
                       </el-form-item>
                       <el-row v-if="btn.dialog.confirmLinkType === 'miniProgram'" :gutter="16">
                         <el-col :span="12">
-                          <el-form-item label="AppID">
+                          <el-form-item>
+                            <template #label>AppID <span class="required-star">*</span></template>
                             <el-input v-model="btn.dialog.confirmMiniAppId" size="small" placeholder="例如:wx1234567890abcdef" @input="handleDialogJumpFieldChange(btn.dialog)" />
                           </el-form-item>
                         </el-col>
                         <el-col :span="12">
-                          <el-form-item label="页面路径">
+                          <el-form-item>
+                            <template #label>页面路径 <span class="required-star">*</span></template>
                             <el-input v-model="btn.dialog.confirmMiniAppPath" size="small" placeholder="例如:pages/index/index" @input="handleDialogJumpFieldChange(btn.dialog)" />
                           </el-form-item>
                         </el-col>
@@ -731,12 +740,12 @@ export default {
         if (block.type === 'buttonGroup') {
           block.data.buttons.forEach(btn => {
             if (btn.actionType === 'link' && !this.validateButtonJumpConfig(btn)) hasError = true
-            if (btn.actionType === 'dialog' && btn.dialog && btn.dialog.showConfirm !== false && !this.validateDialogJumpConfig(btn.dialog)) hasError = true
+            if (btn.actionType === 'dialog' && btn.dialog && !this.validateDialogConfig(btn.dialog)) hasError = true
           })
         }
       })
       if (hasError) {
-        ElMessage.error('保存失败:按钮模块中存在未填写完整的跳转链接配置!')
+        ElMessage.error('保存失败:按钮模块中存在未填写完整的弹窗或跳转配置!')
         return
       }
       if (data.shareConfig.enabled) {
@@ -861,6 +870,21 @@ export default {
       }
       return false
     },
+    isRichTextEmpty(value) {
+      const text = String(value || '')
+        .replace(/<[^>]*>/g, '')
+        .replace(/&nbsp;/g, '')
+        .trim()
+      return !text
+    },
+    validateDialogConfig(dialog) {
+      if (!(dialog.title || '').trim()) return false
+      if (this.isRichTextEmpty(dialog.desc)) return false
+      if (!(dialog.cancelText || '').trim()) return false
+      if (dialog.showConfirm === false) return true
+      if (!(dialog.confirmText || '').trim()) return false
+      return this.validateDialogJumpConfig(dialog)
+    },
     validateDialogJumpConfig(dialog) {
       if (this.getPartnerFixedLink(dialog.confirmLinkType)) return true
       if (dialog.confirmLinkType === 'h5') return !!(dialog.confirmLinkH5 || '').trim()

+ 13 - 6
工作空间/产研/权益/汇丰全行/产品原型/pc-demo/src/views/PageHomeConfig.vue

@@ -37,7 +37,8 @@
           </div>
         </template>
         <el-form label-width="80px">
-          <el-form-item label="Tab名称">
+          <el-form-item>
+            <template #label>Tab名称 <span class="required-star">*</span></template>
             <el-input v-model="currentTierData.tabName" placeholder="例如:卓越理财" style="width: 50%" @input="markModified" />
           </el-form-item>
         </el-form>
@@ -51,7 +52,8 @@
           </div>
         </template>
         <el-form class="header-config-form" label-width="130px">
-          <el-form-item label="头图配图">
+          <el-form-item>
+            <template #label>头图配图 <span class="required-star">*</span></template>
             <div class="image-upload-area">
               <div class="upload-box" @click="triggerUpload('header')">
                 <img v-if="currentTierData.header.imageUrl" :src="currentTierData.header.imageUrl" class="preview-img" />
@@ -68,7 +70,8 @@
             </div>
             <input ref="headerUpload" type="file" accept="image/*" style="display:none" @change="onImageUpload($event, 'header')" />
           </el-form-item>
-          <el-form-item label="主标题(粗体)">
+          <el-form-item>
+            <template #label>主标题(粗体) <span class="required-star">*</span></template>
             <el-input v-model="currentTierData.header.mainTitle" @input="markModified" />
           </el-form-item>
           <el-form-item label="副标题(小字)">
@@ -87,12 +90,14 @@
         <el-form label-width="130px">
           <el-row :gutter="20">
             <el-col :span="12">
-              <el-form-item label="已解锁按钮文案">
+              <el-form-item>
+                <template #label>已解锁按钮文案 <span class="required-star">*</span></template>
                 <el-input v-model="currentTierData.buttons.unlocked" placeholder="例如:进入权益专区" @input="markModified" />
               </el-form-item>
             </el-col>
             <el-col :span="12">
-              <el-form-item label="待解锁按钮文案">
+              <el-form-item>
+                <template #label>待解锁按钮文案 <span class="required-star">*</span></template>
                 <el-input v-model="currentTierData.buttons.locked" placeholder="例如:待解锁" @input="markModified" />
               </el-form-item>
             </el-col>
@@ -153,7 +158,8 @@
             </div>
             <div class="privilege-fields">
               <el-form label-width="60px" inline>
-                <el-form-item label="标题">
+                <el-form-item>
+                  <template #label>标题 <span class="required-star">*</span></template>
                   <el-input v-model="item.title" style="width:160px" @input="markModified" />
                 </el-form-item>
                 <el-form-item label="描述">
@@ -385,6 +391,7 @@ export default {
 .toolbar-left { display: flex; align-items: center; gap: 12px; }
 .toolbar-title { margin: 0; font-size: 18px; font-weight: 600; }
 .toolbar-right { display: flex; gap: 8px; }
+.required-star { color: #F56C6C; }
 
 .config-sections { margin-top: 16px; }
 .section-card { margin-bottom: 16px; }

+ 83 - 21
工作空间/产研/权益/汇丰全行/产品原型/pc-demo/src/views/PageZoneConfig.vue

@@ -61,7 +61,7 @@
           class="rule-block"
         >
           <div class="config-field">
-            <div class="config-field-label">账户月内日均余额名称</div>
+            <div class="config-field-label">账户月内日均余额名称 <span class="required-star">*</span></div>
             <el-input
               v-model="configData.identityModule[m.key].avgBalanceName"
               maxlength="20"
@@ -70,17 +70,26 @@
               @input="markModified"
             />
           </div>
-          <div class="config-field">
-            <div class="config-field-label">余额说明</div>
-            <quill-editor
-              v-model:content="configData.identityModule[m.key].avgBalanceRule"
-              content-type="html"
-              :options="quillOptions"
-              @change="markModified"
-            />
-            <div class="config-tip">
-              <el-icon><InfoFilled /></el-icon>
-              <span>移动端对应:用于配置【账户月内日均余额】旁边的“?”提示弹窗内容。</span>
+          <div class="config-field balance-popup-config">
+            <div class="config-field-label">账户余额弹窗提示</div>
+            <div class="balance-popup-field">
+              <div class="balance-popup-label">弹窗顶部名称 <span class="required-star">*</span></div>
+              <el-input
+                v-model="configData.identityModule[m.key].avgBalancePopupTitle"
+                maxlength="20"
+                placeholder="请输入弹窗顶部标题名称"
+                class="balance-popup-title-input"
+                @input="markModified"
+              />
+            </div>
+            <div class="balance-popup-field">
+              <div class="balance-popup-label">账户余额说明 <span class="required-star">*</span></div>
+              <quill-editor
+                v-model:content="configData.identityModule[m.key].avgBalanceRule"
+                content-type="html"
+                :options="quillOptions"
+                @change="markModified"
+              />
             </div>
           </div>
         </div>
@@ -140,7 +149,8 @@
 
           <!-- 标题 -->
           <el-form label-width="80px" style="margin-top:12px">
-            <el-form-item label="主标题">
+            <el-form-item>
+              <template #label>主标题 <span class="required-star">*</span></template>
               <el-input v-model="item.title" @input="markModified" />
             </el-form-item>
             <el-form-item label="副标题">
@@ -169,17 +179,20 @@
                   <el-radio label="dragon">龙腾</el-radio>
                 </el-radio-group>
               </el-form-item>
-              <el-form-item v-if="item.jumpType === 'h5'" label="配置链接">
+              <el-form-item v-if="item.jumpType === 'h5'">
+                <template #label>配置链接 <span class="required-star">*</span></template>
                 <el-input v-model="item.linkH5" placeholder="例如:https://hsbc.com" @input="markModified" />
               </el-form-item>
               <el-row v-if="item.jumpType === 'miniProgram'" :gutter="20">
                 <el-col :span="12">
-                  <el-form-item label="AppID">
+                  <el-form-item>
+                    <template #label>AppID <span class="required-star">*</span></template>
                     <el-input v-model="item.wechatAppId" placeholder="例如:wx1234567890abcdef" @input="markModified" />
                   </el-form-item>
                 </el-col>
                 <el-col :span="12">
-                  <el-form-item label="页面路径">
+                  <el-form-item>
+                    <template #label>页面路径 <span class="required-star">*</span></template>
                     <el-input v-model="item.wechatPath" placeholder="例如:pages/index/index" @input="markModified" />
                   </el-form-item>
                 </el-col>
@@ -232,10 +245,12 @@
             <input :ref="'exchangeUpload' + index" type="file" accept="image/*" style="display:none" @change="onImageUpload($event, 'exchange', index)" />
           </div>
           <el-form label-width="80px" inline class="exchange-fields">
-            <el-form-item label="展示文字">
+            <el-form-item>
+              <template #label>展示文字 <span class="required-star">*</span></template>
               <el-input v-model="item.title" style="width:200px" @input="markModified" />
             </el-form-item>
-            <el-form-item label="跳转链接">
+            <el-form-item>
+              <template #label>跳转链接 <span class="required-star">*</span></template>
               <el-input v-model="item.link" style="width:280px" placeholder="例如:https://test.hsbc.com" @input="markModified" />
             </el-form-item>
           </el-form>
@@ -251,10 +266,12 @@
         </div>
       </template>
       <el-form label-width="120px">
-        <el-form-item label="弹窗顶部名称">
+        <el-form-item>
+          <template #label>弹窗顶部名称 <span class="required-star">*</span></template>
           <el-input v-model="configData.ruleModal.title" style="width:50%" @input="markModified" />
         </el-form-item>
-        <el-form-item label="规则内容">
+        <el-form-item>
+          <template #label>规则内容 <span class="required-star">*</span></template>
           <quill-editor
             v-model:content="configData.ruleModal.content"
             content-type="html"
@@ -377,6 +394,7 @@ export default {
         bgImage: '',
         showAvgBalance: true,
         avgBalanceName: '账户月内日均余额',
+        avgBalancePopupTitle: '',
         avgBalanceRule: '<p></p>'
       }
       return {
@@ -468,6 +486,29 @@ export default {
       }
       return false
     },
+    isRichTextEmpty(value) {
+      const text = String(value || '')
+        .replace(/<[^>]*>/g, '')
+        .replace(/&nbsp;/g, '')
+        .trim()
+      return !text
+    },
+    validateIdentityBalancePopup() {
+      const list = this.identityMscList || []
+      for (const item of list) {
+        const data = this.configData.identityModule?.[item.key]
+        if (!data || item.key === 'privateBank' || !data.showAvgBalance) continue
+        if (!(data.avgBalancePopupTitle || '').trim()) {
+          ElMessage.error(`${item.label} 的账户余额弹窗提示-弹窗顶部名称未填写!`)
+          return false
+        }
+        if (this.isRichTextEmpty(data.avgBalanceRule)) {
+          ElMessage.error(`${item.label} 的账户余额弹窗提示-账户余额说明未填写!`)
+          return false
+        }
+      }
+      return true
+    },
     async fetchData() {
       const res = await request.get('/api/page-config/zone')
       const cfg = res.data.config || {}
@@ -553,6 +594,7 @@ export default {
       this.markModified()
     },
     async handleSave(type) {
+      if (!this.validateIdentityBalancePopup()) return
       this.normalizeCarouselItems(this.configData.adCarousel || [])
       const invalidCarouselIndex = (this.configData.adCarousel || []).findIndex(item => !this.validateJumpConfig(item))
       if (invalidCarouselIndex > -1) {
@@ -592,6 +634,7 @@ export default {
 .toolbar-left { display: flex; align-items: center; gap: 12px; }
 .toolbar-title { margin: 0; font-size: 18px; font-weight: 600; }
 .toolbar-right { display: flex; gap: 8px; }
+.required-star { color: #F56C6C; }
 
 .section-card { margin-bottom: 16px; }
 .section-header { font-weight: 600; }
@@ -747,10 +790,29 @@ export default {
   margin-bottom: 10px;
   line-height: 20px;
 }
-.balance-name-input {
+.balance-name-input,
+.balance-popup-title-input {
   width: 420px;
   max-width: 100%;
 }
+.balance-popup-config {
+  padding: 16px 18px;
+  border: 1px solid #ebeef5;
+  border-radius: 4px;
+  background: #fafafa;
+}
+.balance-popup-field {
+  margin-bottom: 18px;
+}
+.balance-popup-field:last-child {
+  margin-bottom: 0;
+}
+.balance-popup-label {
+  margin-bottom: 8px;
+  color: #303133;
+  font-size: 13px;
+  line-height: 18px;
+}
 .config-tip {
   display: flex;
   align-items: center;