Prechádzať zdrojové kódy

feat: 管理端先天画像权重配置+数字能量配置页 + 路由菜单

Xiaogang Liao 2 mesiacov pred
rodič
commit
941568bac1

+ 58 - 0
cfc-web/src/api/admin.js

@@ -966,6 +966,64 @@ export function deleteZodiacConfig(id) {
   })
 }
 
+// ========== 先天画像来源权重配置 API ==========
+
+export function listInnatePortraitConfigs() {
+  return request({
+    url: '/api/admin/innate-portrait-config/list',
+    method: 'post'
+  })
+}
+
+export function updateInnatePortraitConfig(data) {
+  return request({
+    url: '/api/admin/innate-portrait-config/update',
+    method: 'post',
+    data
+  })
+}
+
+export function invalidateInnatePortraitScores() {
+  return request({
+    url: '/api/admin/innate-portrait-config/invalidate',
+    method: 'post'
+  })
+}
+
+// ========== 数字能量详细配置 API ==========
+
+export function listNumSoulDetailConfigs(data) {
+  return request({
+    url: '/api/admin/numsoul-detail-config/list',
+    method: 'post',
+    data
+  })
+}
+
+export function createNumSoulDetailConfig(data) {
+  return request({
+    url: '/api/admin/numsoul-detail-config/create',
+    method: 'post',
+    data
+  })
+}
+
+export function updateNumSoulDetailConfig(data) {
+  return request({
+    url: '/api/admin/numsoul-detail-config/update',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteNumSoulDetailConfig(id) {
+  return request({
+    url: '/api/admin/numsoul-detail-config/delete',
+    method: 'post',
+    data: { id }
+  })
+}
+
 // ========== 八字配置管理 API ==========
 
 export function listBaziConfigs() {

+ 12 - 0
cfc-web/src/router/index.js

@@ -512,6 +512,18 @@ const routes = [
         component: () => import('@/views/admin/BloodTypeConfigs.vue'),
         meta: { title: '血型配置', perm: 'config:dimension' }
       },
+      {
+        path: 'innate-portrait-config',
+        name: 'InnatePortraitConfig',
+        component: () => import('@/views/admin/InnatePortraitConfig.vue'),
+        meta: { title: '先天画像权重配置', perm: 'config:dimension' }
+      },
+      {
+        path: 'numsoul-detail-config',
+        name: 'NumSoulDetailConfig',
+        component: () => import('@/views/admin/NumSoulDetailConfig.vue'),
+        meta: { title: '数字能量配置', perm: 'config:dimension' }
+      },
 
       // ========== 饮食管理 (admin) ==========
       {

+ 2 - 0
cfc-web/src/views/Layout.vue

@@ -332,6 +332,8 @@ export default {
                 { path: '/zodiac-configs', label: '星座配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
                 { path: '/bazi-configs', label: '八字配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
                 { path: '/blood-type-configs', label: '血型配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
+                { path: '/innate-portrait-config', label: '先天画像权重配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
+                { path: '/numsoul-detail-config', label: '数字能量配置', icon: 'el-icon-s-management', perm: 'config:dimension' },
               ]},
             // --- 虚拟团队 ---
             { title: '虚拟团队', icon: 'el-icon-s-custom', perm: 'system:base',

+ 75 - 0
cfc-web/src/views/admin/InnatePortraitConfig.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="app-container">
+    <el-card shadow="never">
+      <div slot="header">
+        <span>先天画像来源权重配置</span>
+        <el-button style="float: right" type="primary" size="small" @click="load">刷新</el-button>
+      </div>
+      <el-table :data="list" border stripe>
+        <el-table-column prop="sourceName" label="来源" width="120" />
+        <el-table-column label="权重" width="220">
+          <template slot-scope="scope">
+            <el-input-number
+              v-model="scope.row.weight"
+              :min="0" :max="10000" :step="500"
+              size="small"
+            />
+            <span style="margin-left: 8px; color: #999">
+              {{ (scope.row.weight / 100).toFixed(1) }}%
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column label="启用" width="100">
+          <template slot-scope="scope">
+            <el-switch v-model="scope.row.enabled" :active-value="1" :inactive-value="0" />
+          </template>
+        </el-table-column>
+        <el-table-column label="AI解读" width="100">
+          <template slot-scope="scope">
+            <el-switch v-model="scope.row.aiEnabled" :active-value="1" :inactive-value="0" />
+          </template>
+        </el-table-column>
+        <el-table-column label="排序" width="120">
+          <template slot-scope="scope">
+            <el-input-number v-model="scope.row.sortOrder" :min="0" size="small" />
+          </template>
+        </el-table-column>
+        <el-table-column label="操作">
+          <template slot-scope="scope">
+            <el-button type="primary" size="mini" @click="save(scope.row)">保存</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div style="margin-top: 12px; color: #999; font-size: 12px">
+        提示:权重按基点配置(2500=25%)。保存后自动清除所有成员先天分缓存并触发重算。启用来源权重之和不足100%时按比例归一化。
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import { listInnatePortraitConfigs, updateInnatePortraitConfig } from '@/api/admin'
+
+export default {
+  name: 'InnatePortraitConfig',
+  data() {
+    return { list: [] }
+  },
+  created() {
+    this.load()
+  },
+  methods: {
+    load() {
+      listInnatePortraitConfigs().then(res => {
+        this.list = res.data || []
+      })
+    },
+    save(row) {
+      updateInnatePortraitConfig(row).then(() => {
+        this.$message.success('保存成功')
+        this.load()
+      })
+    }
+  }
+}
+</script>

+ 115 - 0
cfc-web/src/views/admin/NumSoulDetailConfig.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="app-container">
+    <el-card shadow="never">
+      <div slot="header">
+        <span>数字能量配置</span>
+        <div style="float: right">
+          <el-select v-model="filterType" placeholder="筛选类型" clearable size="small" style="width: 160px" @change="load">
+            <el-option label="生命灵数" value="life_path" />
+            <el-option label="天赋数" value="talent" />
+            <el-option label="生日数" value="birthday" />
+            <el-option label="命运数" value="destiny" />
+          </el-select>
+          <el-button type="primary" size="small" style="margin-left: 8px" @click="showCreate">新增</el-button>
+        </div>
+      </div>
+      <el-table :data="list" border stripe>
+        <el-table-column prop="numberType" label="类型" width="110">
+          <template slot-scope="scope">{{ typeLabel(scope.row.numberType) }}</template>
+        </el-table-column>
+        <el-table-column prop="numberValue" label="数字" width="80" />
+        <el-table-column prop="title" label="称号" width="120" />
+        <el-table-column prop="keywords" label="关键词" />
+        <el-table-column prop="mindBase" label="心先天分" width="100" />
+        <el-table-column prop="mindAdvice" label="成长建议" show-overflow-tooltip />
+        <el-table-column label="代表色" width="80">
+          <template slot-scope="scope">
+            <span :style="{ display: 'inline-block', width: '20px', height: '20px', background: scope.row.colorHex, borderRadius: '4px' }" />
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="140">
+          <template slot-scope="scope">
+            <el-button type="text" @click="showEdit(scope.row)">编辑</el-button>
+            <el-button type="text" style="color: #f56c6c" @click="remove(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <el-dialog :title="form.id ? '编辑' : '新增'" :visible.sync="dialogVisible" width="520px">
+        <el-form :model="form" label-width="100px">
+          <el-form-item label="类型">
+            <el-select v-model="form.numberType">
+              <el-option label="生命灵数" value="life_path" />
+              <el-option label="天赋数" value="talent" />
+              <el-option label="生日数" value="birthday" />
+              <el-option label="命运数" value="destiny" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="数字"><el-input-number v-model="form.numberValue" :min="1" :max="99" /></el-form-item>
+          <el-form-item label="称号"><el-input v-model="form.title" /></el-form-item>
+          <el-form-item label="关键词"><el-input v-model="form.keywords" /></el-form-item>
+          <el-form-item label="心先天分"><el-input-number v-model="form.mindBase" :min="0" :max="100" /></el-form-item>
+          <el-form-item label="成长建议"><el-input type="textarea" v-model="form.mindAdvice" /></el-form-item>
+          <el-form-item label="代表色"><el-color-picker v-model="form.colorHex" /></el-form-item>
+        </el-form>
+        <div slot="footer">
+          <el-button @click="dialogVisible = false">取消</el-button>
+          <el-button type="primary" @click="save">保存</el-button>
+        </div>
+      </el-dialog>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import { listNumSoulDetailConfigs, createNumSoulDetailConfig, updateNumSoulDetailConfig, deleteNumSoulDetailConfig } from '@/api/admin'
+
+export default {
+  name: 'NumSoulDetailConfig',
+  data() {
+    return {
+      list: [],
+      filterType: '',
+      dialogVisible: false,
+      form: { id: null, numberType: 'life_path', numberValue: 1, title: '', keywords: '', mindBase: 50, mindAdvice: '', colorHex: '#FF4444' }
+    }
+  },
+  created() {
+    this.load()
+  },
+  methods: {
+    typeLabel(t) {
+      return { life_path: '生命灵数', talent: '天赋数', birthday: '生日数', destiny: '命运数' }[t] || t
+    },
+    load() {
+      listNumSoulDetailConfigs({ numberType: this.filterType || undefined }).then(res => {
+        this.list = res.data || []
+      })
+    },
+    showCreate() {
+      this.form = { id: null, numberType: 'life_path', numberValue: 1, title: '', keywords: '', mindBase: 50, mindAdvice: '', colorHex: '#FF4444' }
+      this.dialogVisible = true
+    },
+    showEdit(row) {
+      this.form = Object.assign({}, row)
+      this.dialogVisible = true
+    },
+    save() {
+      const promise = this.form.id ? updateNumSoulDetailConfig(this.form) : createNumSoulDetailConfig(this.form)
+      promise.then(() => {
+        this.$message.success('保存成功')
+        this.dialogVisible = false
+        this.load()
+      })
+    },
+    remove(row) {
+      this.$confirm('确认删除该配置?', '提示', { type: 'warning' }).then(() => {
+        deleteNumSoulDetailConfig(row.id).then(() => {
+          this.$message.success('删除成功')
+          this.load()
+        })
+      })
+    }
+  }
+}
+</script>