Explorar o código

feat(admin): add service role application review page and admin endpoints

Xiaogang Liao hai 3 meses
pai
achega
c233f5499e

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

@@ -168,6 +168,12 @@ const routes = [
         meta: { title: '操作日志', perm: 'system:logs' }
       },
       // 服务管理(管理员)
+      {
+        path: 'service-role-applications',
+        name: 'ServiceRoleApplications',
+        component: () => import('@/views/service/ServiceRoleApplications.vue'),
+        meta: { title: '服务角色申请审核', perm: 'audit' }
+      },
       {
         path: 'teacher-messages',
         name: 'TeacherMessages',

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

@@ -185,8 +185,9 @@ export default {
             { path: '/growth-task', label: '成长任务管理', icon: 'el-icon-s-management', perm: 'task:list' },
           ]},
 
-        // ===== 4. 审核中心 (admin) =====
-        { path: '/review-center', label: '审核中心', icon: 'el-icon-s-check', perm: 'audit' },
+// ===== 4. 审核中心 (admin) =====
+      { path: '/review-center', label: '审核中心', icon: 'el-icon-s-check', perm: 'audit' },
+      { path: '/service-role-applications', label: '服务角色申请审核', icon: 'el-icon-s-check', perm: 'audit' },
 
 
         // ===== 5. 商城营销 (admin) =====

+ 155 - 0
cfc-web/src/views/service/ServiceRoleApplications.vue

@@ -0,0 +1,155 @@
+<template>
+  <div class="page-container">
+    <el-card>
+      <div slot="header">
+        <span>服务角色申请审核</span>
+      </div>
+      <el-table :data="applications" v-loading="loading" style="width: 100%">
+        <el-table-column prop="id" label="ID" width="60" />
+        <el-table-column prop="userId" label="用户ID" width="80" />
+        <el-table-column label="申请角色" width="200">
+          <template slot-scope="{ row }">
+            <el-tag v-for="role in parseRoles(row.roles)" :key="role" style="margin-right: 4px" size="mini">
+              {{ roleMap[role] || role }}
+            </el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="身份证" width="200">
+          <template slot-scope="{ row }">
+            <div>{{ row.idCard }}</div>
+            <div v-if="row.idCardImages">
+              <el-image
+                v-for="(img, idx) in parseImages(row.idCardImages)"
+                :key="idx"
+                :src="img"
+                style="width: 60px; height: 40px; margin-right: 4px; cursor: pointer;"
+                :preview-src-list="parseImages(row.idCardImages)"
+              />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="资质证书" width="160">
+          <template slot-scope="{ row }">
+            <el-image
+              v-if="row.certificateImages"
+              v-for="(img, idx) in parseImages(row.certificateImages)"
+              :key="'cert-' + idx"
+              :src="img"
+              style="width: 60px; height: 40px; margin-right: 4px; cursor: pointer;"
+              :preview-src-list="parseImages(row.certificateImages)"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column label="地址" width="200">
+          <template slot-scope="{ row }">
+            {{ row.province }}{{ row.city }}{{ row.district }}{{ row.street }} {{ row.addressDetail }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="createdAt" label="申请时间" width="160" />
+        <el-table-column label="状态" width="80">
+          <template slot-scope="{ row }">
+            <el-tag :type="statusType(row.status)">{{ statusText(row.status) }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="160">
+          <template slot-scope="{ row }">
+            <el-button v-if="row.status === 0" type="success" size="mini" @click="handleApprove(row)">批准</el-button>
+            <el-button v-if="row.status === 0" type="danger" size="mini" @click="handleReject(row)">驳回</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </el-card>
+
+    <el-dialog title="驳回申请" :visible.sync="rejectDialogVisible" width="400px">
+      <el-form>
+        <el-form-item label="驳回原因">
+          <el-input type="textarea" v-model="rejectReason" rows="3" placeholder="请输入驳回原因" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="rejectDialogVisible = false">取消</el-button>
+        <el-button type="danger" @click="confirmReject">确认驳回</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import request from '@/utils/request'
+
+export default {
+  data() {
+    return {
+      applications: [],
+      loading: false,
+      rejectDialogVisible: false,
+      rejectReason: '',
+      currentRejectId: null,
+      roleMap: {
+        planner: '规划师',
+        nutritionist: '营养师',
+        butler: '管家',
+        vendor: '服务商',
+        article_admin: '文章管理员',
+        activity_provider: '活动提供商'
+      }
+    }
+  },
+  mounted() {
+    this.fetchApplications()
+  },
+  methods: {
+    async fetchApplications() {
+      this.loading = true
+      try {
+        const res = await request({ url: '/api/service-role/admin/list', method: 'post', data: { status: 0 } })
+        this.applications = res.data || []
+      } catch (e) {
+        this.$message.error('获取列表失败')
+      } finally {
+        this.loading = false
+      }
+    },
+    parseRoles(roles) {
+      try { return JSON.parse(roles) } catch (e) { return [] }
+    },
+    parseImages(images) {
+      try { return JSON.parse(images) } catch (e) { return [] }
+    },
+    statusType(status) {
+      return { 0: 'warning', 1: 'success', 2: 'danger' }[status] || 'info'
+    },
+    statusText(status) {
+      return { 0: '待审核', 1: '已通过', 2: '已驳回' }[status] || '未知'
+    },
+    async handleApprove(row) {
+      try {
+        await request({ url: '/api/service-role/admin/approve', method: 'post', data: { id: row.id } })
+        this.$message.success('已批准')
+        this.fetchApplications()
+      } catch (e) {
+        this.$message.error('操作失败')
+      }
+    },
+    handleReject(row) {
+      this.currentRejectId = row.id
+      this.rejectReason = ''
+      this.rejectDialogVisible = true
+    },
+    async confirmReject() {
+      try {
+        await request({
+          url: '/api/service-role/admin/reject',
+          method: 'post',
+          data: { id: this.currentRejectId, reason: this.rejectReason }
+        })
+        this.$message.success('已驳回')
+        this.rejectDialogVisible = false
+        this.fetchApplications()
+      } catch (e) {
+        this.$message.error('操作失败')
+      }
+    }
+  }
+}
+</script>