Переглянути джерело

feat(web): admin 列表页全列排序 - 给所有数据列补齐 sort-header(46 页)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
E2E Test Bot 3 днів тому
батько
коміт
153c74cebf
58 змінених файлів з 1087 додано та 239 видалено
  1. 19 4
      cfc-web/src/views/admin/Activities.vue
  2. 14 3
      cfc-web/src/views/admin/ActivityRegistrationReview.vue
  3. 11 3
      cfc-web/src/views/admin/ActivityReview.vue
  4. 6 2
      cfc-web/src/views/admin/ArticleCategory.vue
  5. 11 3
      cfc-web/src/views/admin/ArticleManage.vue
  6. 11 3
      cfc-web/src/views/admin/BadgeManage.vue
  7. 29 6
      cfc-web/src/views/admin/BaziConfigs.vue
  8. 21 5
      cfc-web/src/views/admin/BloodTypeConfigs.vue
  9. 19 4
      cfc-web/src/views/admin/ButlerAssignments.vue
  10. 56 12
      cfc-web/src/views/admin/CfValueManage.vue
  11. 22 4
      cfc-web/src/views/admin/CouponGrantLog.vue
  12. 11 3
      cfc-web/src/views/admin/CouponManagement.vue
  13. 16 5
      cfc-web/src/views/admin/EcomSupplierManage.vue
  14. 25 6
      cfc-web/src/views/admin/EmotionAlertManage.vue
  15. 11 3
      cfc-web/src/views/admin/EnergyBehaviorConfig.vue
  16. 31 9
      cfc-web/src/views/admin/EnergyRuleManagement.vue
  17. 36 5
      cfc-web/src/views/admin/FileManage.vue
  18. 9 2
      cfc-web/src/views/admin/GrowthTaskManagement.vue
  19. 13 4
      cfc-web/src/views/admin/HealthPlanManage.vue
  20. 62 13
      cfc-web/src/views/admin/InventoryManage.vue
  21. 6 2
      cfc-web/src/views/admin/KnowledgeTag.vue
  22. 23 3
      cfc-web/src/views/admin/MembershipCenter.vue
  23. 20 3
      cfc-web/src/views/admin/NotificationTemplateManage.vue
  24. 10 1
      cfc-web/src/views/admin/NutritionProducts.vue
  25. 16 4
      cfc-web/src/views/admin/PeriodicServiceConfig.vue
  26. 21 5
      cfc-web/src/views/admin/PlanManagement.vue
  27. 14 3
      cfc-web/src/views/admin/PointsLog.vue
  28. 23 5
      cfc-web/src/views/admin/ProblemDomainManage.vue
  29. 7 1
      cfc-web/src/views/admin/ProductManage.vue
  30. 21 5
      cfc-web/src/views/admin/PromotionManagement.vue
  31. 31 4
      cfc-web/src/views/admin/PurchaseManagement.vue
  32. 16 4
      cfc-web/src/views/admin/Recipes.vue
  33. 16 4
      cfc-web/src/views/admin/ReportAutoLearn.vue
  34. 6 2
      cfc-web/src/views/admin/ReportCollectorTrainer.vue
  35. 19 4
      cfc-web/src/views/admin/ReportManagement.vue
  36. 11 3
      cfc-web/src/views/admin/ReportParserImport.vue
  37. 26 6
      cfc-web/src/views/admin/ReportTypeManagement.vue
  38. 16 4
      cfc-web/src/views/admin/ReportUnknownCluster.vue
  39. 12 3
      cfc-web/src/views/admin/SurveyTemplates.vue
  40. 15 2
      cfc-web/src/views/admin/UnifiedHealthReports.vue
  41. 14 5
      cfc-web/src/views/admin/VirtualTeamList.vue
  42. 26 6
      cfc-web/src/views/admin/ZodiacConfigs.vue
  43. 25 4
      cfc-web/src/views/admin/data-source-config.vue
  44. 33 4
      cfc-web/src/views/admin/gates.vue
  45. 21 5
      cfc-web/src/views/admin/health-knowledge.vue
  46. 37 7
      cfc-web/src/views/admin/indicators/index.vue
  47. 11 3
      cfc-web/src/views/admin/review/ActivityAudit.vue
  48. 6 2
      cfc-web/src/views/admin/review/ArticleAudit.vue
  49. 11 3
      cfc-web/src/views/admin/review/ButlerAudit.vue
  50. 16 4
      cfc-web/src/views/admin/review/GuideAudit.vue
  51. 21 5
      cfc-web/src/views/admin/review/HierarchyAudit.vue
  52. 16 4
      cfc-web/src/views/admin/review/NutritionistAudit.vue
  53. 12 2
      cfc-web/src/views/admin/review/PackageAudit.vue
  54. 11 3
      cfc-web/src/views/admin/review/ProductAudit.vue
  55. 16 4
      cfc-web/src/views/admin/review/VendorAudit.vue
  56. 11 3
      cfc-web/src/views/admin/supply-hierarchy/ChangeRequest.vue
  57. 16 4
      cfc-web/src/views/admin/supply-manage/List.vue
  58. 22 4
      cfc-web/src/views/admin/supply-system/List.vue

+ 19 - 4
cfc-web/src/views/admin/Activities.vue

@@ -75,12 +75,19 @@
           </template>
         </el-table-column>
         <el-table-column prop="dimensionCode" label="维度" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('dimensionCode', $event)">维度<span v-if="sortIndex('dimensionCode') !== null" class="sort-index" :class="sortClass('dimensionCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dimensionCode') }}</span>{{ sortIcon('dimensionCode') }}</span>
+          </template>
           <template slot-scope="{ row }">{{ dimensionLabel(row.dimensionCode) }}</template>
         </el-table-column>
         <el-table-column label="类型" width="90">
           <template slot-scope="{ row }">{{ activityTypeLabel(row.activityType) }}</template>
         </el-table-column>
