10 Commits c1d8437082 ... dcf54f1ec0

Author SHA1 Message Date
  zdd dcf54f1ec0 Merge branch 'dev' of git.echepei.com:gubersail/gubersail-platform-ui into dev 1 week ago
  yz 581a29143b feat(视图配置): 统一添加searchIndex并调整searchMenuSpan值 1 week ago
  yz 79ddcb8de5 feat(问卷管理): 新增基于avue-crud的问卷管理页面 1 week ago
  yz 2adc867887 style(views): 调整多个视图的样式和布局配置 1 week ago
  yz abd745b086 fix(lead): 优化详情删除功能,添加确认提示和批量删除支持 1 week ago
  yz 3fbd6c649e feat(lead-detail): 添加根据ID删除线索详细信息的接口和类型定义 1 week ago
  yz 08143b843b feat(理赔): 添加提交状态字段及关联功能 1 week ago
  yz 3b2c07c209 feat(理赔): 添加车牌号和轮胎数量字段 1 week ago
  yz 42672d5b31 fix(util): 处理文件大小格式化函数的无效输入 1 week ago
  yz 88a5e35bc0 fix(forecast): 将预测数量默认值从0改为1以改善用户体验 1 week ago

+ 15 - 0
src/api/order/lead-detail.js

@@ -6,9 +6,12 @@ import request from '@/router/axios'
  * @typedef {import('@/api/types/lead-detail').LeadDetailQueryParams} LeadDetailQueryParams
  * @typedef {import('@/api/types/lead-detail').LeadDetailAddParams} LeadDetailAddParams
  * @typedef {import('@/api/types/lead-detail').LeadDetailUpdateParams} LeadDetailUpdateParams
+ * @typedef {import('@/api/types/lead-detail').LeadDetailDeleteParams} LeadDetailDeleteParams
  * @typedef {import('@/api/types/lead-detail').LeadDetailListResponse} LeadDetailListResponse
  * @typedef {import('@/api/types/lead-detail').LeadDetailResponse} LeadDetailResponse
  * @typedef {import('@/api/types/lead-detail').LeadDetailOperationResponse} LeadDetailOperationResponse
+ * @typedef {import('@/api/types/lead-detail').LeadDetailDeleteResponse} LeadDetailDeleteResponse
+ * @typedef {import('@/api/types/lead-detail').DeleteResponse} DeleteResponse
  */
 
 
@@ -83,4 +86,16 @@ export const remove = (ids) => {
       ids
     }
   })
+}
+
+/**
+ * 根据ID删除线索详细信息 (DELETE方法)
+ * @param {string|number} id - 要删除的详细信息ID
+ * @returns {LeadDetailDeleteResponse} 操作结果
+ */
+export const deleteById = (id) => {
+  return request({
+    url: `/api/blade-factory/api/factory/lead-detail/${id}`,
+    method: 'delete'
+  })
 }

+ 6 - 0
src/api/types/claim.d.ts

@@ -102,6 +102,12 @@ export interface ClaimItem {
   updateTime: string;
   /** 备注 */
   remark?: string;
+  /** 车牌号 */
+  vehicleNumber?: string;
+  /** 轮胎数量 */
+  tireQuantity?: number;
+  /** 是否已提交 0-未提交 1-已提交 */
+  isSubmitTime?: number;
 }
 
 /**

+ 28 - 1
src/api/types/lead-detail.d.ts

@@ -41,6 +41,14 @@ export interface LeadDetailUpdateParams extends LeadDetailAddParams {
 }
 
 /**
+ * 根据ID删除参数
+ */
+export interface LeadDetailDeleteParams {
+  /** 详细信息ID */
+  id: string | number;
+}
+
+/**
  * 线索详细信息列表响应
  */
 export type LeadDetailListResponse = Promise<AxiosResponse<ApiResponse<PageResult<LeadDetailRecord>>>>;
@@ -53,4 +61,23 @@ export type LeadDetailResponse = Promise<AxiosResponse<ApiResponse<LeadDetailRec
 /**
  * 线索详细信息操作响应
  */
-export type LeadDetailOperationResponse = Promise<AxiosResponse<ApiResponse<boolean>>>;
+export type LeadDetailOperationResponse = Promise<AxiosResponse<ApiResponse<boolean>>>;
+
+/**
+ * 删除操作的响应类型
+ */
+export interface DeleteResponse {
+  /** 状态码 */
+  code: number;
+  /** 操作是否成功 */
+  success: boolean;
+  /** 返回数据 */
+  data: boolean;
+  /** 响应消息 */
+  msg: string;
+}
+
+/**
+ * 根据ID删除线索详细信息响应
+ */
+export type LeadDetailDeleteResponse = Promise<AxiosResponse<ApiResponse<DeleteResponse>>>;

+ 4 - 4
src/components/forecast-form/forecast-form-mixin.js

