lmx пре 2 дана
родитељ
комит
2a843bdb88
3 измењених фајлова са 544 додато и 0 уклоњено
  1. 63 0
      src/api/admin/cidServerManage.js
  2. 480 0
      src/views/admin/cidConfig/cidServerManage.vue
  3. 1 0
      src/views/admin/menu.js

+ 63 - 0
src/api/admin/cidServerManage.js

@@ -0,0 +1,63 @@
+import request from '@/utils/request'
+
+export function listServiceConfig(query) {
+  return request({
+    url: '/admin/cidServerManage/serviceConfig/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getServiceConfig(id) {
+  return request({
+    url: '/admin/cidServerManage/serviceConfig/' + id,
+    method: 'get'
+  })
+}
+
+export function addServiceConfig(data) {
+  return request({
+    url: '/admin/cidServerManage/serviceConfig',
+    method: 'post',
+    data: data
+  })
+}
+
+export function updateServiceConfig(data) {
+  return request({
+    url: '/admin/cidServerManage/serviceConfig',
+    method: 'put',
+    data: data
+  })
+}
+
+export function delServiceConfig(ids) {
+  return request({
+    url: '/admin/cidServerManage/serviceConfig/' + ids,
+    method: 'delete'
+  })
+}
+
+export function listCidServerQuota(data) {
+  return request({
+    url: '/admin/cidServerManage/quota/list',
+    method: 'post',
+    data: data
+  })
+}
+
+export function allocateCidServerQuota(data) {
+  return request({
+    url: '/admin/cidServerManage/quota/allocate',
+    method: 'post',
+    data: data
+  })
+}
+
+export function adjustCidServerQuota(data) {
+  return request({
+    url: '/admin/cidServerManage/quota/adjust',
+    method: 'put',
+    data: data
+  })
+}

+ 480 - 0
src/views/admin/cidConfig/cidServerManage.vue

@@ -0,0 +1,480 @@
+<template>
+  <div class="app-container">
+    <el-tabs v-model="activeTab" class="cid-server-tabs">
+      <el-tab-pane label="服务实例调度" name="serviceConfig">
+        <el-form :model="configQuery" ref="configQueryForm" :inline="true" size="small" class="mb8">
+          <el-form-item label="服务标识" prop="serviceMarker">
+            <el-input v-model="configQuery.serviceMarker" placeholder="请输入服务标识" clearable @keyup.enter.native="handleConfigQuery" />
+          </el-form-item>
+          <el-form-item label="服务类型" prop="serverType">
+            <el-select v-model="configQuery.serverType" placeholder="请选择" clearable style="width:160px">
+              <el-option v-for="item in serverTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="租户" prop="tenantId">
+            <el-select v-model="configQuery.tenantId" placeholder="请选择" clearable filterable style="width:200px">
+              <el-option v-for="item in tenantOptions" :key="item.tenantId" :label="item.tenantName" :value="item.tenantId" />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleConfigQuery">搜索</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetConfigQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleConfigAdd">新增</el-button>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="configLoading" :data="configList" border size="small">
+          <el-table-column label="ID" align="center" prop="id" width="70" />
+          <el-table-column label="服务标识" align="center" prop="serviceMarker" min-width="140" show-overflow-tooltip />
+          <el-table-column label="服务类型" align="center" prop="serverTypeName" width="140" />
+          <el-table-column label="租户数量" align="center" prop="tenantCount" width="100" />
+          <el-table-column label="关联租户" align="center" prop="tenantNames" min-width="200" show-overflow-tooltip />
+          <el-table-column label="创建时间" align="center" prop="createTime" width="155" />
+          <el-table-column label="操作" align="center" width="140">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleConfigEdit(scope.row)">修改</el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="handleConfigDelete(scope.row)">删除</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="configTotal > 0"
+          :total="configTotal"
+          :page.sync="configQuery.pageNum"
+          :limit.sync="configQuery.pageSize"
+          @pagination="getConfigList"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="租户CID名额" name="quota">
+        <el-form :inline="true" size="small" class="mb8">
+          <el-form-item label="选择租户">
+            <el-select
+              v-model="selectedTenantIds"
+              multiple
+              filterable
+              collapse-tags
+              placeholder="最多可选择 10 个租户"
+              style="width:420px"
+              :multiple-limit="10"
+              @change="handleTenantSelectChange"
+            >
+              <el-option
+                v-for="item in tenantOptions"
+                :key="item.tenantId"
+                :label="item.tenantName + ' (' + (item.tenantCode || '-') + ')'"
+                :value="item.tenantId"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" :disabled="!selectedTenantIds.length" @click="handleQuotaQuery">查询</el-button>
+            <el-button icon="el-icon-refresh" size="mini" @click="resetQuotaQuery">重置</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="el-icon-plus" size="mini" :disabled="selectedTenantIds.length !== 1" @click="handleAllocateOpen">分配CID名额</el-button>
+          </el-col>
+          <el-col :span="1.5" v-if="selectedTenantIds.length">
+            <span class="selected-tip">已选 {{ selectedTenantIds.length }} 个租户</span>
+          </el-col>
+        </el-row>
+
+        <el-table v-loading="quotaLoading" :data="quotaList" border size="small" empty-text="请选择租户后点击查询">
+          <el-table-column label="租户名称" align="center" prop="tenantName" min-width="120" show-overflow-tooltip />
+          <el-table-column label="租户编码" align="center" prop="tenantCode" width="110" />
+          <el-table-column label="实例名称" align="center" prop="title" min-width="120" show-overflow-tooltip />
+          <el-table-column label="分组号" align="center" prop="groupNo" width="80" />
+          <el-table-column label="总名额" align="center" prop="totalCount" width="80" />
+          <el-table-column label="已用" align="center" prop="usedCount" width="70" />
+          <el-table-column label="剩余" align="center" prop="remainCount" width="70" />
+          <el-table-column label="创建时间" align="center" prop="createTime" width="155" />
+          <el-table-column label="操作" align="center" width="100">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleAdjustOpen(scope.row)">调整</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+    </el-tabs>
+
+    <el-dialog :title="configDialogTitle" :visible.sync="configOpen" width="560px" append-to-body @close="resetConfigForm">
+      <el-form ref="configForm" :model="configForm" :rules="configRules" label-width="100px" size="small">
+        <el-form-item label="服务标识" prop="serviceMarker">
+          <el-input v-model="configForm.serviceMarker" placeholder="如 cidWorkflow 或 tenant-service-marker" />
+        </el-form-item>
+        <el-form-item label="服务类型" prop="serverType">
+          <el-select v-model="configForm.serverType" placeholder="请选择服务类型" style="width:100%">
+            <el-option v-for="item in serverTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="关联租户" prop="tenantIdList">
+          <el-select v-model="configForm.tenantIdList" multiple filterable collapse-tags placeholder="请选择租户" style="width:100%">
+            <el-option v-for="item in tenantOptions" :key="item.tenantId" :label="item.tenantName" :value="item.tenantId" />
+          </el-select>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="configOpen = false">取 消</el-button>
+        <el-button type="primary" :loading="configSubmitLoading" @click="submitConfigForm">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="分配租户CID名额" :visible.sync="allocateOpen" width="480px" append-to-body @close="resetAllocateForm">
+      <el-form ref="allocateForm" :model="allocateForm" :rules="allocateRules" label-width="100px" size="small">
+        <el-form-item label="租户">
+          <span>{{ allocateTenantName || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="实例名称" prop="title">
+          <el-input v-model="allocateForm.title" placeholder="可选,便于识别" />
+        </el-form-item>
+        <el-form-item label="分组号" prop="groupNo">
+          <el-input-number v-model="allocateForm.groupNo" :min="0" :step="1" controls-position="right" style="width:100%" />
+        </el-form-item>
+        <el-form-item label="分配数量" prop="allocateCount">
+          <el-input-number v-model="allocateForm.allocateCount" :min="1" :step="1" controls-position="right" style="width:100%" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="allocateOpen = false">取 消</el-button>
+        <el-button type="primary" :loading="allocateLoading" @click="submitAllocate">确 定</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="调整租户CID名额" :visible.sync="adjustOpen" width="480px" append-to-body>
+      <el-form ref="adjustForm" :model="adjustForm" :rules="adjustRules" label-width="100px" size="small">
+        <el-form-item label="租户">
+          <span>{{ adjustForm.tenantName || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="实例名称">
+          <span>{{ adjustForm.title || '-' }}</span>
+        </el-form-item>
+        <el-form-item label="分组号">
+          <span>{{ adjustForm.groupNo }}</span>
+        </el-form-item>
+        <el-form-item label="已占用">
+          <span>{{ adjustForm.usedCount }}</span>
+        </el-form-item>
+        <el-form-item label="总名额" prop="totalCount">
+          <el-input-number v-model="adjustForm.totalCount" :min="adjustForm.usedCount || 0" :step="1" controls-position="right" style="width:100%" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="adjustOpen = false">取 消</el-button>
+        <el-button type="primary" :loading="adjustLoading" @click="submitAdjust">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+import {
+  listServiceConfig,
+  getServiceConfig,
+  addServiceConfig,
+  updateServiceConfig,
+  delServiceConfig,
+  listCidServerQuota,
+  allocateCidServerQuota,
+  adjustCidServerQuota
+} from '@/api/admin/cidServerManage'
+import { tenantList } from '@/api/tenant/tenant'
+
+export default {
+  name: 'AdminCidServerManage',
+  data() {
+    const validateAdjustTotal = (rule, value, callback) => {
+      const used = this.adjustForm.usedCount || 0
+      if (value == null || value === '') {
+        callback(new Error('请输入总名额'))
+        return
+      }
+      if (Number(value) < used) {
+        callback(new Error('总名额不能小于已占用数量'))
+        return
+      }
+      callback()
+    }
+    return {
+      activeTab: 'serviceConfig',
+      serverTypeOptions: [
+        { value: 1, label: 'CIDWORKFLOW服务' },
+        { value: 2, label: 'WXTASK服务' },
+        { value: 3, label: 'AICALLTASK服务' }
+      ],
+      tenantOptions: [],
+      configLoading: false,
+      configSubmitLoading: false,
+      configList: [],
+      configTotal: 0,
+      configOpen: false,
+      configDialogTitle: '',
+      configQuery: {
+        pageNum: 1,
+        pageSize: 10,
+        serviceMarker: null,
+        serverType: null,
+        tenantId: null
+      },
+      configForm: {
+        id: null,
+        serviceMarker: null,
+        serverType: null,
+        tenantIdList: []
+      },
+      configRules: {
+        serviceMarker: [{ required: true, message: '请输入服务标识', trigger: 'blur' }],
+        serverType: [{ required: true, message: '请选择服务类型', trigger: 'change' }],
+        tenantIdList: [{ type: 'array', required: true, message: '请选择关联租户', trigger: 'change' }]
+      },
+      selectedTenantIds: [],
+      quotaLoading: false,
+      quotaList: [],
+      allocateOpen: false,
+      allocateLoading: false,
+      allocateTenantName: '',
+      allocateForm: {
+        tenantId: null,
+        title: '',
+        groupNo: null,
+        allocateCount: 1
+      },
+      allocateRules: {
+        groupNo: [{ required: true, message: '请输入分组号', trigger: 'blur' }],
+        allocateCount: [{ required: true, message: '请输入分配数量且须大于0', trigger: 'blur' }]
+      },
+      adjustOpen: false,
+      adjustLoading: false,
+      adjustForm: {
+        tenantId: null,
+        tenantName: '',
+        serverId: null,
+        title: '',
+        groupNo: null,
+        usedCount: 0,
+        totalCount: 0
+      },
+      adjustRules: {
+        totalCount: [
+          { required: true, message: '请输入总名额', trigger: 'blur' },
+          { validator: validateAdjustTotal, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+    this.loadTenantOptions()
+    this.getConfigList()
+  },
+  methods: {
+    loadTenantOptions() {
+      tenantList({ status: 1 }).then(res => {
+        const rows = res.rows || res.data || []
+        this.tenantOptions = rows.map(c => ({
+          tenantId: c.id || c.companyId || c.tenantId,
+          tenantName: c.tenantName,
+          tenantCode: c.tenantCode
+        }))
+      })
+    },
+    getConfigList() {
+      this.configLoading = true
+      listServiceConfig(this.configQuery).then(res => {
+        this.configList = res.rows || []
+        this.configTotal = res.total || 0
+      }).finally(() => {
+        this.configLoading = false
+      })
+    },
+    handleConfigQuery() {
+      this.configQuery.pageNum = 1
+      this.getConfigList()
+    },
+    resetConfigQuery() {
+      this.configQuery = {
+        pageNum: 1,
+        pageSize: 10,
+        serviceMarker: null,
+        serverType: null,
+        tenantId: null
+      }
+      this.getConfigList()
+    },
+    resetConfigForm() {
+      this.configForm = { id: null, serviceMarker: null, serverType: null, tenantIdList: [] }
+      if (this.$refs.configForm) {
+        this.$refs.configForm.resetFields()
+      }
+    },
+    handleConfigAdd() {
+      this.resetConfigForm()
+      this.configDialogTitle = '新增服务实例调度'
+      this.configOpen = true
+    },
+    handleConfigEdit(row) {
+      this.resetConfigForm()
+      getServiceConfig(row.id).then(res => {
+        const data = res.data || {}
+        this.configForm = {
+          id: data.id,
+          serviceMarker: data.serviceMarker,
+          serverType: data.serverType,
+          tenantIdList: data.tenantIdList || []
+        }
+        this.configDialogTitle = '修改服务实例调度'
+        this.configOpen = true
+      })
+    },
+    handleConfigDelete(row) {
+      this.$confirm('是否确认删除该服务实例调度?', '提示', { type: 'warning' }).then(() => {
+        return delServiceConfig(row.id)
+      }).then(() => {
+        this.msgSuccess('删除成功')
+        this.getConfigList()
+      }).catch(() => {})
+    },
+    submitConfigForm() {
+      this.$refs.configForm.validate(valid => {
+        if (!valid) return
+        this.configSubmitLoading = true
+        const payload = {
+          id: this.configForm.id,
+          serviceMarker: this.configForm.serviceMarker,
+          serverType: this.configForm.serverType,
+          tenantIds: (this.configForm.tenantIdList || []).join(',')
+        }
+        const req = this.configForm.id ? updateServiceConfig(payload) : addServiceConfig(payload)
+        req.then(() => {
+          this.msgSuccess(this.configForm.id ? '修改成功' : '新增成功')
+          this.configOpen = false
+          this.getConfigList()
+        }).finally(() => {
+          this.configSubmitLoading = false
+        })
+      })
+    },
+    handleTenantSelectChange(val) {
+      if (val && val.length > 10) {
+        this.selectedTenantIds = val.slice(0, 10)
+        this.msgWarning('最多选择 10 个租户')
+      }
+    },
+    handleQuotaQuery() {
+      if (!this.selectedTenantIds.length) {
+        this.msgWarning('请选择租户')
+        return
+      }
+      this.quotaLoading = true
+      listCidServerQuota({ tenantIds: this.selectedTenantIds }).then(res => {
+        this.quotaList = res.data || []
+      }).finally(() => {
+        this.quotaLoading = false
+      })
+    },
+    resetQuotaQuery() {
+      this.selectedTenantIds = []
+      this.quotaList = []
+    },
+    handleAllocateOpen() {
+      if (this.selectedTenantIds.length !== 1) {
+        this.msgWarning('分配名额时只能选择 1 个租户')
+        return
+      }
+      const tenantId = this.selectedTenantIds[0]
+      const tenant = this.tenantOptions.find(t => t.tenantId === tenantId)
+      this.allocateTenantName = tenant ? tenant.tenantName : ''
+      this.allocateForm = {
+        tenantId: tenantId,
+        title: '',
+        groupNo: null,
+        allocateCount: 1
+      }
+      this.allocateOpen = true
+    },
+    resetAllocateForm() {
+      this.allocateForm = { tenantId: null, title: '', groupNo: null, allocateCount: 1 }
+      if (this.$refs.allocateForm) {
+        this.$refs.allocateForm.resetFields()
+      }
+    },
+    submitAllocate() {
+      this.$refs.allocateForm.validate(valid => {
+        if (!valid) return
+        this.allocateLoading = true
+        allocateCidServerQuota(this.allocateForm).then(() => {
+          this.msgSuccess('分配成功')
+          this.allocateOpen = false
+          this.handleQuotaQuery()
+        }).finally(() => {
+          this.allocateLoading = false
+        })
+      })
+    },
+    handleAdjustOpen(row) {
+      this.adjustForm = {
+        tenantId: row.tenantId,
+        tenantName: row.tenantName,
+        serverId: row.serverId,
+        title: row.title,
+        groupNo: row.groupNo,
+        usedCount: row.usedCount,
+        totalCount: row.totalCount
+      }
+      this.adjustOpen = true
+      this.$nextTick(() => {
+        if (this.$refs.adjustForm) {
+          this.$refs.adjustForm.clearValidate()
+        }
+      })
+    },
+    submitAdjust() {
+      this.$refs.adjustForm.validate(valid => {
+        if (!valid) return
+        this.adjustLoading = true
+        adjustCidServerQuota({
+          tenantId: this.adjustForm.tenantId,
+          serverId: this.adjustForm.serverId,
+          totalCount: this.adjustForm.totalCount
+        }).then(() => {
+          this.msgSuccess('调整成功')
+          this.adjustOpen = false
+          this.handleQuotaQuery()
+        }).finally(() => {
+          this.adjustLoading = false
+        })
+      })
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+.cid-server-tabs {
+  background: transparent;
+}
+.cid-server-tabs >>> .el-tabs__header {
+  margin-bottom: 12px;
+}
+.cid-server-tabs >>> .el-tabs__content {
+  padding: 0;
+}
+.mb8 {
+  margin-bottom: 8px;
+}
+.selected-tip {
+  display: inline-block;
+  line-height: 28px;
+  font-size: 13px;
+  color: #909399;
+}
+</style>

+ 1 - 0
src/views/admin/menu.js

@@ -38,6 +38,7 @@ const adminRoutes = {
 
     // 6. 系统配置
     { path: 'cidConfig', component: () => import('@/views/admin/cidConfig/index'), name: 'AdminCidConfig', meta: { title: 'CID配置' } },
+    { path: 'cidServerManage', component: () => import('@/views/admin/cidConfig/cidServerManage'), name: 'AdminCidServerManage', meta: { title: 'CID服务管理' } },
     { path: 'wxConfig', component: () => import('@/views/admin/wxConfig/index'), name: 'AdminWxConfig', meta: { title: '个微配置' } },
     { path: 'ossConfig', component: () => import('@/views/admin/ossConfig/index'), name: 'AdminOssConfig', meta: { title: 'OSS配置' } },
     { path: 'frontConfig', component: () => import('@/views/admin/frontConfig/index'), name: 'AdminFrontConfig', meta: { title: '点播线路配置' } },