Просмотр исходного кода

feat: Web管理端添加服务商审核页面(审核列表+通过/拒绝操作)

User 3 месяцев назад
Родитель
Сommit
3ff96c9798

+ 19 - 0
zxyj-web/src/api/vendor.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+// 服务商入驻申请列表
+export function getVendorList(params) {
+  return request({
+    url: '/api/admin/vendor/list',
+    method: 'post',
+    data: params
+  })
+}
+
+// 审核服务商入驻
+export function reviewVendor(data) {
+  return request({
+    url: '/api/admin/vendor/review',
+    method: 'post',
+    data: data
+  })
+}

+ 7 - 1
zxyj-web/src/router/index.js

@@ -172,6 +172,12 @@ const routes = [
         name: 'AssessmentAdmin',
         name: 'AssessmentAdmin',
         component: () => import('@/views/admin/Assessment.vue'),
         component: () => import('@/views/admin/Assessment.vue'),
         meta: { title: '测评管理' }
         meta: { title: '测评管理' }
+      },
+      {
+        path: 'vendor-review',
+        name: 'VendorReview',
+        component: () => import('@/views/admin/VendorReview.vue'),
+        meta: { title: '服务商审核' }
       }
       }
     ]
     ]
   }
   }
@@ -260,7 +266,7 @@ router.beforeEach(async (to, from, next) => {
     'Tasks', 'TaskTemplates', 'Rewards',
     'Tasks', 'TaskTemplates', 'Rewards',
     'Users', 'PackageAudit', 'GuideAudit', 'OperationLogs',
     'Users', 'PackageAudit', 'GuideAudit', 'OperationLogs',
     'ServiceTypes', 'ServiceContents', 'PackageTemplates',
     'ServiceTypes', 'ServiceContents', 'PackageTemplates',
-    'AssessmentAdmin'
+    'AssessmentAdmin', 'VendorReview'
   ]
   ]
   if (adminRoutes.includes(to.name) && role === 'teacher') {
   if (adminRoutes.includes(to.name) && role === 'teacher') {
     console.warn('Access denied: Admin role required for', to.name)
     console.warn('Access denied: Admin role required for', to.name)

+ 4 - 0
zxyj-web/src/views/Layout.vue

@@ -141,6 +141,10 @@
               <i class="el-icon-s-order"></i>
               <i class="el-icon-s-order"></i>
               <span>操作日志</span>
               <span>操作日志</span>
             </el-menu-item>
             </el-menu-item>
+            <el-menu-item index="/vendor-review">
+              <i class="el-icon-s-check"></i>
+              <span slot="title">服务商审核</span>
+            </el-menu-item>
           </el-submenu>
           </el-submenu>
         </template>
         </template>
       </el-menu>
       </el-menu>

+ 145 - 0
zxyj-web/src/views/admin/VendorReview.vue

@@ -0,0 +1,145 @@
+<template>
+  <div class="vendor-review">
+    <div class="header">
+      <h2>服务商入驻审核</h2>
+      <el-select v-model="statusFilter" placeholder="审核状态" @change="loadList" style="width: 150px;">
+        <el-option label="全部" value="" />
+        <el-option label="待审核" value="pending" />
+        <el-option label="已通过" value="approved" />
+        <el-option label="已拒绝" value="rejected" />
+      </el-select>
+    </div>
+
+    <el-table :data="list" v-loading="loading" border stripe>
+      <el-table-column prop="id" label="用户ID" width="80" />
+      <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 label="服务商类型" width="140">
+        <template slot-scope="{ row }">
+          {{ vendorTypeLabel(row.vendorType) }}
+        </template>
+      </el-table-column>
+      <el-table-column prop="vendorInfo" label="资质说明" min-width="200" show-overflow-tooltip />
+      <el-table-column label="审核状态" width="100">
+        <template slot-scope="{ row }">
+          <el-tag :type="statusType(row.vendorStatus)">{{ statusLabel(row.vendorStatus) }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column prop="vendorRejectReason" label="拒绝原因" width="150" show-overflow-tooltip />
+      <el-table-column label="操作" width="200" fixed="right">
+        <template slot-scope="{ row }">
+          <el-button v-if="row.vendorStatus === 'pending'" type="success" size="small" @click="handleReview(row, 'approve')">通过</el-button>
+          <el-button v-if="row.vendorStatus === 'pending'" type="danger" size="small" @click="showRejectDialog(row)">拒绝</el-button>
+          <span v-else class="no-op">—</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <el-pagination
+      @size-change="onPageChange"
+      @current-change="onPageChange"
+      :current-page="page"
+      :page-size="size"
+      :total="total"
+      layout="total, prev, pager, next"
+      style="margin-top: 20px; text-align: right;"
+    />
+
+    <!-- 拒绝弹窗 -->
+    <el-dialog title="填写拒绝原因" :visible.sync="rejectDialogVisible" width="400px">
+      <el-input v-model="rejectReason" type="textarea" :rows="3" placeholder="请输入拒绝原因" />
+      <span slot="footer">
+        <el-button @click="rejectDialogVisible = false">取消</el-button>
+        <el-button type="danger" @click="confirmReject">确认拒绝</el-button>
+      </span>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getVendorList, reviewVendor } from '@/api/vendor'
+
+export default {
+  data() {
+    return {
+      list: [],
+      loading: false,
+      page: 1,
+      size: 20,
+      total: 0,
+      statusFilter: 'pending',
+      rejectDialogVisible: false,
+      rejectTarget: null,
+      rejectReason: ''
+    }
+  },
+  mounted() {
+    this.loadList()
+  },
+  methods: {
+    vendorTypeLabel(type) {
+      const map = { planner: '成长规划师', activity_provider: '活动提供商', product_supplier: '商品供应商' }
+      return map[type] || type
+    },
+    statusType(status) {
+      const map = { pending: 'warning', approved: 'success', rejected: 'danger' }
+      return map[status] || 'info'
+    },
+    statusLabel(status) {
+      const map = { pending: '待审核', approved: '已通过', rejected: '已拒绝' }
+      return map[status] || status
+    },
+    async loadList() {
+      this.loading = true
+      try {
+        const res = await getVendorList({ page: this.page, size: this.size, status: this.statusFilter })
+        this.list = res.data.list || []
+        this.total = res.data.total || 0
+      } catch (e) {
+        this.$message.error('加载失败')
+      } finally {
+        this.loading = false
+      }
+    },
+    onPageChange(val) {
+      this.page = val
+      this.loadList()
+    },
+    async handleReview(row, action) {
+      try {
+        await reviewVendor({ userId: row.id, action })
+        this.$message.success('审核完成')
+        this.loadList()
+      } catch (e) {
+        this.$message.error('操作失败')
+      }
+    },
+    showRejectDialog(row) {
+      this.rejectTarget = row
+      this.rejectReason = ''
+      this.rejectDialogVisible = true
+    },
+    async confirmReject() {
+      if (!this.rejectReason) {
+        this.$message.warning('请填写拒绝原因')
+        return
+      }
+      await this.handleReview(this.rejectTarget, 'reject')
+      this.rejectDialogVisible = false
+    }
+  }
+}
+</script>
+
+<style scoped>
+.header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+.no-op {
+  color: #ccc;
+}
+</style>