@@ -1240,8 +1240,8 @@ export default {
         this.brandDescList = brandList
         // 存储库存列表供选择用,不直接展示到表格
         this.stockDescList = stockList
-        // 默认显示全部物料至下方表格,预测数量默认 0,用户可手动删除不需要的物料
-        this.stockTableData = stockList.map(item => ({ ...item, forecastQuantity: 0 }))
+        // 默认显示全部物料至下方表格,预测数量默认 1,用户可手动删除不需要的物料
+        this.stockTableData = stockList.map(item => ({ ...item, forecastQuantity: 1 }))
         // 根据表格中已有的物料,过滤下拉选项
         this.updateStockSelectOptions()
         // 规范化分页并回显选择(新增模式首次加载)
@@ -1296,8 +1296,8 @@ export default {
         return
       }
 
-      // 添加到表格,默认预测数量为 0
-      this.stockTableData.push({ ...stock, forecastQuantity: 0 })
+      // 添加到表格,默认预测数量为 1
+      this.stockTableData.push({ ...stock, forecastQuantity: 1 })
       // 清空已选
       this.selectedStockId = null
       // 导入后更新下拉选项(过滤掉已在表格中的物料)

+ 1 - 1
src/components/forecast-form/index.js

@@ -340,7 +340,7 @@ export default {
         itemName: '',
         specs: '',
         itemSpecs: '',
-        forecastQuantity: 0,
+        forecastQuantity: 1,
         currentInventory: null,
         approvalStatus: APPROVAL_STATUS.PENDING,
         approvedName: '',

+ 1 - 1
src/constants/forecast.js

@@ -586,7 +586,7 @@ export const DEFAULT_FORECAST_SUMMARY_FORM = {
   itemName: '',
   specs: '',
   itemSpecs: '',
-  forecastQuantity: 0,
+  forecastQuantity: 1,
   currentInventory: 0,
   approvalStatus: APPROVAL_STATUS.PENDING,
   approvedName: '',

+ 374 - 0
src/mixins/survey/surveyCrudMixin.js

@@ -0,0 +1,374 @@
+/**
+ * Survey模块avue-crud配置mixin
+ * @fileoverview 提供基于avue-crud的调查问卷管理功能
+ * @author 开发者
+ * @date 2024-XX-XX
+ */
+
+import {
+  getList,
+  add,
+  update,
+  getDetail
+} from '@/api/survey/survey'
+import {
+  SURVEY_STATUS_OPTIONS,
+  SURVEY_TEMPLATE_OPTIONS,
+  getSurveyStatusLabel,
+  getSurveyStatusType,
+  getSurveyTemplateLabel,
+  getSurveyTemplateType
+} from '@/constants/survey'
+
+export default {
+  data() {
+    return {
+      // avue-crud标准配置
+      option: {
+        height: 'auto',
+        calcHeight: 80,
+        tip: false,
+        searchShow: true,
+        searchMenuSpan: 12,
+        searchIndex: 3,
+        border: true,
+        index: true,
+        viewBtn: true,
+        editBtn: true,
+        delBtn: false, // 暂时禁用删除
+        addBtn: true,
+        selection: false,
+        dialogClickModal: false,
+        menu: true,
+        menuWidth: 200,
+        column: [
+          // 问卷编码列
+          {
+            label: '问卷编码',
+            prop: 'surveyCode',
+            width: 150,
+            search: true,
+            rules: [{
+              required: true,
+              message: '请输入问卷编码',
+              trigger: 'blur'
+            }, {
+              min: 3,
+              max: 50,
+              message: '长度在 3 到 50 个字符',
+              trigger: 'blur'
+            }, {
+              pattern: /^[A-Za-z0-9_-]+$/,
+              message: '只能包含字母、数字、下划线和横线',
+              trigger: 'blur'
+            }]
+          },
+          // 问卷标题列
+          {
+            label: '问卷标题',
+            prop: 'title',
+            minWidth: 200,
+            search: true,
+            overHidden: true,
+            rules: [{
+              required: true,
+              message: '请输入问卷标题',
+              trigger: 'blur'
+            }, {
+              min: 2,
+              max: 100,
+              message: '长度在 2 到 100 个字符',
+              trigger: 'blur'
+            }]
+          },
+          // 问卷描述列
+          {
+            label: '问卷描述',
+            prop: 'description',
+            minWidth: 250,
+            search: false,
+            overHidden: true,
+            type: 'textarea',
+            span: 24,
+            minRows: 3,
+            maxRows: 6,
+            rules: [{
+              required: true,
+              message: '请输入问卷描述',
+              trigger: 'blur'
+            }, {
+              min: 5,
+              max: 500,
+              message: '长度在 5 到 500 个字符',
+              trigger: 'blur'
+            }]
+          },
+          // 状态列
+          {
+            label: '状态',
+            prop: 'status',
+            width: 100,
+            search: true,
+            type: 'select',
+            dicData: SURVEY_STATUS_OPTIONS,
+            slot: true,
+            rules: [{
+              required: true,
+              message: '请选择状态',
+              trigger: 'change'
+            }]
+          },
+          // 是否模板列
+          {
+            label: '是否模板',
+            prop: 'isTemplate',
+            width: 100,
+            search: true,
+            type: 'select',
+            dicData: SURVEY_TEMPLATE_OPTIONS,
+            slot: true
+          },
+          // 开始时间列
+          {
+            label: '开始时间',
+            prop: 'startTime',
+            width: 160,
+            type: 'datetime',
+            format: 'yyyy-MM-dd HH:mm:ss',
+            valueFormat: 'yyyy-MM-dd HH:mm:ss',
+            searchRange: true,
+            search: true,
+            rules: [{
+              required: true,
+              message: '请选择开始时间',
+              trigger: 'change'
+            }]
+          },
+          // 结束时间列
+          {
+            label: '结束时间',
+            prop: 'endTime',
+            width: 160,
+            type: 'datetime',
+            format: 'yyyy-MM-dd HH:mm:ss',
+            valueFormat: 'yyyy-MM-dd HH:mm:ss',
+            searchRange: true,
+            search: true,
+            rules: [{
+              required: true,
+              message: '请选择结束时间',
+              trigger: 'change'
+            }]
+          },
+          // 创建时间列
+          {
+            label: '创建时间',
+            prop: 'createTime',
+            width: 160,
+            type: 'datetime',
+            format: 'yyyy-MM-dd HH:mm:ss',
+            valueFormat: 'yyyy-MM-dd HH:mm:ss',
+            addDisplay: false,
+            editDisplay: false,
+            search: false
+          }
+        ]
+      },
+
+      // 数据和分页
+      data: [],
+      page: {
+        currentPage: 1,
+        pageSize: 20,
+        total: 0
+      },
+
+      // 查询和表单
+      query: {},
+      form: {},
+      loading: true,
+
+      // 题目编辑相关
+      questionEditorVisible: false,
+      currentSurveyId: null,
+
+      // 权限配置
+      permissionList: {
+        addBtn: true,
+        viewBtn: true,
+        editBtn: true,
+        delBtn: false
+      }
+    }
+  },
+
+
+  mounted() {
+    this.onLoad(this.page)
+  },
+
+  methods: {
+    // 导入工具函数
+    getSurveyStatusLabel,
+    getSurveyStatusType,
+    getSurveyTemplateLabel,
+    getSurveyTemplateType,
+
+    // avue-crud标准方法
+    async onLoad(page, params = {}) {
+      this.loading = true
+      try {
+        // 处理时间范围查询
+        const queryParams = { ...params }
+        if (queryParams.startTime && Array.isArray(queryParams.startTime)) {
+          queryParams.startTimeStart = queryParams.startTime[0]
+          queryParams.startTimeEnd = queryParams.startTime[1]
+          delete queryParams.startTime
+        }
+        if (queryParams.endTime && Array.isArray(queryParams.endTime)) {
+          queryParams.endTimeStart = queryParams.endTime[0]
+          queryParams.endTimeEnd = queryParams.endTime[1]
+          delete queryParams.endTime
+        }
+
+        const response = await getList(
+          page.currentPage,
+          page.pageSize,
+          queryParams
+        )
+
+        if (response.data && response.data.success) {
+          const { records, total } = response.data.data
+          this.data = records || []
+          this.page.total = total || 0
+        } else {
+          this.$message.error(response.data?.msg || '获取数据失败')
+        }
+      } catch (error) {
+        console.error('加载数据失败:', error)
+        this.$message.error('加载数据失败,请稍后重试')
+      } finally {
+        this.loading = false
+      }
+    },
+
+    searchChange(params, done) {
+      this.query = params
+      this.onLoad(this.page, params)
+      done()
+    },
+
+    searchReset(done) {
+      this.query = {}
+      this.onLoad(this.page)
+      done()
+    },
+
+
+    currentChange(currentPage) {
+      this.page.currentPage = currentPage
+    },
+
+    sizeChange(pageSize) {
+      this.page.pageSize = pageSize
+    },
+
+    refreshChange() {
+      this.onLoad(this.page, this.query)
+    },
+
+    // CRUD操作
+    async beforeOpen(done, type) {
+      if (['edit', 'view'].includes(type)) {
+        try {
+          const response = await getDetail(this.form.id)
+          if (response.data && response.data.success) {
+            this.form = response.data.data
+          } else {
+            this.$message.error('获取详情失败')
+            return
+          }
+        } catch (error) {
+          console.error('获取详情失败:', error)
+          this.$message.error('获取详情失败')
+          return
+        }
+      }
+      done()
+    },
+
+    async rowSave(row, done, loading) {
+      try {
+        // 时间验证
+        if (new Date(row.startTime) >= new Date(row.endTime)) {
+          this.$message.error('开始时间必须小于结束时间')
+          loading()
+          return
+        }
+
+        const response = await add(row)
+        if (response.data && response.data.success) {
+          this.$message.success('新增问卷成功')
+          this.onLoad(this.page)
+          done()
+        } else {
+          this.$message.error(response.data?.msg || '新增失败')
+          loading()
+        }
+      } catch (error) {
+        console.error('新增失败:', error)
+        this.$message.error('新增失败,请稍后重试')
+        loading()
+      }
+    },
+
+    async rowUpdate(row, index, done, loading) {
+      try {
+        // 时间验证
+        if (new Date(row.startTime) >= new Date(row.endTime)) {
+          this.$message.error('开始时间必须小于结束时间')
+          loading()
+          return
+        }
+
+        const response = await update(row)
+        if (response.data && response.data.success) {
+          this.$message.success('更新问卷成功')
+          this.onLoad(this.page)
+          done()
+        } else {
+          this.$message.error(response.data?.msg || '更新失败')
+          loading()
+        }
+      } catch (error) {
+        console.error('更新失败:', error)
+        this.$message.error('更新失败,请稍后重试')
+        loading()
+      }
+    },
+
+    // 题目编辑功能
+    handleEditQuestions(row) {
+      this.currentSurveyId = row.id
+      this.questionEditorVisible = true
+
+      this.$nextTick(() => {
+        if (this.$refs.questionEditor) {
+          this.$refs.questionEditor.loadQuestionList()
+        }
+      })
+    },
+
+    handleCloseQuestionEditor() {
+      this.questionEditorVisible = false
+      this.currentSurveyId = null
+
+      this.$nextTick(() => {
+        if (this.$refs.questionEditor) {
+          this.$refs.questionEditor = null
+        }
+      })
+    }
+
+  }
+}

+ 1 - 1
src/router/page/index.js

@@ -74,7 +74,7 @@ export default [{
     }]
 
   },
-  {
+    {
     path: '*',
     redirect: '/404'
   }

+ 1 - 1
src/router/views/index.js

@@ -148,7 +148,7 @@ export default [
             {
                 path: "index",
                 name: "调查问卷管理",
-                component: () => import("@/views/survey/index"),
+                component: () => import("@/views/survey/index-avue"),
                 meta: {
                     keepAlive: true,
                     isAuth: true,

+ 5 - 1
src/util/util.js

@@ -368,10 +368,14 @@ export const downloadFileBase64 = (path, name) => {
 
 /**
  * 格式化文件大小
- * @param {number} bytes - 文件大小(字节)
+ * @param {number|null|undefined} bytes - 文件大小(字节)
  * @returns {string} 格式化后的文件大小
  */
 export const formatFileSize = (bytes) => {
+  // 处理null、undefined、非数字值
+  if (bytes === null || bytes === undefined || isNaN(bytes) || bytes < 0) {
+    return '-/-'
+  }
   if (bytes === 0) return '0 B'
   const k = 1024
   const sizes = ['B', 'KB', 'MB', 'GB', 'TB']

+ 4 - 0
src/views/announcement/index.scss

@@ -122,6 +122,10 @@
 }
 
 // 响应式设计
+::v-deep .el-col-md-8 { 
+  width: 24.33333%;
+}
+
 @media (max-width: 768px) {
   .detail-content {
     .detail-info {

+ 6 - 3
src/views/announcement/mixins/announcementIndex.js

@@ -172,10 +172,14 @@ export default {
                 height: 'auto',
                 calcHeight: 30,
                 dialogWidth: 1000,
+                menuWidth: 120,
                 labelWidth: 120,
                 tip: false,
                 searchShow: true,
-                searchMenuSpan: 6,
+                searchMenuSpan: 8,
+                searchIndex: 3,
+                searchIcon: true,
+                align: 'center',
                 border: true,
                 index: true,
                 viewBtn: false,
@@ -188,7 +192,6 @@ export default {
                     {
                         label: "公告标题",
                         prop: "title",
-                        span: 12,
                         search: true,
                         overHidden: true,
                         rules: [{
@@ -208,7 +211,6 @@ export default {
                         },
                         slot: true,
                         search: true,
-                        span: 12,
                         searchProp: "categoryId",
                         rules: [{
                             required: true,
@@ -276,6 +278,7 @@ export default {
                         type: "select",
                         dicData: STATUS_OPTIONS,
                         slot: true,
+                        search: true,
                         addDisplay: true,
                         editDisplay: true,
                         // width: 80

+ 33 - 2
src/views/claim/claimMixin.js

@@ -180,7 +180,8 @@ export default {
         calcHeight: 30,
         tip: false,
         searchShow: true,
-        searchMenuSpan: 6,
+        searchMenuSpan: 12,
+        searchIndex: 3,
         border: true,
         index: true,
         indexLabel: '序号',
@@ -253,6 +254,16 @@ export default {
             prop: 'runMileage'
           },
           {
+            label: '车牌号',
+            prop: 'vehicleNumber',
+            search: true
+          },
+          {
+            label: '轮胎数量',
+            prop: 'tireQuantity',
+            type: 'number'
+          },
+          {
             label: '理赔原因',
             prop: 'claimReason'
           },
@@ -275,6 +286,17 @@ export default {
             type: 'datetime',
             format: 'yyyy-MM-dd HH:mm:ss',
             valueFormat: 'yyyy-MM-dd HH:mm:ss'
+          },
+          {
+            label: '提交状态',
+            prop: 'isSubmitTime',
+            type: 'select',
+            dicData: [
+              { label: '未提交', value: 0 },
+              { label: '已提交', value: 1 }
+            ],
+            search: true,
+            slot: true
           }
         ]
       },
@@ -283,7 +305,16 @@ export default {
     }
   },
   computed: {
-    ...mapGetters(['permission'])
+    ...mapGetters(['permission']),
+    
+    /**
+     * 是否可以新增审核记录
+     * 根据isSubmitTime字段判断:0-不可新增,1-可新增
+     * @returns {boolean} 是否可以新增审核记录
+     */
+    canAddAudit() {
+      return this.currentClaimRow?.isSubmitTime === 1
+    }
   },
   methods: {
     /**

+ 31 - 1
src/views/claim/index.vue

@@ -46,6 +46,11 @@
           {{ getAuditStatusLabel(row.auditStatus) }}
         </el-tag>
       </template>
+      <template slot-scope="{row}" slot="isSubmitTime">
+        <el-tag :type="row.isSubmitTime === 1 ? 'success' : 'warning'">
+          {{ row.isSubmitTime === 1 ? '已提交' : '未提交' }}
+        </el-tag>
+      </template>
     </avue-crud>
 
     <!-- 理赔详情对话框 -->
@@ -163,6 +168,18 @@
                 <span>{{ formatYmd(claimDetail.mountDate) }}</span>
               </div>
             </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>车牌号:</label>
+                <span>{{ claimDetail.vehicleNumber || '-' }}</span>
+              </div>
+            </el-col>
+            <el-col :span="8">
+              <div class="detail-item">
+                <label>轮胎数量:</label>
+                <span>{{ claimDetail.tireQuantity || '-' }}</span>
+              </div>
+            </el-col>
           </el-row>
         </el-card>
 
@@ -307,7 +324,17 @@
                width="1000px"
                append-to-body>
       <div style="margin-bottom: 16px;">
-        <el-button type="primary" size="small" @click="handleAddAudit">新增审核</el-button>
+        <el-button 
+          type="primary" 
+          size="small" 
+          @click="handleAddAudit"
+          :disabled="!canAddAudit"
+          :title="canAddAudit ? '新增审核记录' : '该理赔记录未提交,无法新增审核记录'">
+          新增审核
+        </el-button>
+        <span v-if="!canAddAudit" style="margin-left: 8px; color: #999; font-size: 12px;">
+          该理赔记录未提交,无法新增审核记录
+        </span>
       </div>
       <el-table :data="auditList" v-loading="auditLoading">
         <el-table-column prop="auditResult" label="审核结果" width="100">
@@ -662,4 +689,7 @@ export default {
   }
 }
 
+::v-deep .el-col-md-8 { 
+  width: 24.33333%;
+}
 </style>

+ 2 - 1
src/views/complaint/complaintMixin.js

@@ -177,7 +177,8 @@ export default {
         calcHeight: 30,
         tip: false,
         searchShow: true,
-        searchMenuSpan: 6,
+        searchMenuSpan: 18,
+        searchIndex: 3,
         border: true,
         index: true,
         viewBtn: true,

+ 3 - 0
src/views/complaint/index.vue

@@ -450,4 +450,7 @@ export default {
     }
   }
 }
+::v-deep .el-col-md-8 { 
+  width: 24.33333%;
+}
 </style>

+ 2 - 1
src/views/forecast-audit/auditIndex.js

@@ -63,7 +63,8 @@ export default {
         height: 'auto',
         calcHeight: 30,
         searchShow: true,
-        searchMenuSpan: 6,
+        searchMenuSpan: 18,
+        searchIndex: 3,
         border: true,
         index: false,
         viewBtn: false,

+ 2 - 1
src/views/forecast-summary/summaryIndex.js

@@ -80,7 +80,8 @@ import { safeBigInt } from '@/util/util'
          calcHeight: 30,
          tip: false,
          searchShow: true,
-         searchMenuSpan: 6,
+         searchMenuSpan: 12,
+         searchIndex: 3,
          border: true,
          index: true,
          viewBtn: false,

+ 1 - 0
src/views/image-store-apply/mixins/imageStoreApplyIndex.js

@@ -92,6 +92,7 @@ export default {
         tip: false,
         searchShow: true,
         searchMenuSpan: 6,
+        searchIndex: 3,
         border: true,
         index: true,
         viewBtn: false,

+ 58 - 17
src/views/lead/mixins/leadIndex.js

@@ -1,6 +1,6 @@
 // @ts-check
 import { getList, add, update, getDetail } from '@/api/order/lead'
-import { getList as getDetailList, add as addDetail, update as updateDetail, remove as removeDetail, getDetail as getDetailDetail } from '@/api/order/lead-detail'
+import { getList as getDetailList, add as addDetail, update as updateDetail, deleteById, getDetail as getDetailDetail } from '@/api/order/lead-detail'
 import { getCustomerList } from '@/api/common/index'
 import { mapGetters } from 'vuex'
 import {
@@ -304,6 +304,7 @@ export default {
                 tip: false,
                 searchShow: true,
                 searchMenuSpan: 6,
+                searchIndex: 3,
                 border: true,
                 index: true,
                 viewBtn: true,
@@ -1128,7 +1129,7 @@ export default {
         },
         
         /**
-         * 详细信息删除
+         * 详细信息删除 (单条删除)
          * @param {LeadDetailRecord} row - 行数据
          * @param {number} index - 行索引
          * @returns {Promise<void>}
@@ -1136,16 +1137,25 @@ export default {
          */
         async detailRowDel(row, index) {
             try {
-                const res = await removeDetail(row.id)
-                if (res.data && res.data.success) {
-                    this.$message.success('删除成功')
+                await this.$confirm(`确定删除这条详细信息吗?`, '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                })
+                
+                // 使用deleteById方法进行单条删除
+                const res = await deleteById(row.id)
+                if (res.data && res.data.code === 200 && res.data.success) {
+                    this.$message.success(res.data.msg || '删除成功')
                     this.detailOnLoad(this.detailPage)
                 } else {
                     this.$message.error(res.data ? res.data.msg : '删除失败')
                 }
             } catch (error) {
-                console.error('删除失败:', error)
-                this.$message.error('删除失败,请稍后重试')
+                if (error !== 'cancel') {
+                    console.error('删除失败:', error)
+                    this.$message.error('删除失败,请稍后重试')
+                }
             }
         },
         
@@ -1198,26 +1208,57 @@ export default {
                 this.$message.warning('请选择要删除的数据')
                 return
             }
-        
+
             try {
-                await this.$confirm('确定删除选中的详细信息吗?', '提示', {
+                await this.$confirm(`确定删除选中的 ${this.detailSelectionList.length} 条详细信息吗?`, '提示', {
                     confirmButtonText: '确定',
                     cancelButtonText: '取消',
                     type: 'warning'
                 })
-        
-                const res = await removeDetail(this.detailIds)
-                if (res.data && res.data.success) {
-                    this.$message.success('删除成功')
+
+                // 显示删除进度提示
+                const loadingMessage = this.$message({
+                    message: `正在删除 ${this.detailSelectionList.length} 条记录...`,
+                    type: 'info',
+                    duration: 0
+                })
+
+                try {
+                    // 并发调用deleteById进行批量删除
+                    const deletePromises = this.detailIds.map(id => deleteById(id))
+                    const results = await Promise.all(deletePromises)
+                    
+                    // 统计成功和失败的数量
+                    const successCount = results.filter(res => 
+                        res.data && res.data.code === 200 && res.data.success
+                    ).length
+                    const failedCount = this.detailIds.length - successCount
+
+                    // 关闭进度提示
+                    loadingMessage.close()
+
+                    // 根据结果显示不同的提示
+                    if (failedCount === 0) {
+                        this.$message.success(`成功删除 ${successCount} 条记录`)
+                    } else if (successCount === 0) {
+                        this.$message.error(`删除失败,共 ${failedCount} 条记录`)
+                    } else {
+                        this.$message.warning(`部分删除成功:成功 ${successCount} 条,失败 ${failedCount} 条`)
+                    }
+
+                    // 刷新数据并清空选择
                     this.detailOnLoad(this.detailPage)
                     this.$refs.detailCrud.toggleSelection()
-                } else {
-                    this.$message.error(res.data ? res.data.msg : '删除失败')
+
+                } catch (deleteError) {
+                    loadingMessage.close()
+                    throw deleteError
                 }
+
             } catch (error) {
                 if (error !== 'cancel') {
-                    console.error('删除失败:', error)
-                    this.$message.error('删除失败,请稍后重试')
+                    console.error('批量删除失败:', error)
+                    this.$message.error('批量删除失败,请稍后重试')
                 }
             }
         }

+ 2 - 1
src/views/marketing-activity/mixins/marketingActivityIndex.js

@@ -206,7 +206,8 @@ export default {
                 calcHeight: 30,
                 tip: false,
                 searchShow: true,
-                searchMenuSpan: 6,
+                searchMenuSpan: 18,
+                searchIndex: 3,
                 border: true,
                 index: true,
                 viewBtn: true,

+ 330 - 0
src/views/survey/index-avue.scss

@@ -0,0 +1,330 @@
+// Survey模块avue-crud样式定制
+.survey-management-avue {
+  // 搜索区域样式
+  .avue-crud__search {
+    background: #fff;
+    padding: 20px;
+    border-radius: 4px;
+    margin-bottom: 16px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+    .avue-form {
+      .el-form-item {
+        margin-bottom: 18px;
+
+        .el-form-item__label {
+          font-weight: 500;
+          color: #303133;
+        }
+
+        .el-input,
+        .el-select,
+        .el-date-editor {
+          width: 100%;
+        }
+      }
+    }
+  }
+
+  // 表格区域样式
+  .avue-crud__menu {
+    margin-bottom: 16px;
+    padding: 16px 20px;
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+    .el-button {
+      margin-right: 8px;
+
+      &:last-child {
+        margin-right: 0;
+      }
+    }
+  }
+
+  // 表格样式
+  .avue-crud {
+    background: #fff;
+    border-radius: 4px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+    .el-table {
+      .el-table__header {
+        background-color: #f5f7fa;
+
+        th {
+          background-color: #f5f7fa;
+          color: #606266;
+          font-weight: 600;
+        }
+      }
+
+      .el-table__row {
+        &:hover {
+          background-color: #f5f7fa;
+        }
+      }
+    }
+
+    // 状态标签样式
+    .el-tag {
+      font-weight: 500;
+      border-radius: 4px;
+
+      &.el-tag--success {
+        background-color: #f0f9ff;
+        border-color: #67c23a;
+        color: #67c23a;
+      }
+
+      &.el-tag--warning {
+        background-color: #fdf6ec;
+        border-color: #e6a23c;
+        color: #e6a23c;
+      }
+
+      &.el-tag--info {
+        background-color: #f4f4f5;
+        border-color: #909399;
+        color: #909399;
+      }
+    }
+
+    // 操作按钮样式
+    .el-button--text {
+      padding: 2px 8px;
+      font-size: 12px;
+
+      &:hover {
+        background-color: #f0f9ff;
+        color: #409eff;
+      }
+    }
+  }
+
+  // 分页样式
+  .avue-crud__pagination {
+    padding: 20px 0;
+    text-align: right;
+    background: #fff;
+    border-radius: 4px;
+    margin-top: 16px;
+    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+
+    .el-pagination {
+      .el-pagination__total,
+      .el-pagination__sizes,
+      .el-pagination__jump {
+        color: #606266;
+      }
+    }
+  }
+}
+
+// 题目编辑弹窗样式
+.question-editor-dialog {
+  .el-dialog__header {
+    background-color: #f5f7fa;
+    padding: 16px 20px;
+    border-bottom: 1px solid #e4e7ed;
+
+    .el-dialog__title {
+      font-size: 16px;
+      font-weight: 600;
+      color: #303133;
+    }
+  }
+
+  .el-dialog__body {
+    padding: 10px 20px;
+    max-height: 70vh;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background-color: #c0c4cc;
+      border-radius: 3px;
+    }
+
+    &::-webkit-scrollbar-track {
+      background-color: #f5f7fa;
+      border-radius: 3px;
+    }
+  }
+
+  .el-dialog__footer {
+    padding: 16px 20px;
+    background-color: #f5f7fa;
+    border-top: 1px solid #e4e7ed;
+    text-align: center;
+
+    .el-button {
+      margin: 0 8px;
+      min-width: 80px;
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 1200px) {
+  .survey-management-avue {
+    .avue-crud__search {
+      padding: 15px;
+    }
+
+    .avue-crud__menu {
+      padding: 12px 15px;
+
+      .el-button {
+        margin-bottom: 8px;
+        font-size: 12px;
+      }
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .survey-management-avue {
+    .avue-crud__search {
+      padding: 10px;
+
+      .avue-form {
+        .el-form-item {
+          margin-bottom: 12px;
+        }
+      }
+    }
+
+    .avue-crud__menu {
+      padding: 10px;
+
+      .el-button {
+        width: 100%;
+        margin-bottom: 8px;
+        margin-right: 0;
+      }
+    }
+
+    .avue-crud {
+      .el-table {
+        font-size: 12px;
+
+        .el-table__header th {
+          padding: 8px 4px;
+        }
+
+        .el-table__row td {
+          padding: 8px 4px;
+        }
+      }
+
+      .el-button--text {
+        padding: 4px 6px;
+        font-size: 11px;
+      }
+    }
+
+    .avue-crud__pagination {
+      padding: 15px 0;
+      text-align: center;
+
+      .el-pagination {
+        justify-content: center;
+
+        .el-pagination__sizes,
+        .el-pagination__jump {
+          display: none;
+        }
+      }
+    }
+  }
+
+  .question-editor-dialog {
+    width: 95% !important;
+    margin-top: 5vh !important;
+
+    .el-dialog__body {
+      padding: 8px 15px;
+    }
+  }
+}
+
+@media (max-width: 480px) {
+  .survey-management-avue {
+    .avue-crud__search {
+      .avue-form {
+        .el-form-item {
+          .el-form-item__content {
+            .el-input,
+            .el-select,
+            .el-date-editor {
+              font-size: 14px;
+            }
+          }
+        }
+      }
+    }
+
+    .avue-crud {
+      .el-table {
+        .el-table__header th,
+        .el-table__row td {
+          padding: 6px 2px;
+          font-size: 11px;
+        }
+
+        .cell {
+          padding: 0 2px;
+        }
+      }
+    }
+  }
+}
+
+// 动画效果
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.3s ease;
+}
+
+.fade-enter,
+.fade-leave-to {
+  opacity: 0;
+}
+
+.slide-fade-enter-active {
+  transition: all 0.3s ease;
+}
+
+.slide-fade-leave-active {
+  transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
+}
+
+.slide-fade-enter,
+.slide-fade-leave-to {
+  transform: translateX(10px);
+  opacity: 0;
+}
+
+// 加载状态样式
+.avue-crud {
+  .el-loading-mask {
+    background-color: rgba(255, 255, 255, 0.8);
+
+    .el-loading-spinner {
+      .path {
+        stroke: #409eff;
+      }
+    }
+  }
+}
+
+// 工具提示样式
+.el-tooltip__popper {
+  max-width: 300px;
+  line-height: 1.5;
+}

+ 158 - 0
src/views/survey/index-avue.vue

@@ -0,0 +1,158 @@
+<template>
+  <basic-container>
+    <!-- avue-crud表格组件 -->
+    <avue-crud
+      :option="option"
+      :data="data"
+      ref="crud"
+      v-model="form"
+      :page.sync="page"
+      :permission="permissionList"
+      :before-open="beforeOpen"
+      @row-save="rowSave"
+      @row-update="rowUpdate"
+      @row-del="rowDel"
+      @search-change="searchChange"
+      @search-reset="searchReset"
+      @selection-change="selectionChange"
+      @current-change="currentChange"
+      @size-change="sizeChange"
+      @refresh-change="refreshChange"
+    >
+      <!-- 状态插槽 -->
+      <template slot="status" slot-scope="{row}">
+        <el-tag :type="getSurveyStatusType(row.status)">
+          {{ getSurveyStatusLabel(row.status) }}
+        </el-tag>
+      </template>
+
+      <!-- 是否模板插槽 -->
+      <template slot="isTemplate" slot-scope="{row}">
+        <el-tag :type="getSurveyTemplateType(row.isTemplate)">
+          {{ getSurveyTemplateLabel(row.isTemplate) }}
+        </el-tag>
+      </template>
+
+      <!-- 菜单插槽 -->
+      <template slot="menu" slot-scope="{row}">
+        <el-button
+          type="text"
+          size="small"
+          icon="el-icon-setting"
+          @click="handleEditQuestions(row)"
+        >
+          题目编辑
+        </el-button>
+      </template>
+
+          </avue-crud>
+
+    <!-- 题目编辑弹窗 -->
+    <el-dialog
+      title="题目编辑"
+      :visible.sync="questionEditorVisible"
+      width="90%"
+      append-to-body
+      :close-on-click-modal="false"
+      custom-class="question-editor-dialog"
+      @close="handleCloseQuestionEditor"
+    >
+      <survey-question-editor
+        v-if="questionEditorVisible"
+        :survey-id="currentSurveyId"
+        ref="questionEditor"
+      />
+
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="handleCloseQuestionEditor">关闭</el-button>
+      </div>
+    </el-dialog>
+  </basic-container>
+</template>
+
+<script>
+import surveyCrudMixin from '@/mixins/survey/surveyCrudMixin'
+import SurveyQuestionEditor from '@/components/survey-question-editor'
+
+export default {
+  name: 'SurveyManagementAvue',
+
+  components: {
+    SurveyQuestionEditor
+  },
+
+  mixins: [surveyCrudMixin]
+}
+</script>
+
+<style lang="scss" scoped>
+.survey-management-avue {
+  // 题目编辑弹窗样式
+  ::v-deep .question-editor-dialog {
+    .el-dialog__body {
+      padding: 10px 20px;
+      max-height: 70vh;
+      overflow-y: auto;
+    }
+
+    .el-dialog__footer {
+      padding: 10px 20px 20px;
+      text-align: center;
+    }
+  }
+
+  // avue-crud样式优化
+  ::v-deep .avue-crud {
+    .avue-crud__search {
+      .avue-form {
+        .el-form-item {
+          margin-bottom: 18px;
+        }
+      }
+    }
+
+    .avue-crud__menu {
+      .el-button {
+        margin-right: 8px;
+      }
+    }
+
+    .el-tag {
+      &--success {
+        background-color: #f0f9ff;
+        border-color: #67c23a;
+        color: #67c23a;
+      }
+
+      &--warning {
+        background-color: #fdf6ec;
+        border-color: #e6a23c;
+        color: #e6a23c;
+      }
+
+      &--info {
+        background-color: #f4f4f5;
+        border-color: #909399;
+        color: #909399;
+      }
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .survey-management-avue {
+    ::v-deep .avue-crud {
+      .avue-crud__search {
+        padding: 15px;
+      }
+
+      .avue-crud__menu {
+        .el-button {
+          margin-bottom: 8px;
+        }
+      }
+    }
+  }
+}
+</style>