-        <el-table-column prop="location" label="地点" width="120" show-overflow-tooltip />
+        <el-table-column prop="location" label="地点" width="120" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('location', $event)">地点<span v-if="sortIndex('location') !== null" class="sort-index" :class="sortClass('location') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('location') }}</span>{{ sortIcon('location') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="费用(元)" width="90">
           <template slot-scope="{ row }">{{ row.price ? (row.price / 100).toFixed(2) : '免费' }}</template>
         </el-table-column>
@@ -101,8 +108,16 @@
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="startTime" label="开始时间" width="170" />
-        <el-table-column prop="endTime" label="结束时间" width="170" />
+        <el-table-column prop="startTime" label="开始时间" width="170">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('startTime', $event)">开始时间<span v-if="sortIndex('startTime') !== null" class="sort-index" :class="sortClass('startTime') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('startTime') }}</span>{{ sortIcon('startTime') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="endTime" label="结束时间" width="170">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('endTime', $event)">结束时间<span v-if="sortIndex('endTime') !== null" class="sort-index" :class="sortClass('endTime') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('endTime') }}</span>{{ sortIcon('endTime') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="$router.push('/activity-edit?id=' + row.id)">编辑</el-button>
@@ -216,7 +231,7 @@ export default {
       regLoading: false,
       currentActivity: null,
       registrations: [],
-      sortableColumns: { id: 'ID', title: '活动标题', createdAt: '创建时间' }
+      sortableColumns: { id: 'ID', title: '活动标题', dimensionCode: '维度', location: '地点', startTime: '开始时间', endTime: '结束时间', createdAt: '创建时间' }
     }
   },
   created() {

+ 14 - 3
cfc-web/src/views/admin/ActivityRegistrationReview.vue

@@ -23,9 +23,20 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="registrantName" label="报名人" width="100" />
-      <el-table-column prop="registrantPhone" label="手机号" width="120" />
+      <el-table-column prop="registrantName" label="报名人" width="100">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('registrantName', $event)">报名人<span v-if="sortIndex('registrantName') !== null" class="sort-index" :class="sortClass('registrantName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('registrantName') }}</span>{{ sortIcon('registrantName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="registrantPhone" label="手机号" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('registrantPhone', $event)">手机号<span v-if="sortIndex('registrantPhone') !== null" class="sort-index" :class="sortClass('registrantPhone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('registrantPhone') }}</span>{{ sortIcon('registrantPhone') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="status" label="状态" width="90">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+        </template>
         <template slot-scope="{ row }">
           <el-tag :type="row.status === 'approved' ? 'success' : row.status === 'rejected' ? 'danger' : 'warning'">
             {{ row.status === 'approved' ? '已通过' : row.status === 'rejected' ? '已拒绝' : '待审核' }}
@@ -70,7 +81,7 @@ export default {
   mixins: [SortMixin],
   data() {
     return {
-      sortableColumns: { id: 'ID', registeredAt: '报名时间' },
+      sortableColumns: { id: 'ID', registeredAt: '报名时间', registrantName: '报名人', registrantPhone: '手机号', status: '状态' },
       activityList: [],
       list: [],
       loading: false,

+ 11 - 3
cfc-web/src/views/admin/ActivityReview.vue

@@ -29,8 +29,16 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="title" label="活动标题" min-width="200" show-overflow-tooltip />
-      <el-table-column prop="applicant" label="申请人" width="120" />
+      <el-table-column prop="title" label="活动标题" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('title', $event)">活动标题<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="applicant" label="申请人" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('applicant', $event)">申请人<span v-if="sortIndex('applicant') !== null" class="sort-index" :class="sortClass('applicant') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('applicant') }}</span>{{ sortIcon('applicant') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="createdAt" label="申请时间" width="180">
         <template slot="header">
           <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">申请时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
@@ -89,7 +97,7 @@ export default {
   },
   data() {
     return {
-      sortableColumns: { id: 'ID', createdAt: '申请时间' },
+      sortableColumns: { id: 'ID', createdAt: '申请时间', title: '活动标题', applicant: '申请人' },
       loading: false,
       pendingActivities: [],
       filter: {

+ 6 - 2
cfc-web/src/views/admin/ArticleCategory.vue

@@ -31,7 +31,11 @@
             <span style="margin-left: 6px; color: #999;">{{ row.color || '-' }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="sortOrder" label="排序" width="70" />
+        <el-table-column prop="sortOrder" label="排序" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('sortOrder', $event)">排序<span v-if="sortIndex('sortOrder') !== null" class="sort-index" :class="sortClass('sortOrder') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('sortOrder') }}</span>{{ sortIcon('sortOrder') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="状态" width="80">
           <template slot-scope="{ row }">
             <el-tag :type="row.status === 1 || row.status === 'ACTIVE' ? 'success' : 'danger'" size="small">
@@ -109,7 +113,7 @@ export default {
       loading: false,
       submitting: false,
       categories: [],
-      sortableColumns: { id: 'ID', name: '名称' },
+      sortableColumns: { id: 'ID', name: '名称', sortOrder: '排序' },
       dialogVisible: false,
       successDialogVisible: false,
       isEdit: false,

+ 11 - 3
cfc-web/src/views/admin/ArticleManage.vue

@@ -57,7 +57,11 @@
 
       <div class="table-scroll-wrap-lg">
         <el-table :data="list" v-loading="loading" border stripe :max-height="tableHeight">
-          <el-table-column prop="id" label="ID" width="70" />
+          <el-table-column prop="id" label="ID" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="标题" min-width="220">
           <template slot-scope="{ row }">
             <span>{{ row.title }}</span>
@@ -92,7 +96,11 @@
             <span v-else>-</span>
           </template>
         </el-table-column>
-        <el-table-column prop="author" label="作者" width="100" />
+        <el-table-column prop="author" label="作者" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('author', $event)">作者<span v-if="sortIndex('author') !== null" class="sort-index" :class="sortClass('author') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('author') }}</span>{{ sortIcon('author') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="状态" width="100">
           <template slot-scope="{ row }">
             <el-tag v-if="row.status === 'draft' && row.auditStatus === 'pending'" size="small" type="warning">待审核</el-tag>
@@ -346,7 +354,7 @@ export default {
         tagId: '',
         keyword: ''
       },
-      sortableColumns: { viewCount: '阅读' },
+      sortableColumns: { viewCount: '阅读', id: 'ID', author: '作者' },
 
       categories: [],
       tagOptions: [],

+ 11 - 3
cfc-web/src/views/admin/BadgeManage.vue

@@ -32,7 +32,11 @@
           </template>
         </el-table-column>
         <el-table-column prop="name" label="名称" min-width="120" />
-        <el-table-column prop="category" label="分类" width="90" />
+        <el-table-column prop="category" label="分类" width="90">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('category', $event)">分类<span v-if="sortIndex('category') !== null" class="sort-index" :class="sortClass('category') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('category') }}</span>{{ sortIcon('category') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="等级" width="80">
           <template slot-scope="{ row }">
             {{ levelMap[row.level] || row.level || '-' }}
@@ -52,7 +56,11 @@
             />
           </template>
         </el-table-column>
-        <el-table-column prop="sortOrder" label="排序" width="60" align="center" />
+        <el-table-column prop="sortOrder" label="排序" width="60" align="center">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('sortOrder', $event)">排序<span v-if="sortIndex('sortOrder') !== null" class="sort-index" :class="sortClass('sortOrder') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('sortOrder') }}</span>{{ sortIcon('sortOrder') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="createdAt" label="创建时间" width="160">
           <template slot-scope="{ row }">{{ formatTime ? formatTime(row.createdAt) : row.createdAt }}</template>
           <template slot="header">
@@ -213,7 +221,7 @@ export default {
           _needApproval: false
         }
       },
-      sortableColumns: { id: 'ID', createdAt: '创建时间', name: '名称' }
+      sortableColumns: { id: 'ID', name: '名称', category: '分类', sortOrder: '排序', createdAt: '创建时间' }
     }
   },
   mounted() { this.fetchList() },

+ 29 - 6
cfc-web/src/views/admin/BaziConfigs.vue

@@ -15,18 +15,41 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="stemOrBranch" label="天干/地支" width="100"></el-table-column>
+        <el-table-column prop="stemOrBranch" label="天干/地支" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('stemOrBranch', $event)">天干/地支<span v-if="sortIndex('stemOrBranch') !== null" class="sort-index" :class="sortClass('stemOrBranch') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('stemOrBranch') }}</span>{{ sortIcon('stemOrBranch') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="type" label="类型" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('type', $event)">类型<span v-if="sortIndex('type') !== null" class="sort-index" :class="sortClass('type') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('type') }}</span>{{ sortIcon('type') }}</span>
+          </template>
           <template slot-scope="scope">
             <el-tag :type="scope.row.type === 'stem' ? 'primary' : 'success'" size="mini">
               {{ scope.row.type === 'stem' ? '天干' : '地支' }}
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="element" label="五行"></el-table-column>
-        <el-table-column prop="yinYang" label="阴阳"></el-table-column>
-        <el-table-column prop="mindBase" label="心基础分" width="100"></el-table-column>
-        <el-table-column prop="wisdomBase" label="智基础分" width="100"></el-table-column>
+        <el-table-column prop="element" label="五行">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('element', $event)">五行<span v-if="sortIndex('element') !== null" class="sort-index" :class="sortClass('element') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('element') }}</span>{{ sortIcon('element') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="yinYang" label="阴阳">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('yinYang', $event)">阴阳<span v-if="sortIndex('yinYang') !== null" class="sort-index" :class="sortClass('yinYang') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('yinYang') }}</span>{{ sortIcon('yinYang') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="mindBase" label="心基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('mindBase', $event)">心基础分<span v-if="sortIndex('mindBase') !== null" class="sort-index" :class="sortClass('mindBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('mindBase') }}</span>{{ sortIcon('mindBase') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="wisdomBase" label="智基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('wisdomBase', $event)">智基础分<span v-if="sortIndex('wisdomBase') !== null" class="sort-index" :class="sortClass('wisdomBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('wisdomBase') }}</span>{{ sortIcon('wisdomBase') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
@@ -120,7 +143,7 @@ export default {
       successDialogVisible: false,
       isEdit: false,
       form: this.getEmptyForm(),
-      sortableColumns: { id: 'ID' }
+      sortableColumns: { id: 'ID', stemOrBranch: '天干/地支', element: '五行', yinYang: '阴阳', mindBase: '心基础分', wisdomBase: '智基础分' }
     }
   },
   created() {

+ 21 - 5
cfc-web/src/views/admin/BloodTypeConfigs.vue

@@ -14,10 +14,26 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="bloodType" label="血型" width="80"></el-table-column>
-        <el-table-column prop="description" label="性格描述" min-width="200"></el-table-column>
-        <el-table-column prop="mindBase" label="心基础分" width="100"></el-table-column>
-        <el-table-column prop="wisdomBase" label="智基础分" width="100"></el-table-column>
+        <el-table-column prop="bloodType" label="血型" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('bloodType', $event)">血型<span v-if="sortIndex('bloodType') !== null" class="sort-index" :class="sortClass('bloodType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('bloodType') }}</span>{{ sortIcon('bloodType') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="description" label="性格描述" min-width="200">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">性格描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="mindBase" label="心基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('mindBase', $event)">心基础分<span v-if="sortIndex('mindBase') !== null" class="sort-index" :class="sortClass('mindBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('mindBase') }}</span>{{ sortIcon('mindBase') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="wisdomBase" label="智基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('wisdomBase', $event)">智基础分<span v-if="sortIndex('wisdomBase') !== null" class="sort-index" :class="sortClass('wisdomBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('wisdomBase') }}</span>{{ sortIcon('wisdomBase') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
@@ -98,7 +114,7 @@ export default {
       successDialogVisible: false,
       isEdit: false,
       form: this.getEmptyForm(),
-      sortableColumns: { id: 'ID' }
+      sortableColumns: { id: 'ID', bloodType: '血型', description: '性格描述', mindBase: '心基础分', wisdomBase: '智基础分' }
     }
   },
   created() {

+ 19 - 4
cfc-web/src/views/admin/ButlerAssignments.vue

@@ -10,10 +10,25 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="familyId" label="家庭ID" width="100" />
-        <el-table-column prop="butlerNickname" label="管家" min-width="140" />
-        <el-table-column prop="butlerUserId" label="管家用户ID" width="110" />
+        <el-table-column prop="familyId" label="家庭ID" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('familyId', $event)">家庭ID<span v-if="sortIndex('familyId') !== null" class="sort-index" :class="sortClass('familyId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('familyId') }}</span>{{ sortIcon('familyId') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="butlerNickname" label="管家" min-width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('butlerNickname', $event)">管家<span v-if="sortIndex('butlerNickname') !== null" class="sort-index" :class="sortClass('butlerNickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('butlerNickname') }}</span>{{ sortIcon('butlerNickname') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="butlerUserId" label="管家用户ID" width="110">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('butlerUserId', $event)">管家用户ID<span v-if="sortIndex('butlerUserId') !== null" class="sort-index" :class="sortClass('butlerUserId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('butlerUserId') }}</span>{{ sortIcon('butlerUserId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="level" label="订阅级别" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('level', $event)">订阅级别<span v-if="sortIndex('level') !== null" class="sort-index" :class="sortClass('level') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('level') }}</span>{{ sortIcon('level') }}</span>
+          </template>
           <template slot-scope="{ row }">
             <el-tag :type="row.level === 'L2' ? 'warning' : 'info'" size="small">{{ row.level }}</el-tag>
           </template>
@@ -53,7 +68,7 @@ export default {
     return {
       loading: false,
       records: [],
-      sortableColumns: { id: 'ID', assignedAt: '绑定时间' },
+      sortableColumns: { id: 'ID', familyId: '家庭ID', butlerNickname: '管家', butlerUserId: '管家用户ID', level: '订阅级别', assignedAt: '绑定时间' },
       total: 0,
       pageNum: 1,
       pageSize: 10

+ 56 - 12
cfc-web/src/views/admin/CfValueManage.vue

@@ -19,12 +19,36 @@
           <el-table-column label="用户" width="140">
             <template slot-scope="{ row }">{{ row.userName || '用户' + row.userId }}</template>
           </el-table-column>
-          <el-table-column prop="familyId" label="家庭ID" width="100" />
-          <el-table-column prop="totalEarned" label="累计获得" width="100" />
-          <el-table-column prop="available" label="可用" width="80" />
-          <el-table-column prop="frozen" label="冻结" width="80" />
-          <el-table-column prop="withdrawn" label="已提现" width="80" />
-          <el-table-column prop="exchanged" label="已兑换" width="80" />
+          <el-table-column prop="familyId" label="家庭ID" width="100">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('familyId', $event)">家庭ID<span v-if="sortIndex('familyId') !== null" class="sort-index" :class="sortClass('familyId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('familyId') }}</span>{{ sortIcon('familyId') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="totalEarned" label="累计获得" width="100">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('totalEarned', $event)">累计获得<span v-if="sortIndex('totalEarned') !== null" class="sort-index" :class="sortClass('totalEarned') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('totalEarned') }}</span>{{ sortIcon('totalEarned') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="available" label="可用" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('available', $event)">可用<span v-if="sortIndex('available') !== null" class="sort-index" :class="sortClass('available') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('available') }}</span>{{ sortIcon('available') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="frozen" label="冻结" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('frozen', $event)">冻结<span v-if="sortIndex('frozen') !== null" class="sort-index" :class="sortClass('frozen') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('frozen') }}</span>{{ sortIcon('frozen') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="withdrawn" label="已提现" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('withdrawn', $event)">已提现<span v-if="sortIndex('withdrawn') !== null" class="sort-index" :class="sortClass('withdrawn') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('withdrawn') }}</span>{{ sortIcon('withdrawn') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="exchanged" label="已兑换" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('exchanged', $event)">已兑换<span v-if="sortIndex('exchanged') !== null" class="sort-index" :class="sortClass('exchanged') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('exchanged') }}</span>{{ sortIcon('exchanged') }}</span>
+            </template>
+          </el-table-column>
           <el-table-column label="操作" width="100">
             <template slot-scope="{ row }">
               <el-button type="text" size="small" @click="viewLogs(row.userId)">流水</el-button>
@@ -53,11 +77,31 @@
               <el-tag :type="typeTag(row.type)" size="small">{{ row.type }}</el-tag>
             </template>
           </el-table-column>
-          <el-table-column prop="amount" label="数量" width="80" />
-          <el-table-column prop="balanceAfter" label="变动后余额" width="100" />
-          <el-table-column prop="refType" label="来源" width="130" />
-          <el-table-column prop="refId" label="关联ID" width="80" />
-          <el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip />
+          <el-table-column prop="amount" label="数量" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('amount', $event)">数量<span v-if="sortIndex('amount') !== null" class="sort-index" :class="sortClass('amount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('amount') }}</span>{{ sortIcon('amount') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="balanceAfter" label="变动后余额" width="100">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('balanceAfter', $event)">变动后余额<span v-if="sortIndex('balanceAfter') !== null" class="sort-index" :class="sortClass('balanceAfter') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('balanceAfter') }}</span>{{ sortIcon('balanceAfter') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="refType" label="来源" width="130">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('refType', $event)">来源<span v-if="sortIndex('refType') !== null" class="sort-index" :class="sortClass('refType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('refType') }}</span>{{ sortIcon('refType') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="refId" label="关联ID" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('refId', $event)">关联ID<span v-if="sortIndex('refId') !== null" class="sort-index" :class="sortClass('refId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('refId') }}</span>{{ sortIcon('refId') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('remark', $event)">备注<span v-if="sortIndex('remark') !== null" class="sort-index" :class="sortClass('remark') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('remark') }}</span>{{ sortIcon('remark') }}</span>
+            </template>
+          </el-table-column>
           <el-table-column prop="createdAt" label="时间" width="160">
             <template slot="header">
               <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
@@ -81,7 +125,7 @@ export default {
       activeTab: 'balances',
       searchUserId: '',
       logUserId: '',
-      sortableColumns: { id: 'ID', createdAt: '时间' },
+      sortableColumns: { id: 'ID', createdAt: '时间', familyId: '家庭ID', totalEarned: '累计获得', available: '可用', frozen: '冻结', withdrawn: '已提现', exchanged: '已兑换', amount: '数量', balanceAfter: '变动后余额', refType: '来源', refId: '关联ID', remark: '备注' },
       // Balances
       balanceList: [],
       loadingBalance: false,

+ 22 - 4
cfc-web/src/views/admin/CouponGrantLog.vue

@@ -12,11 +12,19 @@
 
       <div class="table-scroll-wrap-sm">
         <el-table :max-height="tableHeight" :data="list" v-loading="loading" border stripe>
-          <el-table-column prop="id" label="ID" width="80" />
+          <el-table-column prop="id" label="ID" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+            </template>
+          </el-table-column>
           <el-table-column label="家庭" width="140">
             <template slot-scope="{ row }">{{ row.familyName || '家庭' + row.familyId }}</template>
           </el-table-column>
-          <el-table-column prop="couponId" label="优惠券ID" width="110" />
+          <el-table-column prop="couponId" label="优惠券ID" width="110">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('couponId', $event)">优惠券ID<span v-if="sortIndex('couponId') !== null" class="sort-index" :class="sortClass('couponId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('couponId') }}</span>{{ sortIcon('couponId') }}</span>
+            </template>
+          </el-table-column>
           <el-table-column label="发放类型" width="120">
             <template slot-scope="{ row }">
               <el-tag size="mini" :type="grantTypeTagType(row.grantType)">{{ grantTypeLabel(row.grantType) }}</el-tag>
@@ -24,10 +32,20 @@
           </el-table-column>
           <el-table-column prop="period" label="周期标识" width="120">
             <template slot-scope="{ row }">{{ row.period || '-' }}</template>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('period', $event)">周期标识<span v-if="sortIndex('period') !== null" class="sort-index" :class="sortClass('period') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('period') }}</span>{{ sortIcon('period') }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="quantity" label="数量" width="80">
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('quantity', $event)">数量<span v-if="sortIndex('quantity') !== null" class="sort-index" :class="sortClass('quantity') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('quantity') }}</span>{{ sortIcon('quantity') }}</span>
+            </template>
           </el-table-column>
-          <el-table-column prop="quantity" label="数量" width="80" />
           <el-table-column prop="source" label="触发来源" min-width="160" show-overflow-tooltip>
             <template slot-scope="{ row }">{{ row.source || '-' }}</template>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('source', $event)">触发来源<span v-if="sortIndex('source') !== null" class="sort-index" :class="sortClass('source') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('source') }}</span>{{ sortIcon('source') }}</span>
+            </template>
           </el-table-column>
           <el-table-column prop="createdAt" label="发放时间" width="180">
             <template slot-scope="{ row }">{{ row.createdAt }}</template>
@@ -72,7 +90,7 @@ export default {
       total: 0,
       familyId: '',
       couponId: '',
-      sortableColumns: { createdAt: '发放时间', id: 'ID' }
+      sortableColumns: { createdAt: '发放时间', id: 'ID', couponId: '优惠券ID', period: '周期标识', quantity: '数量', source: '触发来源' }
     }
   },
   created() {

+ 11 - 3
cfc-web/src/views/admin/CouponManagement.vue

@@ -59,8 +59,16 @@
         <el-table-column label="有效期" width="180">
           <template slot-scope="{ row }">{{ row.validFrom }} ~ {{ row.validUntil }}</template>
         </el-table-column>
-        <el-table-column prop="totalCount" label="总量" width="70" />
-        <el-table-column prop="usedCount" label="已用" width="70" />
+        <el-table-column prop="totalCount" label="总量" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('totalCount', $event)">总量<span v-if="sortIndex('totalCount') !== null" class="sort-index" :class="sortClass('totalCount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('totalCount') }}</span>{{ sortIcon('totalCount') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="usedCount" label="已用" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('usedCount', $event)">已用<span v-if="sortIndex('usedCount') !== null" class="sort-index" :class="sortClass('usedCount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('usedCount') }}</span>{{ sortIcon('usedCount') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="状态" width="80">
           <template slot-scope="{ row }">
             <el-tag :type="row.status !== 'DISABLED' ? 'success' : 'info'" size="mini">
@@ -237,7 +245,7 @@ export default {
       couponOptions: [],
       memberLevelOptions: [],
       keyword: '',
-      sortableColumns: { name: '名称' }
+      sortableColumns: { name: '名称', totalCount: '总量', usedCount: '已用' }
 
     }
   },

+ 16 - 5
cfc-web/src/views/admin/EcomSupplierManage.vue

@@ -20,14 +20,26 @@
           <span class="sort-header" @click.stop="onSortClick('name', $event)">供应商名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="contactName" label="联系人" width="120" />
-      <el-table-column prop="contactPhone" label="联系电话" width="140" />
+      <el-table-column prop="contactName" label="联系人" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('contactName', $event)">联系人<span v-if="sortIndex('contactName') !== null" class="sort-index" :class="sortClass('contactName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('contactName') }}</span>{{ sortIcon('contactName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="contactPhone" label="联系电话" width="140">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('contactPhone', $event)">联系电话<span v-if="sortIndex('contactPhone') !== null" class="sort-index" :class="sortClass('contactPhone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('contactPhone') }}</span>{{ sortIcon('contactPhone') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="启用状态" width="100">
         <template slot-scope="{ row }">
           <el-switch :value="row.status === 1" @change="handleToggle(row)" />
         </template>
       </el-table-column>
-      <el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="remark" label="备注" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('remark', $event)">备注<span v-if="sortIndex('remark') !== null" class="sort-index" :class="sortClass('remark') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('remark') }}</span>{{ sortIcon('remark') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="160" fixed="right">
         <template slot-scope="{ row }">
           <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
@@ -96,13 +108,12 @@ export default {
         status: 1,
         remark: ''
       },
-      sortableColumns: { name: '供应商名称', createdAt: '创建时间', id: 'ID' },
       rules: {
         name: [{ required: true, message: '请输入供应商名称', trigger: 'blur' }],
         contactName: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
         contactPhone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }]
       },
-      sortableColumns: { id: 'ID', name: '供应商名称', createdAt: '创建时间' }
+      sortableColumns: { id: 'ID', name: '供应商名称', contactName: '联系人', contactPhone: '联系电话', remark: '备注' }
     }
   },
   computed: {

+ 25 - 6
cfc-web/src/views/admin/EmotionAlertManage.vue

@@ -10,8 +10,16 @@
       </el-radio-group>
       </div>
     <el-table :max-height="tableHeight" :data="list" v-loading="loading" border stripe>
-      <el-table-column prop="id" label="ID" width="70" />
-      <el-table-column prop="childId" label="孩子ID" width="90" />
+      <el-table-column prop="id" label="ID" width="70">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="childId" label="孩子ID" width="90">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('childId', $event)">孩子ID<span v-if="sortIndex('childId') !== null" class="sort-index" :class="sortClass('childId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('childId') }}</span>{{ sortIcon('childId') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="告警类型" width="140">
         <template slot-scope="{ row }">
           {{ alertTypeLabel(row.alertType) }}
@@ -22,8 +30,16 @@
           <el-tag :type="severityType(row.severity)">{{ severityLabel(row.severity) }}</el-tag>
         </template>
       </el-table-column>
-      <el-table-column prop="title" label="标题" width="180" show-overflow-tooltip />
-      <el-table-column prop="message" label="详情" min-width="220" show-overflow-tooltip />
+      <el-table-column prop="title" label="标题" width="180" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('title', $event)">标题<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="message" label="详情" min-width="220" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('message', $event)">详情<span v-if="sortIndex('message') !== null" class="sort-index" :class="sortClass('message') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('message') }}</span>{{ sortIcon('message') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="状态" width="80">
         <template slot-scope="{ row }">
           <el-tag :type="row.resolved ? 'success' : 'danger'" size="small">
@@ -36,13 +52,16 @@
           {{ formatTime(row.createdAt) }}
         </template>
         <template slot="header">
-          <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">@dblclick.stop="onSortToggle('createdAt')">创建时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
+          <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">创建时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="处理时间" width="160">
         <template slot-scope="{ row }">
           {{ row.resolvedAt ? formatTime(row.resolvedAt) : '-' }}
         </template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('resolvedAt', $event)">处理时间<span v-if="sortIndex('resolvedAt') !== null" class="sort-index" :class="sortClass('resolvedAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('resolvedAt') }}</span>{{ sortIcon('resolvedAt') }}</span>
+        </template>
       </el-table-column>
       <el-table-column label="操作" width="160" fixed="right">
         <template slot-scope="{ row }">
@@ -90,7 +109,7 @@ export default {
       total: 0,
       keyword: '',
       resolvedFilter: '',
-      sortableColumns: { createdAt: '创建时间' }
+      sortableColumns: { id: 'ID', childId: '孩子ID', title: '标题', message: '详情', createdAt: '创建时间', resolvedAt: '处理时间' }
     }
   },
   mounted() {

+ 11 - 3
cfc-web/src/views/admin/EnergyBehaviorConfig.vue

@@ -18,8 +18,16 @@
           <span class="sort-header" @click.stop="onSortClick('behaviorCode', $event)">行为编码<span v-if="sortIndex('behaviorCode') !== null" class="sort-index" :class="sortClass('behaviorCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('behaviorCode') }}</span>{{ sortIcon('behaviorCode') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="behaviorName" label="行为名称" width="130" />
-      <el-table-column prop="description" label="描述" min-width="160" show-overflow-tooltip />
+      <el-table-column prop="behaviorName" label="行为名称" width="130">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('behaviorName', $event)">行为名称<span v-if="sortIndex('behaviorName') !== null" class="sort-index" :class="sortClass('behaviorName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('behaviorName') }}</span>{{ sortIcon('behaviorName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="description" label="描述" min-width="160" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="默认值" width="80">
         <template slot-scope="{ row }">
           <el-tag size="mini" type="info">{{ row.defaultAmount }}</el-tag>
@@ -156,7 +164,7 @@ export default {
       form: {},
       dimAssignList: [],
       dimensions: Object.entries(DIMENSION_MAP).map(([code, v]) => ({ code, name: v.name })),
-      sortableColumns: { behaviorCode: '行为编码', createdAt: '创建时间' }
+      sortableColumns: { behaviorCode: '行为编码', behaviorName: '行为名称', description: '描述' }
     }
   },
   mounted() {

+ 31 - 9
cfc-web/src/views/admin/EnergyRuleManagement.vue

@@ -12,16 +12,36 @@
       </div>
       </div>
     <el-table :max-height="tableHeight" :data="list" v-loading="loading" border stripe>
-      <el-table-column prop="id" label="ID" width="60" />
+      <el-table-column prop="id" label="ID" width="60">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="ruleCode" label="规则编码" width="140">
         <template slot="header">
           <span class="sort-header" @click.stop="onSortClick('ruleCode', $event)">规则编码<span v-if="sortIndex('ruleCode') !== null" class="sort-index" :class="sortClass('ruleCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('ruleCode') }}</span>{{ sortIcon('ruleCode') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="ruleName" label="规则名称" min-width="160" show-overflow-tooltip />
-      <el-table-column prop="eventType" label="事件类型" width="120" />
-      <el-table-column prop="dimensionCode" label="维度" width="80" />
-      <el-table-column prop="amount" label="能量值" width="80" />
+      <el-table-column prop="ruleName" label="规则名称" min-width="160" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('ruleName', $event)">规则名称<span v-if="sortIndex('ruleName') !== null" class="sort-index" :class="sortClass('ruleName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('ruleName') }}</span>{{ sortIcon('ruleName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="eventType" label="事件类型" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('eventType', $event)">事件类型<span v-if="sortIndex('eventType') !== null" class="sort-index" :class="sortClass('eventType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('eventType') }}</span>{{ sortIcon('eventType') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="dimensionCode" label="维度" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('dimensionCode', $event)">维度<span v-if="sortIndex('dimensionCode') !== null" class="sort-index" :class="sortClass('dimensionCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dimensionCode') }}</span>{{ sortIcon('dimensionCode') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="amount" label="能量值" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('amount', $event)">能量值<span v-if="sortIndex('amount') !== null" class="sort-index" :class="sortClass('amount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('amount') }}</span>{{ sortIcon('amount') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="优先级" width="70">
         <template slot-scope="{ row }">
           <el-tag size="mini">{{ row.priority || 0 }}</el-tag>
@@ -32,7 +52,11 @@
           <el-switch :value="row.status === 1" @change="toggleStatus(row)" />
         </template>
       </el-table-column>
-      <el-table-column prop="description" label="描述" min-width="140" show-overflow-tooltip />
+      <el-table-column prop="description" label="描述" min-width="140" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="160" fixed="right">
         <template slot-scope="{ row }">
           <el-button size="mini" type="primary" @click="showDialog(row)">编辑</el-button>
@@ -108,7 +132,6 @@ import { getEnergyRuleList, createEnergyRule, updateEnergyRule, deleteEnergyRule
 export default {
   mixins: [SortMixin],
   name: 'EnergyRuleManagement',
-  mixins: [SortMixin],
   computed: {
     tableHeight() {
       return window.innerHeight - 300
@@ -127,8 +150,7 @@ export default {
       dialogVisible: false,
       saving: false,
       form: this.getEmptyForm(),
-      sortableColumns: { id: 'ID', ruleCode: '规则编码', createdAt: '创建时间' },
-      sortableColumns: { ruleCode: '规则编码', createdAt: '创建时间', id: 'ID' }
+      sortableColumns: { id: 'ID', ruleCode: '规则编码', ruleName: '规则名称', eventType: '事件类型', dimensionCode: '维度', amount: '能量值', description: '描述' }
     }
   },
   mounted() {

+ 36 - 5
cfc-web/src/views/admin/FileManage.vue

@@ -53,7 +53,11 @@
       </div>
 
       <el-table :data="tableData" border stripe v-loading="loading" style="margin-top:16px">
-        <el-table-column prop="id" label="ID" width="70"></el-table-column>
+        <el-table-column prop="id" label="ID" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="预览" width="70">
           <template slot-scope="scope">
             <el-image v-if="scope.row.fileType === 'image'" :src="scope.row.url" style="width:40px;height:40px;border-radius:4px" fit="cover" :preview-src-list="[scope.row.url]"></el-image>
@@ -63,23 +67,41 @@
             <i v-else class="el-icon-document" style="font-size:28px;color:#909399;display:block;text-align:center"></i>
           </template>
         </el-table-column>
-        <el-table-column prop="originalFilename" label="文件名" min-width="180" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="originalFilename" label="文件名" min-width="180" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('originalFilename', $event)">文件名<span v-if="sortIndex('originalFilename') !== null" class="sort-index" :class="sortClass('originalFilename') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('originalFilename') }}</span>{{ sortIcon('originalFilename') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="fileType" label="类型" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('fileType', $event)">类型<span v-if="sortIndex('fileType') !== null" class="sort-index" :class="sortClass('fileType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('fileType') }}</span>{{ sortIcon('fileType') }}</span>
+          </template>
           <template slot-scope="scope">
             <el-tag size="mini" :type="typeTag(scope.row.fileType)">{{ scope.row.fileType || '?' }}</el-tag>
           </template>
         </el-table-column>
         <el-table-column prop="fileSize" label="大小" width="90">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('fileSize', $event)">大小<span v-if="sortIndex('fileSize') !== null" class="sort-index" :class="sortClass('fileSize') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('fileSize') }}</span>{{ sortIcon('fileSize') }}</span>
+          </template>
           <template slot-scope="scope">{{ formatSize(scope.row.fileSize) }}</template>
         </el-table-column>
-        <el-table-column prop="category" label="分类" width="110"></el-table-column>
+        <el-table-column prop="category" label="分类" width="110">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('category', $event)">分类<span v-if="sortIndex('category') !== null" class="sort-index" :class="sortClass('category') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('category') }}</span>{{ sortIcon('category') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="标签" min-width="140">
           <template slot-scope="scope">
             <el-tag v-for="t in (scope.row.tags || [])" :key="t.id" size="mini" style="margin-right:4px;margin-bottom:2px;border:0" :style="{ backgroundColor: t.color + '22', color: t.color }">{{ t.name }}</el-tag>
             <span v-if="!scope.row.tags || scope.row.tags.length === 0" class="no-tag">-</span>
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" min-width="120" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="description" label="描述" min-width="120" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="createdAt" label="上传时间" width="160">
           <template slot-scope="scope">{{ scope.row.createdAt }}</template>
           <template slot="header">
@@ -135,7 +157,7 @@ export default {
       query: { page: 1, pageSize: 20, category: '', fileType: '', tagIds: [], search: '', dateFrom: '', dateTo: '' },
       editVisible: false, saving: false,
       editForm: { id: null, url: '', originalFilename: '', description: '', tagIds: [] },
-      sortableColumns: { createdAt: '上传时间' }
+      sortableColumns: { id: 'ID', originalFilename: '文件名', fileType: '类型', fileSize: '大小', category: '分类', description: '描述', createdAt: '上传时间' }
     }
   },
   mounted() { this.loadStats(); this.loadTags(); this.loadData() },
@@ -194,5 +216,14 @@ export default {
 .stat-card { text-align: center; }
 .stat-value { font-size: 24px; font-weight: bold; color: #303133; }
 .stat-label { font-size: 12px; color: #909399; margin-top: 4px; }
+.sort-header {
+  cursor: pointer;
+  user-select: none;
+  font-weight: 500;
+  font-size: 12px;
+}
+.sort-header:hover {
+  color: #409eff;
+}
 .no-tag { color: #C0C4CC; }
 </style>

+ 9 - 2
cfc-web/src/views/admin/GrowthTaskManagement.vue

@@ -32,6 +32,9 @@
           </template>
         </el-table-column>
         <el-table-column prop="dimensionCode" label="关联维度" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('dimensionCode', $event)">关联维度<span v-if="sortIndex('dimensionCode') !== null" class="sort-index" :class="sortClass('dimensionCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dimensionCode') }}</span>{{ sortIcon('dimensionCode') }}</span>
+          </template>
           <template slot-scope="{ row }">
             <el-tag size="mini" :type="dimensionType(row.dimensionCode)">{{ dimensionLabel(row.dimensionCode) }}</el-tag>
           </template>
@@ -40,7 +43,11 @@
         <el-table-column label="触发方式" width="80">
           <template slot-scope="{ row }">{{ row.triggerType || '—' }}</template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" min-width="180" show-overflow-tooltip />
+        <el-table-column prop="description" label="描述" min-width="180" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="任务值" width="80">
           <template slot-scope="{ row }">{{ row.taskValue ?? '-' }}</template>
         </el-table-column>
@@ -203,7 +210,7 @@ export default {
         size: 10
       },
       form: {},
-      sortableColumns: { id: 'ID', name: '任务名称' }
+      sortableColumns: { id: 'ID', name: '任务名称', dimensionCode: '关联维度', description: '描述' }
     }
   },
   methods: {

+ 13 - 4
cfc-web/src/views/admin/HealthPlanManage.vue

@@ -18,9 +18,15 @@
       <el-table-column prop="id" label="方案ID" width="80" />
       <el-table-column prop="familyName" label="家庭" width="140">
         <template slot-scope="{ row }">{{ row.familyName || row.familyId }}</template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('familyName', $event)">家庭<span v-if="sortIndex('familyName') !== null" class="sort-index" :class="sortClass('familyName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('familyName') }}</span>{{ sortIcon('familyName') }}</span>
+        </template>
       </el-table-column>
       <el-table-column prop="memberName" label="成员" width="120">
         <template slot-scope="{ row }">{{ row.memberName || row.memberIds || '-' }}</template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('memberName', $event)">成员<span v-if="sortIndex('memberName') !== null" class="sort-index" :class="sortClass('memberName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('memberName') }}</span>{{ sortIcon('memberName') }}</span>
+        </template>
       </el-table-column>
       <el-table-column label="维度" width="160">
         <template slot-scope="{ row }">
@@ -39,12 +45,15 @@
       </el-table-column>
       <el-table-column prop="reviewComment" label="审核意见" width="150">
         <template slot-scope="{ row }">{{ row.reviewComment || '-' }}</template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('reviewComment', $event)">审核意见<span v-if="sortIndex('reviewComment') !== null" class="sort-index" :class="sortClass('reviewComment') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('reviewComment') }}</span>{{ sortIcon('reviewComment') }}</span>
+        </template>
       </el-table-column>
       <el-table-column prop="createdAt" label="创建时间" width="160">
         <template slot-scope="{ row }">{{ formatTime(row.createdAt) }}</template>
-        <template slot="header">
-          <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">@dblclick.stop="onSortToggle('createdAt')">创建时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
-        </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">创建时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
+          </template>
       </el-table-column>
       <el-table-column label="操作" width="100">
         <template slot-scope="{ row }">
@@ -140,7 +149,7 @@ export default {
       detailLoading: false,
       tasks: [],
       tasksLoading: false,
-      sortableColumns: { createdAt: '创建时间', id: '方案ID' }
+      sortableColumns: { id: '方案ID', familyName: '家庭', memberName: '成员', reviewComment: '审核意见', createdAt: '创建时间' }
     }
   },
   created() {

+ 62 - 13
cfc-web/src/views/admin/InventoryManage.vue

@@ -39,8 +39,16 @@
                 <span :style="{ color: row.direction === 1 ? '#67c23a' : '#f56c6c' }">{{ row.direction === 1 ? '+' : '-' }}{{ row.quantity }}</span>
               </template>
             </el-table-column>
-            <el-table-column prop="beforeStock" label="变动前" width="70" />
-            <el-table-column prop="afterStock" label="变动后" width="70" />
+            <el-table-column prop="beforeStock" label="变动前" width="70">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('beforeStock', $event)">变动前<span v-if="sortIndex('beforeStock') !== null" class="sort-index" :class="sortClass('beforeStock') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('beforeStock') }}</span>{{ sortIcon('beforeStock') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="afterStock" label="变动后" width="70">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('afterStock', $event)">变动后<span v-if="sortIndex('afterStock') !== null" class="sort-index" :class="sortClass('afterStock') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('afterStock') }}</span>{{ sortIcon('afterStock') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
             <el-table-column prop="createdAt" label="时间" width="160">
               <template slot-scope="{ row }">{{ formatTime ? formatTime(row.createdAt) : row.createdAt }}</template>
@@ -55,15 +63,27 @@
         <!-- 入库单 -->
         <el-tab-pane label="入库单" name="inbound">
           <el-table :data="inboundList" v-loading="inboundLoading" border stripe max-height="500">
-            <el-table-column prop="orderNo" label="入库单号" width="180" />
-            <el-table-column prop="supplierName" label="供应商" width="120" />
+            <el-table-column prop="orderNo" label="入库单号" width="180">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('orderNo', $event)">入库单号<span v-if="sortIndex('orderNo') !== null" class="sort-index" :class="sortClass('orderNo') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('orderNo') }}</span>{{ sortIcon('orderNo') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="supplierName" label="供应商" width="120">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('supplierName', $event)">供应商<span v-if="sortIndex('supplierName') !== null" class="sort-index" :class="sortClass('supplierName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('supplierName') }}</span>{{ sortIcon('supplierName') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="入库日期" width="100">
               <template slot-scope="{ row }">{{ row.inboundDate || '-' }}</template>
             </el-table-column>
             <el-table-column label="总金额" width="100">
               <template slot-scope="{ row }">{{ row.totalAmount ? '¥' + (row.totalAmount / 100).toFixed(2) : '-' }}</template>
             </el-table-column>
-            <el-table-column prop="totalItems" label="商品项数" width="80" />
+            <el-table-column prop="totalItems" label="商品项数" width="80">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('totalItems', $event)">商品项数<span v-if="sortIndex('totalItems') !== null" class="sort-index" :class="sortClass('totalItems') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('totalItems') }}</span>{{ sortIcon('totalItems') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="状态" width="90">
               <template slot-scope="{ row }">
                 <el-tag :type="row.status === 'completed' ? 'success' : row.status === 'cancelled' ? 'info' : 'warning'" size="mini">
@@ -71,7 +91,12 @@
                 </el-tag>
               </template>
             </el-table-column>
-            <el-table-column prop="createdAt" label="创建时间" width="160" />
+            <el-table-column prop="createdAt" label="创建时间" width="160">
+              <template slot-scope="{ row }">{{ formatTime ? formatTime(row.createdAt) : row.createdAt }}</template>
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">创建时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="操作" width="200" fixed="right">
               <template slot-scope="{ row }">
                 <el-button size="mini" @click="showInboundDetail(row)">详情</el-button>
@@ -102,15 +127,27 @@
         <el-tab-pane label="出库单" name="outbound">
           <el-button type="primary" size="mini" @click="showCreateOutbound = true" style="margin-bottom:12px;">新建出库单</el-button>
           <el-table :data="outboundList" v-loading="outboundLoading" border stripe max-height="500">
-            <el-table-column prop="id" label="ID" width="60" />
+            <el-table-column prop="id" label="ID" width="60">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="商品" min-width="150">
               <template slot-scope="{ row }">{{ row.productName || 'ID:' + row.productId }}</template>
             </el-table-column>
             <el-table-column label="数量" width="70">
               <template slot-scope="{ row }"><span style="color:#f56c6c;">-{{ row.quantity }}</span></template>
             </el-table-column>
-            <el-table-column prop="remark" label="出库原因" min-width="200" show-overflow-tooltip />
-            <el-table-column prop="createdAt" label="时间" width="160" />
+            <el-table-column prop="remark" label="出库原因" min-width="200" show-overflow-tooltip>
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('remark', $event)">出库原因<span v-if="sortIndex('remark') !== null" class="sort-index" :class="sortClass('remark') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('remark') }}</span>{{ sortIcon('remark') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="createdAt" label="时间" width="160">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
+              </template>
+            </el-table-column>
           </el-table>
           <el-pagination @size-change="outboundPageSize=$event;loadOutboundList()" @current-change="outboundPage=$event;loadOutboundList()" :current-page="outboundPage" :page-sizes="[10,20,50]" :page-size="outboundPageSize" :total="outboundTotal" layout="total, sizes, prev, pager, next, jumper" class="pagination-wrap" />
         </el-tab-pane>
@@ -119,7 +156,11 @@
         <el-tab-pane label="盘点记录" name="counting">
           <el-button type="primary" size="mini" @click="showCreateCounting = true" style="margin-bottom:12px;">新建盘点</el-button>
           <el-table :data="countingList" v-loading="countingLoading" border stripe max-height="500">
-            <el-table-column prop="id" label="ID" width="60" />
+            <el-table-column prop="id" label="ID" width="60">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="系统库存" width="80">
               <template slot-scope="{ row }">{{ row.expectedStock }}</template>
             </el-table-column>
@@ -136,8 +177,16 @@
                 <el-tag :type="row.status === 'confirmed' ? 'success' : 'warning'" size="mini">{{ row.status === 'confirmed' ? '已确认' : '待确认' }}</el-tag>
               </template>
             </el-table-column>
-            <el-table-column prop="remark" label="备注" min-width="150" />
-            <el-table-column prop="createdAt" label="时间" width="160" />
+            <el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip>
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('remark', $event)">备注<span v-if="sortIndex('remark') !== null" class="sort-index" :class="sortClass('remark') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('remark') }}</span>{{ sortIcon('remark') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="createdAt" label="时间" width="160">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="操作" width="100" fixed="right">
               <template slot-scope="{ row }">
                 <el-button v-if="row.status === 'pending'" size="mini" type="success" @click="handleConfirmCounting(row)">确认</el-button>
@@ -243,7 +292,7 @@ export default {
       outboundList: [], outboundLoading: false, outboundPage: 1, outboundPageSize: 20, outboundTotal: 0,
       showCreateOutbound: false, outboundProductOptions: [], outboundSkuOptions: [],
       outboundForm: { productId: '', skuId: '', quantity: 1, reason: '', remark: '' },
-      sortableColumns: { id: 'ID', createdAt: '时间' }
+      sortableColumns: { id: 'ID', createdAt: '时间', beforeStock: '变动前', afterStock: '变动后', orderNo: '入库单号', supplierName: '供应商', totalItems: '商品项数', remark: '备注' }
     }
   },
   mounted() {

+ 6 - 2
cfc-web/src/views/admin/KnowledgeTag.vue

@@ -14,7 +14,11 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="tagName" label="标签名称" min-width="200" />
+        <el-table-column prop="tagName" label="标签名称" min-width="200">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('tagName', $event)">标签名称<span v-if="sortIndex('tagName') !== null" class="sort-index" :class="sortClass('tagName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('tagName') }}</span>{{ sortIcon('tagName') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="类型" width="140">
           <template slot-scope="{ row }">
             <el-tag size="small" :type="row.tagType === 'category' ? 'success' : 'info'">
@@ -86,7 +90,7 @@ export default {
       loading: false,
       submitting: false,
       tags: [],
-      sortableColumns: { id: 'ID', createdAt: '创建时间' },
+      sortableColumns: { id: 'ID', createdAt: '创建时间', tagName: '标签名称' },
       keyword: '',
       dialogVisible: false,
       successDialogVisible: false,

+ 23 - 3
cfc-web/src/views/admin/MembershipCenter.vue

@@ -74,7 +74,11 @@
         <el-tab-pane label="升级记录" name="records">
           <div class="table-scroll-wrap-lg">
             <el-table :data="upgradeRecords" v-loading="recordsLoading" border stripe size="small" empty-text="暂无升级记录">
-              <el-table-column prop="id" label="ID" width="60" />
+              <el-table-column prop="id" label="ID" width="60">
+                <template slot="header">
+                  <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+                </template>
+              </el-table-column>
               <el-table-column label="用户" width="110">
                 <template slot-scope="{ row }">{{ row.userName || ('用户' + row.userId) }}</template>
               </el-table-column>
@@ -92,9 +96,16 @@
                   <el-tag :type="upgradeTypeTag(row.upgradeType)" size="mini">{{ upgradeTypeLabel(row.upgradeType) }}</el-tag>
                 </template>
               </el-table-column>
-              <el-table-column prop="orderId" label="订单号" width="120" show-overflow-tooltip />
+              <el-table-column prop="orderId" label="订单号" width="120" show-overflow-tooltip>
+                <template slot="header">
+                  <span class="sort-header" @click.stop="onSortClick('orderId', $event)">订单号<span v-if="sortIndex('orderId') !== null" class="sort-index" :class="sortClass('orderId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('orderId') }}</span>{{ sortIcon('orderId') }}</span>
+                </template>
+              </el-table-column>
               <el-table-column label="到期时间" width="150">
                 <template slot-scope="{ row }">{{ formatTime(row.expireTime) }}</template>
+                <template slot="header">
+                  <span class="sort-header" @click.stop="onSortClick('expireTime', $event)">到期时间<span v-if="sortIndex('expireTime') !== null" class="sort-index" :class="sortClass('expireTime') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('expireTime') }}</span>{{ sortIcon('expireTime') }}</span>
+                </template>
               </el-table-column>
               <el-table-column label="创建时间" width="150">
                 <template slot-scope="{ row }">{{ formatTime(row.createdAt) }}</template>
@@ -337,7 +348,7 @@ export default {
         teacherConsultation: 0,
         features: ''
       },
-      sortableColumns: { createdAt: '创建时间', id: 'ID' }
+      sortableColumns: { id: 'ID', orderId: '订单号', expireTime: '到期时间', createdAt: '创建时间' }
     }
   },
   computed: {
@@ -639,4 +650,13 @@ export default {
   font-size: 40px;
   margin-bottom: 8px;
 }
+.sort-header {
+  cursor: pointer;
+  user-select: none;
+  font-weight: 500;
+  font-size: 12px;
+}
+.sort-header:hover {
+  color: #409eff;
+}
 </style>

+ 20 - 3
cfc-web/src/views/admin/NotificationTemplateManage.vue

@@ -12,14 +12,28 @@
           <template slot-scope="{ row }">
             <el-tag size="small">{{ row.type }}</el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('type', $event)">类型<span v-if="sortIndex('type') !== null" class="sort-index" :class="sortClass('type') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('type') }}</span>{{ sortIcon('type') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('title', $event)">标题<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="content" label="内容模板" min-width="280" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('content', $event)">内容模板<span v-if="sortIndex('content') !== null" class="sort-index" :class="sortClass('content') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('content') }}</span>{{ sortIcon('content') }}</span>
+          </template>
         </el-table-column>
-        <el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip></el-table-column>
-        <el-table-column prop="content" label="内容模板" min-width="280" show-overflow-tooltip></el-table-column>
         <el-table-column prop="channels" label="推送通道" width="220">
           <template slot-scope="{ row }">
             <el-tag v-for="ch in channelLabels(row.channels)" :key="ch.value" :type="ch.type" size="mini"
               style="margin-right: 4px">{{ ch.label }}</el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('channels', $event)">推送通道<span v-if="sortIndex('channels') !== null" class="sort-index" :class="sortClass('channels') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('channels') }}</span>{{ sortIcon('channels') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="status" label="状态" width="90">
           <template slot-scope="{ row }">
@@ -27,6 +41,9 @@
               {{ row.status === 1 ? '启用' : '停用' }}
             </el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="updatedAt" label="更新时间" width="170">
           <template slot-scope="{ row }">{{ formatTime(row.updatedAt) }}</template>
@@ -120,7 +137,7 @@ export default {
         channelList: ['in_app'],
         status: 1
       },
-      sortableColumns: { id: 'ID', updatedAt: '更新时间' }
+      sortableColumns: { id: 'ID', updatedAt: '更新时间', type: '类型', title: '标题', content: '内容模板', channels: '推送通道', status: '状态' }
     }
   },
   created() {

+ 10 - 1
cfc-web/src/views/admin/NutritionProducts.vue

@@ -77,17 +77,26 @@
           <template slot-scope="{ row }">
             <span>{{ brandName(row.brandId) }}</span>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('brandId', $event)">品牌<span v-if="sortIndex('brandId') !== null" class="sort-index" :class="sortClass('brandId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('brandId') }}</span>{{ sortIcon('brandId') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="分类" width="95" align="center">
           <template slot-scope="{ row }">
             <el-tag size="mini" effect="plain">{{ categoryName(row.categoryId) }}</el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('categoryId', $event)">分类<span v-if="sortIndex('categoryId') !== null" class="sort-index" :class="sortClass('categoryId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('categoryId') }}</span>{{ sortIcon('categoryId') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="价格" width="120" align="right">
           <template slot-scope="{ row }">
             <span class="price-val">¥{{ row.price != null ? Number(row.price).toFixed(2) : '-' }}</span>
             <span v-if="row.originalPrice" class="price-orig">¥{{ row.originalPrice }}</span>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('price', $event)">价格<span v-if="sortIndex('price') !== null" class="sort-index" :class="sortClass('price') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('price') }}</span>{{ sortIcon('price') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="已售" width="70" align="center">
           <template slot-scope="{ row }">{{ row.soldNum != null ? row.soldNum : '-' }}</template>
@@ -255,7 +264,7 @@ export default {
       categoryFilter: '',
       brandFilter: '',
       list: [],
-      sortableColumns: { name: '产品名称', soldNum: '已售' },
+      sortableColumns: { name: '产品名称', soldNum: '已售', price: '价格', brandId: '品牌', categoryId: '分类' },
       total: 0,
       page: 1,
       pageSize: 20,

+ 16 - 4
cfc-web/src/views/admin/PeriodicServiceConfig.vue

@@ -11,14 +11,26 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="productId" label="商品ID" width="80" />
+      <el-table-column prop="productId" label="商品ID" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('productId', $event)">商品ID<span v-if="sortIndex('productId') !== null" class="sort-index" :class="sortClass('productId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('productId') }}</span>{{ sortIcon('productId') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="serviceName" label="服务名称" min-width="160">
         <template slot="header">
           <span class="sort-header" @click.stop="onSortClick('serviceName', $event)">服务名称{{ sortIcon('serviceName') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="cycleDays" label="周期天数" width="100" />
-      <el-table-column prop="remindBeforeDays" label="提前提醒(天)" width="120" />
+      <el-table-column prop="cycleDays" label="周期天数" width="100">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('cycleDays', $event)">周期天数<span v-if="sortIndex('cycleDays') !== null" class="sort-index" :class="sortClass('cycleDays') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('cycleDays') }}</span>{{ sortIcon('cycleDays') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="remindBeforeDays" label="提前提醒(天)" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('remindBeforeDays', $event)">提前提醒(天)<span v-if="sortIndex('remindBeforeDays') !== null" class="sort-index" :class="sortClass('remindBeforeDays') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('remindBeforeDays') }}</span>{{ sortIcon('remindBeforeDays') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="自动续费" width="100">
         <template slot-scope="scope">
           <el-tag :type="scope.row.autoRenew === 1 ? 'success' : 'info'" size="small">
@@ -81,7 +93,7 @@ export default {
       submitting: false,
       loading: false,
       list: [],
-      sortableColumns: { id: 'ID', serviceName: '服务名称' },
+      sortableColumns: { id: 'ID', serviceName: '服务名称', productId: '商品ID', cycleDays: '周期天数', remindBeforeDays: '提前提醒天数' },
       dialogVisible: false,
       dialogTitle: '',
       form: {

+ 21 - 5
cfc-web/src/views/admin/PlanManagement.vue

@@ -22,8 +22,16 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">方案ID{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="familyId" label="家庭ID" width="80" />
-      <el-table-column prop="childId" label="孩子ID" width="80" />
+      <el-table-column prop="familyId" label="家庭ID" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('familyId', $event)">家庭ID{{ sortIcon('familyId') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="childId" label="孩子ID" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('childId', $event)">孩子ID{{ sortIcon('childId') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="name" label="方案名称" min-width="180">
         <template slot="header">
           <span class="sort-header" @click.stop="onSortClick('name', $event)">方案名称{{ sortIcon('name') }}</span>
@@ -40,8 +48,16 @@
         </template>
       </el-table-column>
       <el-table-column prop="source" label="来源" width="100" />
-      <el-table-column prop="createdAt" label="创建时间" width="160" />
-      <el-table-column prop="reviewedAt" label="审核时间" width="160" />
+      <el-table-column prop="createdAt" label="创建时间" width="160">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">创建时间{{ sortIcon('createdAt') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="reviewedAt" label="审核时间" width="160">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('reviewedAt', $event)">审核时间{{ sortIcon('reviewedAt') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="180">
         <template slot-scope="{ row }">
           <el-button size="mini" type="primary" @click="showDetail(row)">详情</el-button>
@@ -88,7 +104,7 @@ export default {
   data() {
     return {
       plans: [],
-      sortableColumns: { id: '方案ID', name: '方案名称' },
+      sortableColumns: { id: '方案ID', name: '方案名称', familyId: '家庭ID', childId: '孩子ID', createdAt: '创建时间', reviewedAt: '审核时间' },
       statusFilter: '',
       familySearch: '',
       detailVisible: false,

+ 14 - 3
cfc-web/src/views/admin/PointsLog.vue

@@ -28,7 +28,11 @@
             <span class="sort-header" @click.stop="onSortClick('createdAt', $event)">时间<span v-if="sortIndex('createdAt') !== null" class="sort-index" :class="sortClass('createdAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('createdAt') }}</span>{{ sortIcon('createdAt') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="childId" label="孩子ID" width="80" />
+        <el-table-column prop="childId" label="孩子ID" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('childId', $event)">孩子ID<span v-if="sortIndex('childId') !== null" class="sort-index" :class="sortClass('childId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('childId') }}</span>{{ sortIcon('childId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="类型" width="100">
           <template slot-scope="{ row }">{{ typeLabel(row.type) }}</template>
         </el-table-column>
@@ -46,7 +50,11 @@
             </span>
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="expireAt" label="过期时间" width="160">
           <template slot-scope="{ row }">
             <span v-if="row.expireAt" :style="{ color: row.expired ? '#999' : '#E6A23C' }">
@@ -54,6 +62,9 @@
             </span>
             <span v-else style="color:#999">永久有效</span>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('expireAt', $event)">过期时间<span v-if="sortIndex('expireAt') !== null" class="sort-index" :class="sortClass('expireAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('expireAt') }}</span>{{ sortIcon('expireAt') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
@@ -146,7 +157,7 @@ export default {
       },
       detailVisible: false,
       currentRow: null,
-      sortableColumns: { createdAt: '时间' }
+      sortableColumns: { createdAt: '时间', childId: '孩子ID', description: '描述', expireAt: '过期时间' }
     }
   },
   created() {

+ 23 - 5
cfc-web/src/views/admin/ProblemDomainManage.vue

@@ -12,20 +12,38 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="code" label="编码" min-width="110" />
+        <el-table-column prop="code" label="编码" min-width="110">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('code', $event)">编码<span v-if="sortIndex('code') !== null" class="sort-index" :class="sortClass('code') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('code') }}</span>{{ sortIcon('code') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="name" label="名称" min-width="100">
           <template slot="header">
             <span class="sort-header" @click.stop="onSortClick('name', $event)">名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
           </template>
         </el-table-column>
         <el-table-column prop="icon" label="图标" width="70" align="center">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('icon', $event)">图标<span v-if="sortIndex('icon') !== null" class="sort-index" :class="sortClass('icon') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('icon') }}</span>{{ sortIcon('icon') }}</span>
+          </template>
           <template slot-scope="scope">
             <span style="font-size:20px">{{ scope.row.icon || '🧭' }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" min-width="160" show-overflow-tooltip />
-        <el-table-column prop="rewardCfValue" label="奖励CF" width="80" align="center" />
-        <el-table-column label="启用" width="80" align="center">
+        <el-table-column prop="description" label="描述" min-width="160" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="rewardCfValue" label="奖励CF" width="80" align="center">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('rewardCfValue', $event)">奖励CF<span v-if="sortIndex('rewardCfValue') !== null" class="sort-index" :class="sortClass('rewardCfValue') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('rewardCfValue') }}</span>{{ sortIcon('rewardCfValue') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="启用" width="80" align="center">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">启用<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
           <template slot-scope="scope">
             <el-switch
               v-model="scope.row.status"
@@ -152,7 +170,7 @@ export default {
         flowIntroJson: ''
       },
       flowSteps: [],
-      sortableColumns: { id: 'ID', name: '名称' }
+      sortableColumns: { id: 'ID', code: '编码', name: '名称', icon: '图标', description: '描述', rewardCfValue: '奖励CF', status: '启用' }
     }
   },
   created() {

+ 7 - 1
cfc-web/src/views/admin/ProductManage.vue

@@ -72,6 +72,9 @@
             {{ row.stock }}
           </span>
         </template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('stock', $event)" @dblclick.stop="onSortToggle('stock')">库存<span v-if="sortIndex('stock') !== null" class="sort-index" :class="sortClass('stock') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('stock') }}</span>{{ sortIcon('stock') }}</span>
+        </template>
       </el-table-column>
       <el-table-column prop="salesCount" label="销量" width="70">
         <template slot="header">
@@ -94,6 +97,9 @@
         <template slot-scope="{ row }">
           {{ row.sortOrder != null ? row.sortOrder : '-' }}
         </template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('sortOrder', $event)" @dblclick.stop="onSortToggle('sortOrder')">排序<span v-if="sortIndex('sortOrder') !== null" class="sort-index" :class="sortClass('sortOrder') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('sortOrder') }}</span>{{ sortIcon('sortOrder') }}</span>
+        </template>
       </el-table-column>
       <el-table-column label="最低可见级别" width="140">
         <template slot-scope="{ row }">
@@ -243,7 +249,7 @@ export default {
         size: 20,
         total: 0
       },
-      sortableColumns: { name: '商品名称', salesCount: '销量', createdAt: '创建时间' },
+      sortableColumns: { name: '商品名称', stock: '库存', salesCount: '销量', sortOrder: '排序', createdAt: '创建时间' },
 
       rejectDialogVisible: false,
       rejectTarget: null,

+ 21 - 5
cfc-web/src/views/admin/PromotionManagement.vue

@@ -7,9 +7,21 @@
             <el-input v-model="milestoneKeyword" placeholder="搜索里程碑..." prefix-icon="el-icon-search" style="width:200px" clearable @keyup.enter.native="handleMilestoneSearch" @clear="handleMilestoneSearch" />
     </div>
     <el-table :data="filteredMilestones" v-loading="milestoneLoading" border stripe :max-height="tableHeight">
-            <el-table-column prop="milestone" label="里程碑" min-width="180" show-overflow-tooltip />
-            <el-table-column prop="rewardPoints" label="奖励积分" width="120" />
-            <el-table-column prop="rewardEnergy" label="奖励能量" width="120" />
+            <el-table-column prop="milestone" label="里程碑" min-width="180" show-overflow-tooltip>
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('milestone', $event)">里程碑<span v-if="sortIndex('milestone') !== null" class="sort-index" :class="sortClass('milestone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('milestone') }}</span>{{ sortIcon('milestone') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="rewardPoints" label="奖励积分" width="120">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('rewardPoints', $event)">奖励积分<span v-if="sortIndex('rewardPoints') !== null" class="sort-index" :class="sortClass('rewardPoints') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('rewardPoints') }}</span>{{ sortIcon('rewardPoints') }}</span>
+              </template>
+            </el-table-column>
+            <el-table-column prop="rewardEnergy" label="奖励能量" width="120">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('rewardEnergy', $event)">奖励能量<span v-if="sortIndex('rewardEnergy') !== null" class="sort-index" :class="sortClass('rewardEnergy') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('rewardEnergy') }}</span>{{ sortIcon('rewardEnergy') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column label="操作" width="140" fixed="right">
               <template slot-scope="{ row }">
                 <el-button size="mini" @click="handleEditMilestone(row)" :disabled="row.claimed">
@@ -51,7 +63,11 @@
             <span class="sort-header" @click.stop="onSortClick('nickname', $event)">昵称<span v-if="sortIndex('nickname') !== null" class="sort-index" :class="sortClass('nickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('nickname') }}</span>{{ sortIcon('nickname') }}</span>
           </template>
         </el-table-column>
-            <el-table-column prop="referralCount" label="邀请数" width="100" />
+            <el-table-column prop="referralCount" label="邀请数" width="100">
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('referralCount', $event)">邀请数<span v-if="sortIndex('referralCount') !== null" class="sort-index" :class="sortClass('referralCount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('referralCount') }}</span>{{ sortIcon('referralCount') }}</span>
+              </template>
+            </el-table-column>
     </el-table>
     <el-pagination
             v-if="leaderboardTotal > leaderboardSize"
@@ -114,7 +130,7 @@ export default {
       leaderboardSize: 20,
       leaderboardTotal: 0,
       searchMode: false,
-      sortableColumns: { nickname: '昵称', createdAt: '创建时间', referralCount: '邀请数' }
+      sortableColumns: { nickname: '昵称', createdAt: '创建时间', referralCount: '邀请数', milestone: '里程碑', rewardPoints: '奖励积分', rewardEnergy: '奖励能量' }
     }
   },
   created() {

+ 31 - 4
cfc-web/src/views/admin/PurchaseManagement.vue

@@ -53,27 +53,54 @@
 
       <!-- 列表 -->
       <el-table :data="list" v-loading="loading" border stripe style="width: 100%;">
-        <el-table-column prop="orderNo" label="订单号" width="180" />
-        <el-table-column prop="userId" label="用户ID" width="100" />
-        <el-table-column prop="familyId" label="家庭ID" width="100" />
+        <el-table-column prop="orderNo" label="订单号" width="180">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('orderNo', $event)">订单号<span v-if="sortIndex('orderNo') !== null" class="sort-index" :class="sortClass('orderNo') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('orderNo') }}</span>{{ sortIcon('orderNo') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="userId" label="用户ID" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('userId', $event)">用户ID<span v-if="sortIndex('userId') !== null" class="sort-index" :class="sortClass('userId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('userId') }}</span>{{ sortIcon('userId') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="familyId" label="家庭ID" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('familyId', $event)">家庭ID<span v-if="sortIndex('familyId') !== null" class="sort-index" :class="sortClass('familyId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('familyId') }}</span>{{ sortIcon('familyId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="amount" label="金额(分)" width="100">
           <template slot-scope="{ row }">{{ row.amount / 100 }}元</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('amount', $event)">金额<span v-if="sortIndex('amount') !== null" class="sort-index" :class="sortClass('amount') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('amount') }}</span>{{ sortIcon('amount') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="status" label="状态" width="100">
           <template slot-scope="{ row }">
             <el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="startDate" label="开始时间" width="160">
           <template slot-scope="{ row }">{{ formatDateTime(row.startDate) }}</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('startDate', $event)">开始时间<span v-if="sortIndex('startDate') !== null" class="sort-index" :class="sortClass('startDate') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('startDate') }}</span>{{ sortIcon('startDate') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="endDate" label="结束时间" width="160">
           <template slot-scope="{ row }">{{ formatDateTime(row.endDate) }}</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('endDate', $event)">结束时间<span v-if="sortIndex('endDate') !== null" class="sort-index" :class="sortClass('endDate') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('endDate') }}</span>{{ sortIcon('endDate') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="isEarlyRenewal" label="早期续费" width="90">
           <template slot-scope="{ row }">
             <el-tag :type="row.isEarlyRenewal ? 'success' : 'info'" size="small">{{ row.isEarlyRenewal ? '是' : '否' }}</el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('isEarlyRenewal', $event)">早期续费<span v-if="sortIndex('isEarlyRenewal') !== null" class="sort-index" :class="sortClass('isEarlyRenewal') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('isEarlyRenewal') }}</span>{{ sortIcon('isEarlyRenewal') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="createdAt" label="创建时间" width="160">
           <template slot-scope="{ row }">{{ formatDateTime(row.createdAt) }}</template>
@@ -144,7 +171,7 @@ export default {
         activeUsers: 0,
         revenue: '0.00'
       },
-      sortableColumns: { id: 'ID', createdAt: '创建时间' }
+      sortableColumns: { id: 'ID', createdAt: '创建时间', orderNo: '订单号', userId: '用户ID', familyId: '家庭ID', amount: '金额', status: '状态', startDate: '开始时间', endDate: '结束时间', isEarlyRenewal: '早期续费' }
     }
   },
   created() {

+ 16 - 4
cfc-web/src/views/admin/Recipes.vue

@@ -40,9 +40,21 @@
           </template>
         </el-table-column>
 
-        <el-table-column prop="mealType" label="类型" width="80" />
-        <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
-        <el-table-column prop="status" label="状态" width="80" />
+        <el-table-column prop="mealType" label="类型" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('mealType', $event)">类型<span v-if="sortIndex('mealType') !== null" class="sort-index" :class="sortClass('mealType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('mealType') }}</span>{{ sortIcon('mealType') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="editItem(row)">编辑</el-button>
@@ -131,7 +143,7 @@ export default {
       mealTypeFilter: '',
       keyword: '',
       editId: null,
-      sortableColumns: {"name": "名称", "mealType": "餐型", "status": "状态", "createdAt": "创建时间"},
+      sortableColumns: {"name": "名称", "mealType": "餐型", "status": "状态", "createdAt": "创建时间", "description": "描述"},
       form: {
         name: '',
         mealType: '',

+ 16 - 4
cfc-web/src/views/admin/ReportAutoLearn.vue

@@ -16,7 +16,11 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="clusterKey" label="聚类键" width="140" />
+        <el-table-column prop="clusterKey" label="聚类键" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('clusterKey', $event)">聚类键<span v-if="sortIndex('clusterKey') !== null" class="sort-index" :class="sortClass('clusterKey') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('clusterKey') }}</span>{{ sortIcon('clusterKey') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="reportCount" label="报告数" width="80">
           <template slot="header">
             <span class="sort-header" @click.stop="onSortClick('reportCount', $event)">报告数{{ sortIcon('reportCount') }}</span>
@@ -29,8 +33,16 @@
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="generatedTypeId" label="类型ID" width="140" />
-        <el-table-column prop="updatedAt" label="更新时间" width="180" />
+        <el-table-column prop="generatedTypeId" label="类型ID" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('generatedTypeId', $event)">类型ID<span v-if="sortIndex('generatedTypeId') !== null" class="sort-index" :class="sortClass('generatedTypeId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('generatedTypeId') }}</span>{{ sortIcon('generatedTypeId') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="updatedAt" label="更新时间" width="180">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('updatedAt', $event)">更新时间<span v-if="sortIndex('updatedAt') !== null" class="sort-index" :class="sortClass('updatedAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('updatedAt') }}</span>{{ sortIcon('updatedAt') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="180" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleDetail(row)">详情</el-button>
@@ -69,7 +81,7 @@ export default {
     return {
       loading: false,
       clusters: [],
-      sortableColumns: { id: 'ID', reportCount: '报告数' },
+      sortableColumns: { id: 'ID', reportCount: '报告数', clusterKey: '聚类键', generatedTypeId: '类型ID', updatedAt: '更新时间' },
       detailVisible: false,
       currentCluster: null,
     }

+ 6 - 2
cfc-web/src/views/admin/ReportCollectorTrainer.vue

@@ -19,7 +19,11 @@
                 <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
               </template>
             </el-table-column>
-            <el-table-column prop="clusterKey" label="聚类键" width="120" show-overflow-tooltip />
+            <el-table-column prop="clusterKey" label="聚类键" width="120" show-overflow-tooltip>
+              <template slot="header">
+                <span class="sort-header" @click.stop="onSortClick('clusterKey', $event)">聚类键<span v-if="sortIndex('clusterKey') !== null" class="sort-index" :class="sortClass('clusterKey') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('clusterKey') }}</span>{{ sortIcon('clusterKey') }}</span>
+              </template>
+            </el-table-column>
             <el-table-column prop="reportCount" label="报告数" width="70">
               <template slot="header">
                 <span class="sort-header" @click.stop="onSortClick('reportCount', $event)">报告数{{ sortIcon('reportCount') }}</span>
@@ -140,7 +144,7 @@ export default {
       savingAnnotation: false,
       statusFilter: '',
       clusters: [],
-      sortableColumns: { id: 'ID', reportCount: '报告数' },
+      sortableColumns: { id: 'ID', reportCount: '报告数', clusterKey: '聚类键' },
       currentCluster: null,
       uploads: [],
       selectedUpload: null,

+ 19 - 4
cfc-web/src/views/admin/ReportManagement.vue

@@ -34,14 +34,29 @@
             <el-tag size="small" :type="getTypeTag(scope.row.reportType)">{{ scope.row.reportTypeName }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="title" label="标题"></el-table-column>
-        <el-table-column prop="subjectName" label="报告主体" width="120"></el-table-column>
-        <el-table-column prop="reportDate" label="报告日期" width="120"></el-table-column>
+        <el-table-column prop="title" label="标题">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('title', $event)">标题{{ sortIcon('title') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="subjectName" label="报告主体" width="120">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('subjectName', $event)">报告主体{{ sortIcon('subjectName') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="reportDate" label="报告日期" width="120">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('reportDate', $event)">报告日期{{ sortIcon('reportDate') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="overallScore" label="综合评分" width="100">
           <template slot-scope="scope">
             <span v-if="scope.row.overallScore">{{ scope.row.overallScore }}</span>
             <span v-else>-</span>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('overallScore', $event)">综合评分{{ sortIcon('overallScore') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="状态" width="100">
           <template slot-scope="scope">
@@ -83,7 +98,7 @@ export default {
   data() {
     return {
       tableData: [],
-      sortableColumns: { id: 'ID', createdAt: '创建时间' },
+      sortableColumns: { id: 'ID', title: '标题', subjectName: '报告主体', reportDate: '报告日期', overallScore: '综合评分', createdAt: '创建时间' },
       total: 0,
       loading: false,
       query: {

+ 11 - 3
cfc-web/src/views/admin/ReportParserImport.vue

@@ -14,8 +14,16 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="packageName" label="导入包名称" min-width="200" />
-        <el-table-column prop="packageFileUrl" label="文件" width="150" />
+        <el-table-column prop="packageName" label="导入包名称" min-width="200">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('packageName', $event)">导入包名称<span v-if="sortIndex('packageName') !== null" class="sort-index" :class="sortClass('packageName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('packageName') }}</span>{{ sortIcon('packageName') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="packageFileUrl" label="文件" width="150">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('packageFileUrl', $event)">文件<span v-if="sortIndex('packageFileUrl') !== null" class="sort-index" :class="sortClass('packageFileUrl') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('packageFileUrl') }}</span>{{ sortIcon('packageFileUrl') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="状态" width="100">
           <template slot-scope="{ row }">
             <el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
@@ -94,7 +102,7 @@ export default {
     return {
       loading: false, submitting: false,
       imports: [],
-      sortableColumns: { id: 'ID', createdAt: '导入时间' },
+      sortableColumns: { id: 'ID', createdAt: '导入时间', packageName: '导入包名称', packageFileUrl: '文件' },
       uploadDialogVisible: false,
       previewDialogVisible: false,
       selectedFile: null,

+ 26 - 6
cfc-web/src/views/admin/ReportTypeManagement.vue

@@ -15,15 +15,31 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="typeId" label="类型标识" width="140" />
+        <el-table-column prop="typeId" label="类型标识" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('typeId', $event)">类型标识{{ sortIcon('typeId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="displayName" label="显示名称" min-width="160">
           <template slot="header">
             <span class="sort-header" @click.stop="onSortClick('displayName', $event)">显示名称{{ sortIcon('displayName') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="family" label="家族" width="100" />
-        <el-table-column prop="parserPath" label="解析器路径" width="200" />
-        <el-table-column prop="minConfidence" label="阈值" width="70" />
+        <el-table-column prop="family" label="家族" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('family', $event)">家族{{ sortIcon('family') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="parserPath" label="解析器路径" width="200">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('parserPath', $event)">解析器路径{{ sortIcon('parserPath') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="minConfidence" label="阈值" width="70">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('minConfidence', $event)">阈值{{ sortIcon('minConfidence') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="状态" width="80">
           <template slot-scope="{ row }">
             <el-tag :type="row.isActive ? 'success' : 'info'" size="small">
@@ -39,7 +55,11 @@
             <span v-else style="color:#bbb;">—</span>
           </template>
         </el-table-column>
-        <el-table-column prop="source" label="来源" width="100" />
+        <el-table-column prop="source" label="来源" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('source', $event)">来源{{ sortIcon('source') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="220" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
@@ -150,7 +170,7 @@ export default {
     return {
       loading: false, submitting: false, fpLoading: false, fpSubmitting: false,
       types: [], keyword: '',
-      sortableColumns: { id: 'ID', displayName: '显示名称' },
+      sortableColumns: { id: 'ID', typeId: '类型标识', displayName: '显示名称', family: '家族', parserPath: '解析器路径', minConfidence: '阈值', source: '来源' },
       dialogVisible: false, isEdit: false,
       form: { typeId: '', displayName: '', family: '', description: '', parserPath: '', minConfidence: 10 },
       fpDialogVisible: false, currentType: null,

+ 16 - 4
cfc-web/src/views/admin/ReportUnknownCluster.vue

@@ -19,7 +19,11 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="clusterKey" label="聚类键" width="140" />
+        <el-table-column prop="clusterKey" label="聚类键" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('clusterKey', $event)">聚类键{{ sortIcon('clusterKey') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="reportCount" label="报告数" width="80">
           <template slot="header">
             <span class="sort-header" @click.stop="onSortClick('reportCount', $event)">报告数{{ sortIcon('reportCount') }}</span>
@@ -30,8 +34,16 @@
             <el-tag :type="statusType(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="generatedTypeId" label="生成类型" width="140" />
-        <el-table-column prop="updatedAt" label="更新时间" width="180" />
+        <el-table-column prop="generatedTypeId" label="生成类型" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('generatedTypeId', $event)">生成类型{{ sortIcon('generatedTypeId') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="updatedAt" label="更新时间" width="180">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('updatedAt', $event)">更新时间{{ sortIcon('updatedAt') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="160" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleDetail(row)">详情</el-button>
@@ -79,7 +91,7 @@ export default {
     return {
       loading: false, uploadLoading: false,
       clusters: [], statusFilter: '',
-      sortableColumns: { id: 'ID', reportCount: '报告数' },
+      sortableColumns: { id: 'ID', clusterKey: '聚类键', reportCount: '报告数', generatedTypeId: '生成类型', updatedAt: '更新时间' },
       detailVisible: false, currentCluster: null,
       uploads: [],
     }

+ 12 - 3
cfc-web/src/views/admin/SurveyTemplates.vue

@@ -13,16 +13,26 @@
             <span class="sort-header" @click.stop="onSortClick('title', $event)">标题<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="dimension" label="维度" width="80" />
+        <el-table-column prop="dimension" label="维度" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('dimension', $event)">维度<span v-if="sortIndex('dimension') !== null" class="sort-index" :class="sortClass('dimension') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dimension') }}</span>{{ sortIcon('dimension') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="cycleType" label="周期" width="100">
           <template slot-scope="scope">
             {{ cycleLabel(scope.row.cycleType) }}
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('cycleType', $event)">周期<span v-if="sortIndex('cycleType') !== null" class="sort-index" :class="sortClass('cycleType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('cycleType') }}</span>{{ sortIcon('cycleType') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="aiGenerated" label="AI生成" width="80">
           <template slot-scope="scope">
             {{ scope.row.aiGenerated === 1 ? '是' : '否' }}
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('aiGenerated', $event)">AI生成<span v-if="sortIndex('aiGenerated') !== null" class="sort-index" :class="sortClass('aiGenerated') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('aiGenerated') }}</span>{{ sortIcon('aiGenerated') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="启用" width="80" align="center">
           <template slot-scope="scope">
@@ -140,7 +150,6 @@ import SortMixin from '@/mixins/SortMixin'
 import { getSurveyTemplates, saveSurveyTemplate, deleteSurveyTemplate, aiGenerateSurveyQuestions } from '@/api/survey'
 
 export default {
-  mixins: [SortMixin],
   name: 'SurveyTemplates',
   mixins: [SortMixin],
   data() {
@@ -154,7 +163,7 @@ export default {
       form: this.emptyForm(),
       aiForm: { dimension: '', topic: '' },
       addOptionText: {},
-      sortableColumns: { id: 'ID', createdAt: '创建时间' }
+      sortableColumns: { title: '标题', dimension: '维度', cycleType: '周期', aiGenerated: 'AI生成', createdAt: '创建时间' }
     }
   },
   created() {

+ 15 - 2
cfc-web/src/views/admin/UnifiedHealthReports.vue

@@ -34,14 +34,24 @@
               <el-tag size="small" :type="getTypeTag(row.reportType || row.reportTypeName)">{{ row.reportTypeName || row.reportType }}</el-tag>
             </template>
           </el-table-column>
-          <el-table-column prop="title" label="标题" min-width="140" show-overflow-tooltip />
+          <el-table-column prop="title" label="标题" min-width="140" show-overflow-tooltip>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('title', $event)">标题{{ sortIcon('title') }}</span>
+            </template>
+          </el-table-column>
           <el-table-column label="报告对象" width="120">
             <template slot-scope="{ row }">{{ row.subjectName || row.childName || row.personName || row.userName || '-' }}</template>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('subjectName', $event)">报告对象{{ sortIcon('subjectName') }}</span>
+            </template>
           </el-table-column>
           <el-table-column label="综合评分" width="90">
             <template slot-scope="{ row }">
               <el-tag :type="scoreType(row.overallScore)" size="small">{{ row.overallScore ?? '-' }}</el-tag>
             </template>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('overallScore', $event)">综合评分{{ sortIcon('overallScore') }}</span>
+            </template>
           </el-table-column>
           <el-table-column label="肠道" width="70" v-if="false">
             <template slot-scope="{ row }">{{ row.gutHealthScore || '-' }}</template>
@@ -58,6 +68,9 @@
             <template slot-scope="{ row }">
               <el-tag size="small">{{ row.status || '已确认' }}</el-tag>
             </template>
+            <template slot="header">
+              <span class="sort-header" @click.stop="onSortClick('status', $event)">状态{{ sortIcon('status') }}</span>
+            </template>
           </el-table-column>
           <el-table-column label="营养缺乏" width="120">
             <template slot-scope="{ row }">
@@ -196,7 +209,7 @@ export default {
   data() {
     return {
       activeTab: 'list',
-      sortableColumns: { id: 'ID', reportDate: '报告日期' },
+      sortableColumns: { id: 'ID', title: '标题', subjectName: '报告对象', overallScore: '综合评分', reportDate: '报告日期', status: '状态' },
 
       // 报告列表
       reportList: [],

+ 14 - 5
cfc-web/src/views/admin/VirtualTeamList.vue

@@ -31,12 +31,23 @@
             <span class="sort-header" @click.stop="onSortClick('name', $event)">团队名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" show-overflow-tooltip></el-table-column>
-        <el-table-column prop="ownerId" label="负责人ID" width="100"></el-table-column>
+        <el-table-column prop="description" label="描述" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="ownerId" label="负责人ID" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('ownerId', $event)">负责人ID<span v-if="sortIndex('ownerId') !== null" class="sort-index" :class="sortClass('ownerId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('ownerId') }}</span>{{ sortIcon('ownerId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="profitRate" label="利润率" width="100">
           <template slot-scope="scope">
             {{ scope.row.profitRate != null ? (scope.row.profitRate + '%') : '-' }}
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('profitRate', $event)">利润率<span v-if="sortIndex('profitRate') !== null" class="sort-index" :class="sortClass('profitRate') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('profitRate') }}</span>{{ sortIcon('profitRate') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="enabled" label="状态" width="80">
           <template slot-scope="scope">
@@ -124,7 +135,6 @@ import {
 export default {
   mixins: [SortMixin],
   name: 'VirtualTeamList',
-  mixins: [SortMixin],
   data() {
     return {
       teams: [],
@@ -140,8 +150,7 @@ export default {
       formRules: {
         name: [{ required: true, message: '请输入团队名称', trigger: 'blur' }]
       },
-      sortableColumns: { id: 'ID', createdAt: '创建时间', name: '团队名称' },
-      sortableColumns: { name: '团队名称', createdAt: '创建时间', id: 'ID' }
+      sortableColumns: { id: 'ID', name: '团队名称', description: '描述', ownerId: '负责人ID', profitRate: '利润率', createdAt: '创建时间' }
     }
   },
   computed: {

+ 26 - 6
cfc-web/src/views/admin/ZodiacConfigs.vue

@@ -15,16 +15,36 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="zodiacCode" label="代码" width="120"></el-table-column>
-        <el-table-column prop="zodiacName" label="名称"></el-table-column>
-        <el-table-column prop="element" label="五行"></el-table-column>
+        <el-table-column prop="zodiacCode" label="代码" width="120">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('zodiacCode', $event)">代码<span v-if="sortIndex('zodiacCode') !== null" class="sort-index" :class="sortClass('zodiacCode') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('zodiacCode') }}</span>{{ sortIcon('zodiacCode') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="zodiacName" label="名称">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('zodiacName', $event)">名称<span v-if="sortIndex('zodiacName') !== null" class="sort-index" :class="sortClass('zodiacName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('zodiacName') }}</span>{{ sortIcon('zodiacName') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="element" label="五行">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('element', $event)">五行<span v-if="sortIndex('element') !== null" class="sort-index" :class="sortClass('element') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('element') }}</span>{{ sortIcon('element') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="日期范围">
           <template slot-scope="scope">
             {{ scope.row.startMonth }}.{{ scope.row.startDay }} - {{ scope.row.endMonth }}.{{ scope.row.endDay }}
           </template>
         </el-table-column>
-        <el-table-column prop="mindBase" label="心基础分" width="100"></el-table-column>
-        <el-table-column prop="wisdomBase" label="智基础分" width="100"></el-table-column>
+        <el-table-column prop="mindBase" label="心基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('mindBase', $event)">心基础分<span v-if="sortIndex('mindBase') !== null" class="sort-index" :class="sortClass('mindBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('mindBase') }}</span>{{ sortIcon('mindBase') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="wisdomBase" label="智基础分" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('wisdomBase', $event)">智基础分<span v-if="sortIndex('wisdomBase') !== null" class="sort-index" :class="sortClass('wisdomBase') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('wisdomBase') }}</span>{{ sortIcon('wisdomBase') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="200" fixed="right">
           <template slot-scope="{ row }">
             <el-button size="mini" type="primary" @click="handleEdit(row)">编辑</el-button>
@@ -117,7 +137,7 @@ export default {
       successDialogVisible: false,
       isEdit: false,
       form: this.getEmptyForm(),
-      sortableColumns: { id: 'ID' }
+      sortableColumns: { id: 'ID', zodiacCode: '代码', zodiacName: '名称', element: '五行', mindBase: '心基础分', wisdomBase: '智基础分' }
     }
   },
   created() {

+ 25 - 4
cfc-web/src/views/admin/data-source-config.vue

@@ -10,18 +10,39 @@
       </div>
       <div class="table-scroll-wrap-sm">
       <el-table :max-height="tableHeight" :data="records" stripe v-loading="loading">
-        <el-table-column prop="id" label="ID" width="60"></el-table-column>
-        <el-table-column prop="memberId" label="成员ID" width="80"></el-table-column>
+        <el-table-column prop="id" label="ID" width="60">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="memberId" label="成员ID" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('memberId', $event)">成员ID<span v-if="sortIndex('memberId') !== null" class="sort-index" :class="sortClass('memberId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('memberId') }}</span>{{ sortIcon('memberId') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="sourceType" label="类型" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('sourceType', $event)">类型<span v-if="sortIndex('sourceType') !== null" class="sort-index" :class="sortClass('sourceType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('sourceType') }}</span>{{ sortIcon('sourceType') }}</span>
+          </template>
           <template slot-scope="scope">
             <el-tag size="mini">{{ scope.row.sourceType }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="dimensionCodes" label="维度" width="150" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="dimensionCodes" label="维度" width="150" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('dimensionCodes', $event)">维度<span v-if="sortIndex('dimensionCodes') !== null" class="sort-index" :class="sortClass('dimensionCodes') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dimensionCodes') }}</span>{{ sortIcon('dimensionCodes') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="confidence" label="置信度" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('confidence', $event)">置信度<span v-if="sortIndex('confidence') !== null" class="sort-index" :class="sortClass('confidence') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('confidence') }}</span>{{ sortIcon('confidence') }}</span>
+          </template>
           <template slot-scope="scope">{{ scope.row.confidence }}</template>
         </el-table-column>
         <el-table-column prop="fileUrl" label="文件URL" min-width="200" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('fileUrl', $event)">文件URL<span v-if="sortIndex('fileUrl') !== null" class="sort-index" :class="sortClass('fileUrl') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('fileUrl') }}</span>{{ sortIcon('fileUrl') }}</span>
+          </template>
           <template slot-scope="scope">
             <a v-if="scope.row.fileUrl" :href="scope.row.fileUrl" target="_blank" style="color:#409EFF;font-size:12px;">查看文件</a>
             <span v-else style="color:#999">-</span>
@@ -128,7 +149,7 @@ export default {
       isEdit: false,
       form: this.emptyForm(),
       keyword: '',
-      sortableColumns: { createdAt: '创建时间' }
+      sortableColumns: { id: 'ID', memberId: '成员ID', sourceType: '类型', dimensionCodes: '维度', confidence: '置信度', fileUrl: '文件URL', createdAt: '创建时间' }
     }
   },
   mounted() {

+ 33 - 4
cfc-web/src/views/admin/gates.vue

@@ -26,6 +26,9 @@
         </el-table-column>
         <el-table-column prop="gateType" label="类型" width="140">
           <template slot-scope="scope">{{ gateTypeLabel(scope.row.gateType) }}</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('gateType', $event)">类型<span v-if="sortIndex('gateType') !== null" class="sort-index" :class="sortClass('gateType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('gateType') }}</span>{{ sortIcon('gateType') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="归属" width="80">
           <template slot-scope="scope">
@@ -33,6 +36,9 @@
               {{ scope.row.isRequired === 1 ? '主线' : '增值' }}
             </el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('isRequired', $event)">归属<span v-if="sortIndex('isRequired') !== null" class="sort-index" :class="sortClass('isRequired') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('isRequired') }}</span>{{ sortIcon('isRequired') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="形态" width="80">
           <template slot-scope="scope">
@@ -40,12 +46,21 @@
               {{ scope.row.isSoft === 1 ? '软引导' : '硬门禁' }}
             </el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('isSoft', $event)">形态<span v-if="sortIndex('isSoft') !== null" class="sort-index" :class="sortClass('isSoft') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('isSoft') }}</span>{{ sortIcon('isSoft') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="unlockTarget" label="解锁目标" width="150">
           <template slot-scope="scope">{{ unlockTargetLabel(scope.row.unlockTarget) }}</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('unlockTarget', $event)">解锁目标<span v-if="sortIndex('unlockTarget') !== null" class="sort-index" :class="sortClass('unlockTarget') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('unlockTarget') }}</span>{{ sortIcon('unlockTarget') }}</span>
+          </template>
         </el-table-column>
         <el-table-column prop="conditionParams" label="条件" width="120">
           <template slot-scope="scope">{{ scope.row.conditionParams || '—' }}</template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('conditionParams', $event)">条件<span v-if="sortIndex('conditionParams') !== null" class="sort-index" :class="sortClass('conditionParams') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('conditionParams') }}</span>{{ sortIcon('conditionParams') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="奖励" width="140">
           <template slot-scope="scope">
@@ -53,6 +68,9 @@
             <span v-if="scope.row.rewardEnergy > 0" style="color:#3A7CC2;margin-left:6px">+{{ scope.row.rewardEnergy }}能量</span>
             <span v-if="!scope.row.rewardPoints && !scope.row.rewardEnergy">—</span>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('rewardPoints', $event)">奖励<span v-if="sortIndex('rewardPoints') !== null" class="sort-index" :class="sortClass('rewardPoints') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('rewardPoints') }}</span>{{ sortIcon('rewardPoints') }}</span>
+          </template>
         </el-table-column>
         <el-table-column label="状态" width="80">
           <template slot-scope="scope">
@@ -96,15 +114,26 @@
       </el-form>
       <el-table v-if="familyProgressList.length > 0" :data="familyProgressList" border size="small">
         <el-table-column prop="gateId" label="关卡ID" width="80"></el-table-column>
-        <el-table-column prop="status" label="状态" width="100">
+          <el-table-column prop="status" label="状态" width="100">
           <template slot-scope="scope">
             <el-tag :type="scope.row.status === 'UNLOCKED' ? 'success' : 'info'" size="small">
               {{ scope.row.status === 'UNLOCKED' ? '已解锁' : '锁定' }}
             </el-tag>
           </template>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="unlockedBy" label="解锁人" width="80">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('unlockedBy', $event)">解锁人<span v-if="sortIndex('unlockedBy') !== null" class="sort-index" :class="sortClass('unlockedBy') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('unlockedBy') }}</span>{{ sortIcon('unlockedBy') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="unlockedAt" label="解锁时间" width="180">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('unlockedAt', $event)">解锁时间<span v-if="sortIndex('unlockedAt') !== null" class="sort-index" :class="sortClass('unlockedAt') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('unlockedAt') }}</span>{{ sortIcon('unlockedAt') }}</span>
+          </template>
         </el-table-column>
-        <el-table-column prop="unlockedBy" label="解锁人" width="80"></el-table-column>
-        <el-table-column prop="unlockedAt" label="解锁时间" width="180"></el-table-column>
       </el-table>
     </el-card>
 
@@ -232,7 +261,7 @@ export default {
         familyId: ''
       },
       familyProgressList: [],
-      sortableColumns: { name: '关卡名称', createdAt: '创建时间', id: 'ID' }
+      sortableColumns: { sortOrder: '排序', name: '名称', gateType: '类型', isRequired: '归属', isSoft: '形态', unlockTarget: '解锁目标', conditionParams: '条件', rewardPoints: '奖励', createdAt: '创建时间', id: 'ID' }
     }
   },
   mounted() {

+ 21 - 5
cfc-web/src/views/admin/health-knowledge.vue

@@ -32,10 +32,26 @@
             <span class="sort-header" @click.stop="onSortClick('itemName', $event)">指标名称{{ sortIcon('itemName') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="category" label="分类" width="140" />
-        <el-table-column prop="normalRange" label="正常范围" width="140" />
-        <el-table-column prop="description" label="说明" min-width="260" show-overflow-tooltip />
-        <el-table-column prop="source" label="来源" width="120" show-overflow-tooltip />
+        <el-table-column prop="category" label="分类" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('category', $event)">分类<span v-if="sortIndex('category') !== null" class="sort-index" :class="sortClass('category') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('category') }}</span>{{ sortIcon('category') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="normalRange" label="正常范围" width="140">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('normalRange', $event)">正常范围<span v-if="sortIndex('normalRange') !== null" class="sort-index" :class="sortClass('normalRange') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('normalRange') }}</span>{{ sortIcon('normalRange') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="description" label="说明" min-width="260" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">说明<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="source" label="来源" width="120" show-overflow-tooltip>
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('source', $event)">来源<span v-if="sortIndex('source') !== null" class="sort-index" :class="sortClass('source') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('source') }}</span>{{ sortIcon('source') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="操作" width="130" fixed="right">
           <template slot-scope="{ row }">
             <el-button type="text" @click="editRow(row)">编辑</el-button>
@@ -87,7 +103,7 @@ export default {
     return {
       loading: false,
       list: [],
-      sortableColumns: { id: 'ID', itemName: '指标名称' },
+      sortableColumns: { id: 'ID', itemName: '指标名称', category: '分类', normalRange: '正常范围', description: '说明', source: '来源' },
       filters: { name: '', category: '' },
       categories: ['维生素', '氨基酸', '微量元素', '短链脂肪酸', '神经递质与激素', '肠道屏障与代谢物', '抗生素风险评估'],
       dialog: { visible: false, isEdit: false, saving: false, form: {} }

+ 37 - 7
cfc-web/src/views/admin/indicators/index.vue

@@ -22,23 +22,53 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="domain" label="领域" width="100" />
-      <el-table-column prop="category" label="分类" width="100" />
-      <el-table-column prop="code" label="编码" width="160" />
-      <el-table-column prop="name" label="名称" width="160" />
-      <el-table-column prop="dataType" label="数据类型" width="100" />
+      <el-table-column prop="domain" label="领域" width="100">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('domain', $event)">领域<span v-if="sortIndex('domain') !== null" class="sort-index" :class="sortClass('domain') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('domain') }}</span>{{ sortIcon('domain') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="category" label="分类" width="100">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('category', $event)">分类<span v-if="sortIndex('category') !== null" class="sort-index" :class="sortClass('category') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('category') }}</span>{{ sortIcon('category') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="code" label="编码" width="160">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('code', $event)">编码<span v-if="sortIndex('code') !== null" class="sort-index" :class="sortClass('code') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('code') }}</span>{{ sortIcon('code') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="name" label="名称" width="160">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('name', $event)">名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="dataType" label="数据类型" width="100">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('dataType', $event)">数据类型<span v-if="sortIndex('dataType') !== null" class="sort-index" :class="sortClass('dataType') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('dataType') }}</span>{{ sortIcon('dataType') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="options" label="可选值" min-width="200">
         <template slot-scope="{ row }">
           <span v-if="row.options">{{ row.options }}</span>
         </template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('options', $event)">可选值<span v-if="sortIndex('options') !== null" class="sort-index" :class="sortClass('options') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('options') }}</span>{{ sortIcon('options') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="sortOrder" label="排序" width="60">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('sortOrder', $event)">排序<span v-if="sortIndex('sortOrder') !== null" class="sort-index" :class="sortClass('sortOrder') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('sortOrder') }}</span>{{ sortIcon('sortOrder') }}</span>
+        </template>
       </el-table-column>
-      <el-table-column prop="sortOrder" label="排序" width="60" />
       <el-table-column prop="status" label="状态" width="80">
         <template slot-scope="{ row }">
           <el-tag :type="row.status === 1 ? 'success' : 'info'">
             {{ row.status === 1 ? '启用' : '禁用' }}
           </el-tag>
         </template>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+        </template>
       </el-table-column>
       <el-table-column label="操作" width="160" fixed="right">
         <template slot-scope="{ row }">
@@ -127,7 +157,7 @@ export default {
         sortOrder: 0,
         status: 1
       },
-      sortableColumns: { id: 'ID' }
+      sortableColumns: { id: 'ID', domain: '领域', category: '分类', code: '编码', name: '名称', dataType: '数据类型', options: '可选值', sortOrder: '排序', status: '状态' }
     }
   },
   mounted() {

+ 11 - 3
cfc-web/src/views/admin/review/ActivityAudit.vue

@@ -16,13 +16,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="title" label="活动名称" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="title" label="活动名称" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('title', $event)">活动名称<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.auditStatus)">{{ statusLabel(row.auditStatus) }}</el-tag>
         </template>
       </el-table-column>
-      <el-table-column prop="auditReason" label="原因" width="160" show-overflow-tooltip />
+      <el-table-column prop="auditReason" label="原因" width="160" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('auditReason', $event)">原因<span v-if="sortIndex('auditReason') !== null" class="sort-index" :class="sortClass('auditReason') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('auditReason') }}</span>{{ sortIcon('auditReason') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="180" fixed="right">
         <template slot-scope="{ row }">
           <template v-if="row.auditStatus === 'pending'">
@@ -59,7 +67,7 @@ export default {
   data() {
     return {
       list: [], loading: false, keyword: '', statusFilter: 'pending',
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', title: '活动名称', auditReason: '原因' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 6 - 2
cfc-web/src/views/admin/review/ArticleAudit.vue

@@ -19,7 +19,11 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="title" label="标题" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('title', $event)">标题<span v-if="sortIndex('title') !== null" class="sort-index" :class="sortClass('title') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('title') }}</span>{{ sortIcon('title') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="90">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.auditStatus)" size="small">{{ statusLabel(row.auditStatus) }}</el-tag>
@@ -126,7 +130,7 @@ export default {
       page: 1,
       size: 20,
       total: 0,
-      sortableColumns: { id: 'ID', createdAt: '申请时间' },
+      sortableColumns: { id: 'ID', title: '标题', createdAt: '申请时间' },
       selectedRows: [],
       detailVisible: false,
       rejectDialogVisible: false,

+ 11 - 3
cfc-web/src/views/admin/review/ButlerAudit.vue

@@ -18,8 +18,16 @@
       <el-table-column label="用户" width="120">
           <template slot-scope="{ row }">{{ row.userName || '用户' + row.userId }}</template>
         </el-table-column>
-      <el-table-column prop="tier" label="等级" width="80" />
-      <el-table-column prop="description" label="申请说明" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="tier" label="等级" width="80">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('tier', $event)">等级<span v-if="sortIndex('tier') !== null" class="sort-index" :class="sortClass('tier') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('tier') }}</span>{{ sortIcon('tier') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="description" label="申请说明" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('description', $event)">申请说明<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag>
@@ -71,7 +79,7 @@ export default {
   data() {
     return {
       list: [], loading: false, statusFilter: 'pending',
-      sortableColumns: { id: '档案ID' },
+      sortableColumns: { id: '档案ID', tier: '等级', description: '申请说明' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 16 - 4
cfc-web/src/views/admin/review/GuideAudit.vue

@@ -16,9 +16,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="nickname" label="昵称" width="120" />
-      <el-table-column prop="realName" label="真实姓名" width="120" />
-      <el-table-column prop="phone" label="手机号" width="140" />
+      <el-table-column prop="nickname" label="昵称" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('nickname', $event)">昵称<span v-if="sortIndex('nickname') !== null" class="sort-index" :class="sortClass('nickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('nickname') }}</span>{{ sortIcon('nickname') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="realName" label="真实姓名" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('realName', $event)">真实姓名<span v-if="sortIndex('realName') !== null" class="sort-index" :class="sortClass('realName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('realName') }}</span>{{ sortIcon('realName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="phone" label="手机号" width="140">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('phone', $event)">手机号<span v-if="sortIndex('phone') !== null" class="sort-index" :class="sortClass('phone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('phone') }}</span>{{ sortIcon('phone') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.teacherStatus)">{{ statusLabel(row.teacherStatus) }}</el-tag>
@@ -71,7 +83,7 @@ export default {
     return {
       list: [], loading: false, keyword: '', statusFilter: 'pending',
       page: 1, size: 20, total: 0,
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', nickname: '昵称', realName: '真实姓名', phone: '手机号' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 21 - 5
cfc-web/src/views/admin/review/HierarchyAudit.vue

@@ -15,10 +15,26 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="applicantName" label="申请人" width="120" />
-      <el-table-column prop="currentSuperior" label="当前上级" width="120" />
-      <el-table-column prop="targetSuperior" label="目标上级" width="120" />
-      <el-table-column prop="reason" label="申请原因" min-width="200" show-overflow-tooltip />
+      <el-table-column prop="applicantName" label="申请人" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('applicantName', $event)">申请人<span v-if="sortIndex('applicantName') !== null" class="sort-index" :class="sortClass('applicantName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('applicantName') }}</span>{{ sortIcon('applicantName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="currentSuperior" label="当前上级" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('currentSuperior', $event)">当前上级<span v-if="sortIndex('currentSuperior') !== null" class="sort-index" :class="sortClass('currentSuperior') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('currentSuperior') }}</span>{{ sortIcon('currentSuperior') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="targetSuperior" label="目标上级" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('targetSuperior', $event)">目标上级<span v-if="sortIndex('targetSuperior') !== null" class="sort-index" :class="sortClass('targetSuperior') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('targetSuperior') }}</span>{{ sortIcon('targetSuperior') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="reason" label="申请原因" min-width="200" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('reason', $event)">申请原因<span v-if="sortIndex('reason') !== null" class="sort-index" :class="sortClass('reason') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('reason') }}</span>{{ sortIcon('reason') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag>
@@ -61,7 +77,7 @@ export default {
   data() {
     return {
       list: [], loading: false, statusFilter: 'pending',
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', applicantName: '申请人', currentSuperior: '当前上级', targetSuperior: '目标上级', reason: '申请原因' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 16 - 4
cfc-web/src/views/admin/review/NutritionistAudit.vue

@@ -16,9 +16,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="nickname" label="昵称" width="120" />
-      <el-table-column prop="realName" label="真实姓名" width="120" />
-      <el-table-column prop="phone" label="手机号" width="140" />
+      <el-table-column prop="nickname" label="昵称" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('nickname', $event)">昵称<span v-if="sortIndex('nickname') !== null" class="sort-index" :class="sortClass('nickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('nickname') }}</span>{{ sortIcon('nickname') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="realName" label="真实姓名" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('realName', $event)">真实姓名<span v-if="sortIndex('realName') !== null" class="sort-index" :class="sortClass('realName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('realName') }}</span>{{ sortIcon('realName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="phone" label="手机号" width="140">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('phone', $event)">手机号<span v-if="sortIndex('phone') !== null" class="sort-index" :class="sortClass('phone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('phone') }}</span>{{ sortIcon('phone') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.nutritionistStatus)">{{ statusLabel(row.nutritionistStatus) }}</el-tag>
@@ -60,7 +72,7 @@ export default {
   data() {
     return {
       list: [], loading: false, keyword: '', statusFilter: 'pending',
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', nickname: '昵称', realName: '真实姓名', phone: '手机号' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 12 - 2
cfc-web/src/views/admin/review/PackageAudit.vue

@@ -18,11 +18,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="name" label="任务模板名称" min-width="180" show-overflow-tooltip />
+      <el-table-column prop="name" label="任务模板名称" min-width="180" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('name', $event)">任务模板名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column prop="cycleDays" label="周期" width="70">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('cycleDays', $event)">周期<span v-if="sortIndex('cycleDays') !== null" class="sort-index" :class="sortClass('cycleDays') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('cycleDays') }}</span>{{ sortIcon('cycleDays') }}</span>
+        </template>
         <template slot-scope="{ row }">{{ row.cycleDays }}天</template>
       </el-table-column>
       <el-table-column prop="price" label="价格" width="90">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('price', $event)">价格<span v-if="sortIndex('price') !== null" class="sort-index" :class="sortClass('price') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('price') }}</span>{{ sortIcon('price') }}</span>
+        </template>
         <template slot-scope="{ row }">{{ formatPrice(row.price) }}</template>
       </el-table-column>
       <el-table-column label="审核状态" width="90">
@@ -128,7 +138,7 @@ export default {
       page: 1,
       size: 20,
       total: 0,
-      sortableColumns: { id: 'ID', createdAt: '申请时间' },
+      sortableColumns: { id: 'ID', name: '任务模板名称', cycleDays: '周期', price: '价格', createdAt: '申请时间' },
       selectedRows: [],
       detailVisible: false,
       rejectDialogVisible: false,

+ 11 - 3
cfc-web/src/views/admin/review/ProductAudit.vue

@@ -15,13 +15,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="name" label="商品名称" min-width="180" show-overflow-tooltip />
+      <el-table-column prop="name" label="商品名称" min-width="180" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('name', $event)">商品名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="审核状态" width="100">
         <template slot-scope="{ row }">
           <el-tag :type="statusType(row.status)">{{ statusLabel(row.status) }}</el-tag>
         </template>
       </el-table-column>
-      <el-table-column prop="rejectReason" label="原因" width="160" show-overflow-tooltip />
+      <el-table-column prop="rejectReason" label="原因" width="160" show-overflow-tooltip>
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('rejectReason', $event)">原因<span v-if="sortIndex('rejectReason') !== null" class="sort-index" :class="sortClass('rejectReason') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('rejectReason') }}</span>{{ sortIcon('rejectReason') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" width="180" fixed="right">
         <template slot-scope="{ row }">
           <template v-if="row.status === 'pending'">
@@ -58,7 +66,7 @@ export default {
   data() {
     return {
       list: [], loading: false, statusFilter: 'pending',
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', name: '商品名称', rejectReason: '原因' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 16 - 4
cfc-web/src/views/admin/review/VendorAudit.vue

@@ -16,9 +16,21 @@
           <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
         </template>
       </el-table-column>
-      <el-table-column prop="nickname" label="昵称" width="120" />
-      <el-table-column prop="realName" label="姓名" width="120" />
-      <el-table-column prop="phone" label="手机号" width="140" />
+      <el-table-column prop="nickname" label="昵称" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('nickname', $event)">昵称<span v-if="sortIndex('nickname') !== null" class="sort-index" :class="sortClass('nickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('nickname') }}</span>{{ sortIcon('nickname') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="realName" label="姓名" width="120">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('realName', $event)">姓名<span v-if="sortIndex('realName') !== null" class="sort-index" :class="sortClass('realName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('realName') }}</span>{{ sortIcon('realName') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="phone" label="手机号" width="140">
+        <template slot="header">
+          <span class="sort-header" @click.stop="onSortClick('phone', $event)">手机号<span v-if="sortIndex('phone') !== null" class="sort-index" :class="sortClass('phone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('phone') }}</span>{{ sortIcon('phone') }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="类型" width="120">
         <template slot-scope="{ row }">{{ vendorTypeLabel(row.vendorType) }}</template>
       </el-table-column>
@@ -63,7 +75,7 @@ export default {
   data() {
     return {
       list: [], loading: false, keyword: '', statusFilter: 'pending',
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', nickname: '昵称', realName: '姓名', phone: '手机号' },
       rejectDialogVisible: false, rejectTarget: null, rejectReason: ''
     }
   },

+ 11 - 3
cfc-web/src/views/admin/supply-hierarchy/ChangeRequest.vue

@@ -28,14 +28,22 @@
                         <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
                     </template>
                 </el-table-column>
-                <el-table-column prop="systemId" label="体系ID" width="80"></el-table-column>
+                <el-table-column prop="systemId" label="体系ID" width="80">
+                    <template slot="header">
+                        <span class="sort-header" @click.stop="onSortClick('systemId', $event)">体系ID<span v-if="sortIndex('systemId') !== null" class="sort-index" :class="sortClass('systemId') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('systemId') }}</span>{{ sortIcon('systemId') }}</span>
+                    </template>
+                </el-table-column>
                 <el-table-column label="申请人" width="120">
                     <template slot-scope="scope">{{ scope.row.applicantNickname }} ({{ scope.row.applicantRealName }})</template>
                 </el-table-column>
                 <el-table-column label="目标上级" width="120">
                     <template slot-scope="scope">{{ scope.row.targetParentNickname }} ({{ scope.row.targetParentRealName }})</template>
                 </el-table-column>
-                <el-table-column prop="reason" label="申请理由" min-width="180"></el-table-column>
+                <el-table-column prop="reason" label="申请理由" min-width="180">
+                    <template slot="header">
+                        <span class="sort-header" @click.stop="onSortClick('reason', $event)">申请理由<span v-if="sortIndex('reason') !== null" class="sort-index" :class="sortClass('reason') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('reason') }}</span>{{ sortIcon('reason') }}</span>
+                    </template>
+                </el-table-column>
                 <el-table-column prop="status" label="状态" width="100">
                     <template slot-scope="scope">
                         <el-tag :type="getStatusTagType(scope.row.status)" size="small">
@@ -89,7 +97,7 @@ export default {
         return {
             supplySystems: [],
             requests: [],
-            sortableColumns: { id: 'ID', createdAt: '申请时间' },
+            sortableColumns: { id: 'ID', systemId: '体系ID', reason: '申请理由', createdAt: '申请时间' },
             filterForm: {
                 systemId: null,
                 status: null

+ 16 - 4
cfc-web/src/views/admin/supply-manage/List.vue

@@ -30,9 +30,21 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="nickname" label="昵称" width="130"></el-table-column>
-        <el-table-column prop="realName" label="真实姓名" width="120"></el-table-column>
-        <el-table-column prop="phone" label="手机号" width="130"></el-table-column>
+        <el-table-column prop="nickname" label="昵称" width="130">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('nickname', $event)">昵称<span v-if="sortIndex('nickname') !== null" class="sort-index" :class="sortClass('nickname') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('nickname') }}</span>{{ sortIcon('nickname') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="realName" label="真实姓名" width="120">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('realName', $event)">真实姓名<span v-if="sortIndex('realName') !== null" class="sort-index" :class="sortClass('realName') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('realName') }}</span>{{ sortIcon('realName') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="phone" label="手机号" width="130">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('phone', $event)">手机号<span v-if="sortIndex('phone') !== null" class="sort-index" :class="sortClass('phone') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('phone') }}</span>{{ sortIcon('phone') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column label="服务商类型" width="130">
           <template slot-scope="scope">
             <el-tag size="small">{{ getVendorTypeLabel(scope.row.vendorType) }}</el-tag>
@@ -90,7 +102,7 @@ export default {
     return {
       suppliers: [],
       loading: false,
-      sortableColumns: { id: 'ID', createdAt: '创建时间' },
+      sortableColumns: { id: 'ID', nickname: '昵称', realName: '真实姓名', phone: '手机号', createdAt: '创建时间' },
       searchKeyword: '',
       searchVendorStatus: '',
       page: 1,

+ 22 - 4
cfc-web/src/views/admin/supply-system/List.vue

@@ -29,15 +29,33 @@
             <span class="sort-header" @click.stop="onSortClick('id', $event)">ID<span v-if="sortIndex('id') !== null" class="sort-index" :class="sortClass('id') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('id') }}</span>{{ sortIcon('id') }}</span>
           </template>
         </el-table-column>
-        <el-table-column prop="name" label="体系名称" min-width="150"></el-table-column>
-        <el-table-column prop="settlementPeriodDays" label="账期(天)" width="100"></el-table-column>
+        <el-table-column prop="name" label="体系名称" min-width="150">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('name', $event)">体系名称<span v-if="sortIndex('name') !== null" class="sort-index" :class="sortClass('name') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('name') }}</span>{{ sortIcon('name') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="settlementPeriodDays" label="账期(天)" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('settlementPeriodDays', $event)">账期(天)<span v-if="sortIndex('settlementPeriodDays') !== null" class="sort-index" :class="sortClass('settlementPeriodDays') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('settlementPeriodDays') }}</span>{{ sortIcon('settlementPeriodDays') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="platformProfitRate" label="平台留利" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('platformProfitRate', $event)">平台留利<span v-if="sortIndex('platformProfitRate') !== null" class="sort-index" :class="sortClass('platformProfitRate') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('platformProfitRate') }}</span>{{ sortIcon('platformProfitRate') }}</span>
+          </template>
           <template slot-scope="scope">
             {{ scope.row.platformProfitRate ? (scope.row.platformProfitRate * 1).toFixed(2) + '%' : '-' }}
           </template>
         </el-table-column>
-        <el-table-column prop="description" label="描述" min-width="200"></el-table-column>
+        <el-table-column prop="description" label="描述" min-width="200">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('description', $event)">描述<span v-if="sortIndex('description') !== null" class="sort-index" :class="sortClass('description') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('description') }}</span>{{ sortIcon('description') }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="status" label="状态" width="100">
+          <template slot="header">
+            <span class="sort-header" @click.stop="onSortClick('status', $event)">状态<span v-if="sortIndex('status') !== null" class="sort-index" :class="sortClass('status') === 'sort-asc' ? 'sort-asc-badge' : 'sort-desc-badge'">{{ sortIndex('status') }}</span>{{ sortIcon('status') }}</span>
+          </template>
           <template slot-scope="scope">
             <el-tag :type="scope.row.status === 'active' ? 'success' : 'danger'" size="small">
               {{ scope.row.status === 'active' ? '启用' : '停用' }}
@@ -85,7 +103,7 @@ export default {
     return {
       systems: [],
       loading: false,
-      sortableColumns: { id: 'ID' },
+      sortableColumns: { id: 'ID', name: '体系名称', settlementPeriodDays: '账期(天)', platformProfitRate: '平台留利', description: '描述', status: '状态' },
       searchKeyword: '',
       searchStatus: '',
       page: 1,