|
|
@@ -8,27 +8,17 @@
|
|
|
<el-tag type="info" effect="plain" style="margin-left: 10px;">共 {{ total }} 人</el-tag>
|
|
|
</div>
|
|
|
<div class="right-panel">
|
|
|
- <el-button type="primary" icon="Plus" style="margin-right: 15px" @click="handleCreate" v-hasPermi="['fulfiller:pool:add']">新增履约者</el-button>
|
|
|
- <el-input
|
|
|
- v-model="searchKey"
|
|
|
- placeholder="搜索姓名/手机号/身份证"
|
|
|
- class="search-input"
|
|
|
- prefix-icon="Search"
|
|
|
- clearable
|
|
|
- @keyup.enter="handleSearch"
|
|
|
- @clear="handleSearch"
|
|
|
- />
|
|
|
- <el-cascader
|
|
|
- v-model="filterCascaderValue"
|
|
|
- :options="cityCascaderOptions"
|
|
|
- :props="{ checkStrictly: true }"
|
|
|
- placeholder="所属城市/区域"
|
|
|
- clearable
|
|
|
- style="width: 200px; margin-left: 10px;"
|
|
|
- @change="handleFilterCascaderChange"
|
|
|
- />
|
|
|
- <el-select v-model="queryParams.stationId" placeholder="所属站点" style="width: 150px; margin-left: 10px;" clearable @change="getList">
|
|
|
- <el-option v-for="station in stationOptions" :key="station.id" :label="station.name" :value="station.id" />
|
|
|
+ <el-button type="primary" icon="Plus" style="margin-right: 15px" @click="handleCreate"
|
|
|
+ v-hasPermi="['fulfiller:pool:add']">新增履约者</el-button>
|
|
|
+ <el-input v-model="searchKey" placeholder="搜索姓名/手机号/身份证" class="search-input" prefix-icon="Search" clearable
|
|
|
+ @keyup.enter="handleSearch" @clear="handleSearch" />
|
|
|
+ <el-cascader v-model="filterCascaderValue" :options="cityCascaderOptions" :props="{ checkStrictly: true }"
|
|
|
+ placeholder="所属城市/区域" clearable style="width: 200px; margin-left: 10px;"
|
|
|
+ @change="handleFilterCascaderChange" />
|
|
|
+ <el-select v-model="queryParams.stationId" placeholder="所属站点" style="width: 150px; margin-left: 10px;"
|
|
|
+ clearable @change="getList">
|
|
|
+ <el-option v-for="station in stationOptions" :key="station.id" :label="station.name"
|
|
|
+ :value="station.id" />
|
|
|
</el-select>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -42,7 +32,8 @@
|
|
|
</el-tabs>
|
|
|
</template>
|
|
|
|
|
|
- <el-table v-loading="loading" :data="tableData" style="width: 100%" :header-cell-style="{ background: '#f5f7fa' }">
|
|
|
+ <el-table v-loading="loading" :data="tableData" style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa' }">
|
|
|
<el-table-column label="基本信息" width="280">
|
|
|
<template #default="scope">
|
|
|
<div class="user-info">
|
|
|
@@ -51,13 +42,18 @@
|
|
|
<div class="name-row">
|
|
|
<span class="name">{{ scope.row.name }}</span>
|
|
|
<span class="gender-tag">
|
|
|
- <el-icon v-if="scope.row.gender === '0'" color="#409eff"><Male /></el-icon>
|
|
|
- <el-icon v-else color="#f56c6c"><Female /></el-icon>
|
|
|
- </span>
|
|
|
+ <el-icon v-if="scope.row.gender === '0'" color="#409eff">
|
|
|
+ <Male />
|
|
|
+ </el-icon>
|
|
|
+ <el-icon v-else color="#f56c6c">
|
|
|
+ <Female />
|
|
|
+ </el-icon>
|
|
|
+ </span>
|
|
|
</div>
|
|
|
<div class="tags-row" style="margin: 3px 0">
|
|
|
<!-- work type -->
|
|
|
- <el-tag size="small" :type="scope.row.workType === 'full_time' ? 'warning' : 'info'" effect="light" style="margin-right: 5px">
|
|
|
+ <el-tag size="small" :type="scope.row.workType === 'full_time' ? 'warning' : 'info'" effect="light"
|
|
|
+ style="margin-right: 5px">
|
|
|
{{ scope.row.workType === 'full_time' ? '全职专送' : '兼职众包' }}
|
|
|
</el-tag>
|
|
|
<!-- 等级展示 -->
|
|
|
@@ -75,10 +71,14 @@
|
|
|
<template #default="scope">
|
|
|
<div class="auth-row">
|
|
|
<div class="auth-card" :class="{ active: scope.row.authId }">
|
|
|
- <el-icon><Postcard /></el-icon> 身份证
|
|
|
+ <el-icon>
|
|
|
+ <Postcard />
|
|
|
+ </el-icon> 身份证
|
|
|
</div>
|
|
|
<div class="auth-card" :class="{ active: scope.row.authQual }">
|
|
|
- <el-icon><Medal /></el-icon> 资质证
|
|
|
+ <el-icon>
|
|
|
+ <Medal />
|
|
|
+ </el-icon> 资质证
|
|
|
</div>
|
|
|
</div>
|
|
|
<div style="margin-top:5px;">
|
|
|
@@ -100,14 +100,8 @@
|
|
|
|
|
|
<el-table-column label="技能标签" min-width="180">
|
|
|
<template #default="scope">
|
|
|
- <el-tag
|
|
|
- v-for="tag in scope.row.tags"
|
|
|
- :key="tag.id"
|
|
|
- :type="tag.colorType"
|
|
|
- size="small"
|
|
|
- class="skill-tag"
|
|
|
- effect="plain"
|
|
|
- >
|
|
|
+ <el-tag v-for="tag in scope.row.tags" :key="tag.id" :type="tag.colorType" size="small" class="skill-tag"
|
|
|
+ effect="plain">
|
|
|
{{ tag.name }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
@@ -139,17 +133,24 @@
|
|
|
<el-table-column label="操作" width="240" fixed="right">
|
|
|
<template #default="scope">
|
|
|
<div class="op-cell">
|
|
|
- <el-button link type="primary" size="small" @click="handleDetail(scope.row)" v-hasPermi="['fulfiller:pool:query']">详情</el-button>
|
|
|
- <el-button link type="primary" size="small" @click="handleEdit(scope.row)" v-hasPermi="['fulfiller:pool:edit']">编辑</el-button>
|
|
|
- <el-button link type="warning" size="small" @click="handleReward(scope.row)" v-hasPermi="['fulfiller:pool:edit']">奖惩</el-button>
|
|
|
+ <el-button link type="primary" size="small" @click="handleDetail(scope.row)"
|
|
|
+ v-hasPermi="['fulfiller:pool:query']">详情</el-button>
|
|
|
+ <el-button link type="primary" size="small" @click="handleEdit(scope.row)"
|
|
|
+ v-hasPermi="['fulfiller:pool:edit']">编辑</el-button>
|
|
|
+ <el-button link type="warning" size="small" @click="handleReward(scope.row)"
|
|
|
+ v-hasPermi="['fulfiller:pool:edit']">奖惩</el-button>
|
|
|
<el-dropdown trigger="click" @command="(cmd) => handleCommand(cmd, scope.row)">
|
|
|
<el-button link type="primary">更多<el-icon class="el-icon--right"><arrow-down /></el-icon></el-button>
|
|
|
<template #dropdown>
|
|
|
<el-dropdown-menu>
|
|
|
- <el-dropdown-item command="adjustPoints" v-hasPermi="['fulfiller:pool:edit']">修改积分</el-dropdown-item>
|
|
|
- <el-dropdown-item command="adjustBalance" v-hasPermi="['fulfiller:pool:edit']">余额增减</el-dropdown-item>
|
|
|
- <el-dropdown-item v-if="scope.row.status !== 'disabled'" command="disable" divided style="color: #f56c6c" v-hasPermi="['fulfiller:pool:edit']">禁用账号</el-dropdown-item>
|
|
|
- <el-dropdown-item v-else command="enable" divided style="color: #67c23a" v-hasPermi="['fulfiller:pool:edit']">启用账号</el-dropdown-item>
|
|
|
+ <el-dropdown-item command="adjustPoints"
|
|
|
+ v-hasPermi="['fulfiller:pool:edit']">修改积分</el-dropdown-item>
|
|
|
+ <el-dropdown-item command="adjustBalance"
|
|
|
+ v-hasPermi="['fulfiller:pool:edit']">余额增减</el-dropdown-item>
|
|
|
+ <el-dropdown-item v-if="scope.row.status !== 'disabled'" command="disable" divided
|
|
|
+ style="color: #f56c6c" v-hasPermi="['fulfiller:pool:edit']">禁用账号</el-dropdown-item>
|
|
|
+ <el-dropdown-item v-else command="enable" divided style="color: #67c23a"
|
|
|
+ v-hasPermi="['fulfiller:pool:edit']">启用账号</el-dropdown-item>
|
|
|
<el-dropdown-item command="violation" v-hasPermi="['fulfiller:pool:edit']">违规记录</el-dropdown-item>
|
|
|
<el-dropdown-item command="resetPwd" v-hasPermi="['fulfiller:pool:edit']">重置密码</el-dropdown-item>
|
|
|
</el-dropdown-menu>
|
|
|
@@ -161,46 +162,42 @@
|
|
|
</el-table>
|
|
|
|
|
|
<div class="pagination-container">
|
|
|
- <el-pagination
|
|
|
- v-model:current-page="queryParams.pageNum"
|
|
|
- v-model:page-size="queryParams.pageSize"
|
|
|
- :page-sizes="[10, 20, 50, 100]"
|
|
|
- layout="total, sizes, prev, pager, next, jumper"
|
|
|
- :total="total"
|
|
|
- @size-change="handleSizeChange"
|
|
|
- @current-change="handleCurrentChange"
|
|
|
- />
|
|
|
+ <el-pagination v-model:current-page="queryParams.pageNum" v-model:page-size="queryParams.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper" :total="total"
|
|
|
+ @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
<!-- 详情侧边栏 Drawer -->
|
|
|
- <el-drawer
|
|
|
- v-model="detailVisible"
|
|
|
- title="履约者档案详情"
|
|
|
- size="750px"
|
|
|
- direction="rtl"
|
|
|
- custom-class="detail-drawer"
|
|
|
- >
|
|
|
+ <el-drawer v-model="detailVisible" title="履约者档案详情" size="750px" direction="rtl" custom-class="detail-drawer">
|
|
|
<div class="drawer-content" v-if="currentItem">
|
|
|
<!-- 头部概览 -->
|
|
|
<div class="user-header-card">
|
|
|
- <el-avatar :size="70" :src="currentItem.avatarUrl" class="header-avatar">{{ currentItem.name?.charAt(0) }}</el-avatar>
|
|
|
+ <el-avatar :size="70" :src="currentItem.avatarUrl" class="header-avatar">{{ currentItem.name?.charAt(0)
|
|
|
+ }}</el-avatar>
|
|
|
<div class="header-info">
|
|
|
<div class="top-row">
|
|
|
<span class="user-name">{{ currentItem.name }}</span>
|
|
|
- <el-tag size="small" :type="currentItem.gender === '0' ? '' : 'danger'" effect="plain" round style="margin-left: 8px;">
|
|
|
+ <el-tag size="small" :type="currentItem.gender === '0' ? '' : 'danger'" effect="plain" round
|
|
|
+ style="margin-left: 8px;">
|
|
|
{{ currentItem.gender === '0' ? '男' : '女' }} {{ currentItem.age }}岁
|
|
|
</el-tag>
|
|
|
<span class="status-badge" :class="currentItem.status">{{ getStatusText(currentItem.status) }}</span>
|
|
|
</div>
|
|
|
<div class="sub-row">
|
|
|
- <span class="info-item"><el-icon><Iphone /></el-icon> {{ currentItem.phone }}</span>
|
|
|
+ <span class="info-item"><el-icon>
|
|
|
+ <Iphone />
|
|
|
+ </el-icon> {{ currentItem.phone }}</span>
|
|
|
<span class="divider">|</span>
|
|
|
- <span class="info-item"><el-icon><Location /></el-icon> {{ currentItem.cityName }}</span>
|
|
|
+ <span class="info-item"><el-icon>
|
|
|
+ <Location />
|
|
|
+ </el-icon> {{ currentItem.cityName }}</span>
|
|
|
</div>
|
|
|
<div class="tags-row">
|
|
|
- <el-tag size="small" :type="getLevelType(currentItem.levelName)" effect="dark">{{ getLevelText(currentItem.levelName) }}</el-tag>
|
|
|
- <el-tag size="small" type="warning" effect="plain" v-if="currentItem.workType === 'full_time'" style="margin-left:5px">全职专送</el-tag>
|
|
|
+ <el-tag size="small" :type="getLevelType(currentItem.levelName)" effect="dark">{{
|
|
|
+ getLevelText(currentItem.levelName) }}</el-tag>
|
|
|
+ <el-tag size="small" type="warning" effect="plain" v-if="currentItem.workType === 'full_time'"
|
|
|
+ style="margin-left:5px">全职专送</el-tag>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -235,11 +232,13 @@
|
|
|
<div class="section-title">基础信息</div>
|
|
|
<el-descriptions :column="2" border>
|
|
|
<el-descriptions-item label="身份证号">{{ currentItem.idCard }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="真实姓名">{{ currentItem.realName || currentItem.name }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="真实姓名">{{ currentItem.realName || currentItem.name
|
|
|
+ }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="归属站点">{{ currentItem.stationName }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="证件有效期">{{ currentItem.idCardExpiry || '-' }}</el-descriptions-item>
|
|
|
<el-descriptions-item label="入驻时间">{{ currentItem.createTime }}</el-descriptions-item>
|
|
|
- <el-descriptions-item label="工作性质">{{ currentItem.workType === 'full_time' ? '全职' : '兼职' }}</el-descriptions-item>
|
|
|
+ <el-descriptions-item label="工作性质">{{ currentItem.workType === 'full_time' ? '全职' : '兼职'
|
|
|
+ }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
</div>
|
|
|
|
|
|
@@ -248,13 +247,21 @@
|
|
|
<div class="cert-row">
|
|
|
<div class="cert-item" @click="handleViewImage(currentItem.idCardFrontUrl)">
|
|
|
<el-image :src="currentItem.idCardFrontUrl || ''" fit="cover" class="cert-img">
|
|
|
- <template #error><div class="img-slot"><el-icon><Picture /></el-icon></div></template>
|
|
|
+ <template #error>
|
|
|
+ <div class="img-slot"><el-icon>
|
|
|
+ <Picture />
|
|
|
+ </el-icon></div>
|
|
|
+ </template>
|
|
|
</el-image>
|
|
|
<div class="cert-name">身份证人像面</div>
|
|
|
</div>
|
|
|
<div class="cert-item" @click="handleViewImage(currentItem.idCardBackUrl)">
|
|
|
<el-image :src="currentItem.idCardBackUrl || ''" fit="cover" class="cert-img">
|
|
|
- <template #error><div class="img-slot"><el-icon><Picture /></el-icon></div></template>
|
|
|
+ <template #error>
|
|
|
+ <div class="img-slot"><el-icon>
|
|
|
+ <Picture />
|
|
|
+ </el-icon></div>
|
|
|
+ </template>
|
|
|
</el-image>
|
|
|
<div class="cert-name">身份证国徽面</div>
|
|
|
</div>
|
|
|
@@ -264,9 +271,14 @@
|
|
|
<div class="section-block">
|
|
|
<div class="section-title">资质认证</div>
|
|
|
<div class="cert-row" v-if="qualImageUrlList.length">
|
|
|
- <div class="cert-item" v-for="(img, index) in qualImageUrlList" :key="index" @click="handleViewImage(img)">
|
|
|
+ <div class="cert-item" v-for="(img, index) in qualImageUrlList" :key="index"
|
|
|
+ @click="handleViewImage(img)">
|
|
|
<el-image :src="img" fit="cover" class="cert-img">
|
|
|
- <template #error><div class="img-slot"><el-icon><Picture /></el-icon></div></template>
|
|
|
+ <template #error>
|
|
|
+ <div class="img-slot"><el-icon>
|
|
|
+ <Picture />
|
|
|
+ </el-icon></div>
|
|
|
+ </template>
|
|
|
</el-image>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -275,7 +287,8 @@
|
|
|
<div class="section-block">
|
|
|
<div class="section-title">技能标签</div>
|
|
|
<div class="tag-list">
|
|
|
- <el-tag v-for="tag in currentItem.tags" :key="tag.id" :type="tag.colorType" size="large" style="margin-right: 12px; margin-bottom: 8px;">{{ tag.name }}</el-tag>
|
|
|
+ <el-tag v-for="tag in currentItem.tags" :key="tag.id" :type="tag.colorType" size="large"
|
|
|
+ style="margin-right: 12px; margin-bottom: 8px;">{{ tag.name }}</el-tag>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -283,7 +296,8 @@
|
|
|
|
|
|
<el-tab-pane label="服务订单" name="orders">
|
|
|
<div class="tab-content-wrapper">
|
|
|
- <el-table v-loading="logLoading" :data="serviceOrderData" stripe style="width: 100%" :header-cell-style="{background:'#f5f7fa', color:'#606266'}">
|
|
|
+ <el-table v-loading="logLoading" :data="serviceOrderData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
<el-table-column prop="code" label="订单号" width="160" show-overflow-tooltip />
|
|
|
<el-table-column label="服务项目" show-overflow-tooltip>
|
|
|
<template #default="{ row }">
|
|
|
@@ -292,7 +306,8 @@
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="price" label="收入" width="100">
|
|
|
<template #default="{ row }">
|
|
|
- <span style="color: #67c23a; font-weight: bold; font-size: 15px;">+{{ (row.price / 100).toFixed(2) }}</span>
|
|
|
+ <span style="color: #67c23a; font-weight: bold; font-size: 15px;">+{{ (row.price / 100).toFixed(2)
|
|
|
+ }}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="serviceTime" label="时间" width="160" show-overflow-tooltip />
|
|
|
@@ -309,18 +324,21 @@
|
|
|
|
|
|
<el-tab-pane label="积分记录" name="pointLogs">
|
|
|
<div class="tab-content-wrapper">
|
|
|
- <el-table v-loading="logLoading" :data="pointsLogData" stripe style="width: 100%" :header-cell-style="{background:'#f5f7fa', color:'#606266'}">
|
|
|
+ <el-table v-loading="logLoading" :data="pointsLogData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
<el-table-column prop="createTime" label="变动时间" width="180" />
|
|
|
<el-table-column prop="bizType" label="业务类型" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <el-tag :type="getPointsBizTypeTag(row.bizType)" size="small" effect="plain">{{ getPointsBizTypeName(row.bizType) }}</el-tag>
|
|
|
+ <el-tag :type="getPointsBizTypeTag(row.bizType)" size="small" effect="plain">{{
|
|
|
+ getPointsBizTypeName(row.bizType) }}</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="amount" label="变动数值" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <span :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '15px' }">
|
|
|
- {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ row.amount }}
|
|
|
- </span>
|
|
|
+ <span
|
|
|
+ :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '15px' }">
|
|
|
+ {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ row.amount }}
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="reason" label="变动原因" show-overflow-tooltip />
|
|
|
@@ -331,18 +349,22 @@
|
|
|
|
|
|
<el-tab-pane label="余额变动" name="balanceLogs">
|
|
|
<div class="tab-content-wrapper">
|
|
|
- <el-table v-loading="logLoading" :data="balanceLogData" stripe style="width: 100%" :header-cell-style="{background:'#f5f7fa', color:'#606266'}">
|
|
|
+ <el-table v-loading="logLoading" :data="balanceLogData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
<el-table-column prop="createTime" label="变动时间" width="180" show-overflow-tooltip />
|
|
|
<el-table-column prop="subType" label="资金类型" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <el-tag :type="getBalanceBizTypeTag(row.subType)" size="small" effect="plain">{{ getBalanceBizTypeName(row.bizType) }}</el-tag>
|
|
|
+ <el-tag :type="getBalanceBizTypeTag(row.subType)" size="small" effect="plain">{{
|
|
|
+ getBalanceBizTypeName(row.bizType) }}</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="amount" label="变动金额" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <span :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '15px' }">
|
|
|
- {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ (row.amount / 100).toFixed(2) }}
|
|
|
- </span>
|
|
|
+ <span
|
|
|
+ :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold', fontSize: '15px' }">
|
|
|
+ {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ (row.amount /
|
|
|
+ 100).toFixed(2) }}
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="balanceAfter" label="变动后余额" width="120">
|
|
|
@@ -358,11 +380,13 @@
|
|
|
|
|
|
<el-tab-pane label="奖惩记录" name="rewards">
|
|
|
<div class="tab-content-wrapper">
|
|
|
- <el-table v-loading="logLoading" :data="rewardLogData" stripe style="width: 100%" :header-cell-style="{background:'#f5f7fa', color:'#606266'}">
|
|
|
+ <el-table v-loading="logLoading" :data="rewardLogData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
<el-table-column prop="createTime" label="操作时间" width="180" />
|
|
|
<el-table-column prop="bizType" label="奖惩类型" width="100">
|
|
|
<template #default="{ row }">
|
|
|
- <el-tag :type="fulfillerEnums.RewardBizType[row.bizType]?.tagType || 'info'" size="small" effect="plain">
|
|
|
+ <el-tag :type="fulfillerEnums.RewardBizType[row.bizType]?.tagType || 'info'" size="small"
|
|
|
+ effect="plain">
|
|
|
{{ getRewardBizTypeName(row.bizType) }}
|
|
|
</el-tag>
|
|
|
</template>
|
|
|
@@ -374,9 +398,12 @@
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="amount" label="涉及数值" width="120">
|
|
|
<template #default="{ row }">
|
|
|
- <span :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold' }">
|
|
|
- {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ row.target === 'balance' ? (row.amount / 100).toFixed(2) : row.amount }} {{ row.target === 'points' ? '分' : '元' }}
|
|
|
- </span>
|
|
|
+ <span
|
|
|
+ :style="{ color: ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '#67c23a' : '#f56c6c', fontWeight: 'bold' }">
|
|
|
+ {{ ['reward', fulfillerEnums.ActionType.ADD].includes(row.type) ? '+' : '-' }}{{ row.target ===
|
|
|
+ 'balance' ? (row.amount / 100).toFixed(2) : row.amount }} {{ row.target === 'points' ? '分' : '元'
|
|
|
+ }}
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="reason" label="奖惩原因" show-overflow-tooltip />
|
|
|
@@ -387,24 +414,39 @@
|
|
|
|
|
|
<el-tab-pane label="违规记录" name="violation">
|
|
|
<div class="tab-content-wrapper">
|
|
|
- <el-table v-loading="logLoading" :data="violationLogData" stripe style="width: 100%" :header-cell-style="{background:'#f5f7fa', color:'#606266'}">
|
|
|
+ <el-table v-loading="logLoading" :data="violationLogData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
<el-table-column prop="violationTime" label="违规时间" width="180">
|
|
|
- <template #default="{ row }">
|
|
|
- <div style="display: flex; align-items: center; gap: 5px;">
|
|
|
- <el-icon color="#909399"><Timer /></el-icon>
|
|
|
- <span>{{ row.violationTime }}</span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="count" label="违规次数" width="120" align="center">
|
|
|
- <template #default="{ row }">
|
|
|
- <el-tag type="danger" effect="plain" round v-if="row.count > 0">{{ row.count }} 次</el-tag>
|
|
|
- </template>
|
|
|
</el-table-column>
|
|
|
+ <el-table-column prop="count" label="违规次数" width="100" />
|
|
|
<el-table-column prop="reason" label="违规原因" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="operatorName" label="操作人" width="100" />
|
|
|
</el-table>
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="投诉记录" name="complaints">
|
|
|
+ <div class="tab-content-wrapper">
|
|
|
+ <el-table v-loading="logLoading" :data="complaintLogData" stripe style="width: 100%"
|
|
|
+ :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
|
|
+ <el-table-column prop="createTime" label="投诉时间" width="180" />
|
|
|
+ <el-table-column prop="orderCode" label="订单号" width="160" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="reason" label="投诉原因" show-overflow-tooltip />
|
|
|
+ <el-table-column prop="createBy" label="操作人" width="100" />
|
|
|
+ </el-table>
|
|
|
+ <div style="margin-top: 20px; display: flex; justify-content: flex-end;">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="complaintPagination.pageNum"
|
|
|
+ v-model:page-size="complaintPagination.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50]"
|
|
|
+ layout="total, sizes, prev, pager, next"
|
|
|
+ :total="complaintPagination.total"
|
|
|
+ @size-change="loadComplaintLogs"
|
|
|
+ @current-change="loadComplaintLogs"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
</el-tabs>
|
|
|
</div>
|
|
|
</el-drawer>
|
|
|
@@ -446,13 +488,16 @@
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="服务城市">
|
|
|
- <el-cascader v-model="editDialog.cascaderValue" :options="cityCascaderOptions" :props="{ checkStrictly: true }" placeholder="请选择城市/区域" clearable style="width: 100%" @change="handleEditCascaderChange" />
|
|
|
+ <el-cascader v-model="editDialog.cascaderValue" :options="cityCascaderOptions"
|
|
|
+ :props="{ checkStrictly: true }" placeholder="请选择城市/区域" clearable style="width: 100%"
|
|
|
+ @change="handleEditCascaderChange" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="归属站点">
|
|
|
<el-select v-model="editDialog.form.stationId" placeholder="请选择站点" style="width: 100%">
|
|
|
- <el-option v-for="station in editDialog.stationOptions" :key="station.id" :label="station.name" :value="station.id" />
|
|
|
+ <el-option v-for="station in editDialog.stationOptions" :key="station.id" :label="station.name"
|
|
|
+ :value="station.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
@@ -461,7 +506,7 @@
|
|
|
<el-row :gutter="20">
|
|
|
<el-col :span="12">
|
|
|
<el-form-item label="等级">
|
|
|
- <el-input v-model="editDialog.form.levelId" placeholder="等级ID" />
|
|
|
+ <el-input v-model="editDialog.form.level" placeholder="等级" />
|
|
|
</el-form-item>
|
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
|
@@ -482,10 +527,10 @@
|
|
|
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="editDialog.visible = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="saveEdit">保存变更</el-button>
|
|
|
- </span>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="editDialog.visible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="saveEdit">保存变更</el-button>
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
@@ -515,10 +560,10 @@
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<template #footer>
|
|
|
- <span class="dialog-footer">
|
|
|
- <el-button @click="rewardDialog.visible = false">取消</el-button>
|
|
|
- <el-button type="primary" @click="submitReward">确认执行</el-button>
|
|
|
- </span>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="rewardDialog.visible = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitReward">确认执行</el-button>
|
|
|
+ </span>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
|
|
|
@@ -541,11 +586,14 @@
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="服务城市">
|
|
|
- <el-cascader v-model="createDialog.cascaderValue" :options="cityCascaderOptions" :props="{ checkStrictly: true }" placeholder="请选择城市/区域" clearable style="width: 100%" @change="handleCreateCascaderChange" />
|
|
|
+ <el-cascader v-model="createDialog.cascaderValue" :options="cityCascaderOptions"
|
|
|
+ :props="{ checkStrictly: true }" placeholder="请选择城市/区域" clearable style="width: 100%"
|
|
|
+ @change="handleCreateCascaderChange" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="归属站点">
|
|
|
<el-select v-model="createDialog.form.stationId" placeholder="请选择站点" style="width: 100%">
|
|
|
- <el-option v-for="station in createDialog.stationOptions" :key="station.id" :label="station.name" :value="station.id" />
|
|
|
+ <el-option v-for="station in createDialog.stationOptions" :key="station.id" :label="station.name"
|
|
|
+ :value="station.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
@@ -561,15 +609,12 @@
|
|
|
<el-form-item label="违规次数" required>
|
|
|
<el-input-number v-model="violationDialog.form.count" :min="1" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
+ <el-form-item label="扣罚积分" required>
|
|
|
+ <el-input-number v-model="violationDialog.form.points" :min="0" style="width: 100%" placeholder="违规扣罚积分" />
|
|
|
+ </el-form-item>
|
|
|
<el-form-item label="违规时间" required>
|
|
|
- <el-date-picker
|
|
|
- v-model="violationDialog.form.violationTime"
|
|
|
- type="datetime"
|
|
|
- placeholder="请选择违规时间"
|
|
|
- format="YYYY-MM-DD HH:mm:ss"
|
|
|
- value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
- style="width: 100%"
|
|
|
- />
|
|
|
+ <el-date-picker v-model="violationDialog.form.violationTime" type="datetime" placeholder="请选择违规时间"
|
|
|
+ format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="违规原因" required>
|
|
|
<el-input v-model="violationDialog.form.reason" type="textarea" :rows="3" placeholder="请输入违规原因说明" />
|
|
|
@@ -610,10 +655,12 @@
|
|
|
<el-dialog v-model="balanceDialog.visible" title="余额增减" width="450px">
|
|
|
<el-form :model="balanceDialog.form" label-width="80px">
|
|
|
<el-form-item label="当前余额">
|
|
|
- <span style="color: #f56c6c; font-weight: bold">¥{{ (balanceDialog.currentRow?.balance / 100).toFixed(2) }}</span>
|
|
|
+ <span style="color: #f56c6c; font-weight: bold">¥{{ (balanceDialog.currentRow?.balance / 100).toFixed(2)
|
|
|
+ }}</span>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="扣减类型">
|
|
|
- <el-radio-group v-model="balanceDialog.form.type" @change="balanceDialog.form.subType = balanceDialog.form.type === fulfillerEnums.ActionType.ADD ? 'admin_reward' : 'admin_punish'">
|
|
|
+ <el-radio-group v-model="balanceDialog.form.type"
|
|
|
+ @change="balanceDialog.form.subType = balanceDialog.form.type === fulfillerEnums.ActionType.ADD ? 'admin_reward' : 'admin_punish'">
|
|
|
<el-radio :label="fulfillerEnums.ActionType.ADD">增加</el-radio>
|
|
|
<el-radio :label="fulfillerEnums.ActionType.REDUCE">减少</el-radio>
|
|
|
</el-radio-group>
|
|
|
@@ -656,6 +703,7 @@ import {
|
|
|
} from '@/api/fulfiller/pool'
|
|
|
import { addViolation, listViolationByFulfiller } from '@/api/fulfiller/violation'
|
|
|
import type { FlfViolationVO } from '@/api/fulfiller/violation/types'
|
|
|
+import { pageComplaintByFulfiller } from '@/api/fulfiller/complaint'
|
|
|
import { listSubOrderOnFulfiller } from '@/api/order/subOrder/index'
|
|
|
import { listOnStore as listServiceOnStore } from '@/api/service/list/index'
|
|
|
import type {
|
|
|
@@ -669,6 +717,8 @@ import { listOnStore } from '@/api/system/areaStation'
|
|
|
import type { SysAreaStationOnStoreVo } from '@/api/system/areaStation/types'
|
|
|
import fulfillerEnums from '@/enums/fulfiller.json'
|
|
|
import ImageUpload from '@/components/ImageUpload/index.vue'
|
|
|
+import { listAllLevelRights, addLevelRights, updateLevelRights, delLevelRights, changeLevelRightsStatus } from '@/api/fulfiller/levelRights';
|
|
|
+import { listAllLevelConfig, addLevelConfig, updateLevelConfig, delLevelConfig } from '@/api/fulfiller/levelConfig';
|
|
|
|
|
|
const loading = ref(false)
|
|
|
const searchKey = ref('')
|
|
|
@@ -702,6 +752,8 @@ const pointsLogData = ref<FlfPointsLogVO[]>([])
|
|
|
const balanceLogData = ref<FlfBalanceLogVO[]>([])
|
|
|
const rewardLogData = ref<FlfRewardLogVO[]>([])
|
|
|
const violationLogData = ref<FlfViolationVO[]>([])
|
|
|
+const complaintLogData = ref<any[]>([])
|
|
|
+const complaintPagination = reactive({ pageNum: 1, pageSize: 20, total: 0 })
|
|
|
const serviceOrderData = ref<any[]>([])
|
|
|
const serviceOptions = ref<any[]>([])
|
|
|
const logLoading = ref(false)
|
|
|
@@ -806,25 +858,25 @@ const getRewardBizTypeName = (type: string) => {
|
|
|
|
|
|
/** 加载服务项目列表用于名称映射 */
|
|
|
const loadServiceOptions = async () => {
|
|
|
- try {
|
|
|
- const res = await listServiceOnStore()
|
|
|
- serviceOptions.value = res.data || []
|
|
|
- } catch { /* ignore */ }
|
|
|
+ try {
|
|
|
+ const res = await listServiceOnStore()
|
|
|
+ serviceOptions.value = res.data || []
|
|
|
+ } catch { /* ignore */ }
|
|
|
}
|
|
|
|
|
|
const getServiceName = (serviceId: number | string) => {
|
|
|
- const item = serviceOptions.value.find(i => i.id === serviceId)
|
|
|
- return item ? item.name : '未知服务'
|
|
|
+ const item = serviceOptions.value.find(i => i.id === serviceId)
|
|
|
+ return item ? item.name : '未知服务'
|
|
|
}
|
|
|
|
|
|
const getSubOrderStatusName = (status: number) => {
|
|
|
- const map: Record<number, string> = { 0: '待派单', 1: '待接单', 2: '待服务', 3: '服务中', 4: '已完成', 5: '已取消' }
|
|
|
- return map[status] || '未知'
|
|
|
+ const map: Record<number, string> = { 0: '待派单', 1: '待接单', 2: '待服务', 3: '服务中', 4: '已完成', 5: '已取消' }
|
|
|
+ return map[status] || '未知'
|
|
|
}
|
|
|
|
|
|
const getSubOrderStatusType = (status: number) => {
|
|
|
- const map: Record<number, string> = { 0: 'info', 1: 'warning', 2: 'primary', 3: 'success', 4: 'success', 5: 'danger' }
|
|
|
- return map[status] || 'info'
|
|
|
+ const map: Record<number, string> = { 0: 'info', 1: 'warning', 2: 'primary', 3: 'success', 4: 'success', 5: 'danger' }
|
|
|
+ return map[status] || 'info'
|
|
|
}
|
|
|
|
|
|
const rewardDialog = reactive({
|
|
|
@@ -868,7 +920,8 @@ const violationDialog = reactive({
|
|
|
form: {
|
|
|
count: 1,
|
|
|
violationTime: '',
|
|
|
- reason: ''
|
|
|
+ reason: '',
|
|
|
+ points: 0
|
|
|
}
|
|
|
})
|
|
|
|
|
|
@@ -914,6 +967,24 @@ const loadLogs = async (fulfillerId: string | number) => {
|
|
|
} catch { /* ignore */ } finally {
|
|
|
logLoading.value = false
|
|
|
}
|
|
|
+ loadComplaintLogs(fulfillerId)
|
|
|
+}
|
|
|
+
|
|
|
+const loadComplaintLogs = async (fulfillerId?: string | number) => {
|
|
|
+ const id = fulfillerId || currentItem.value?.id
|
|
|
+ if (!id) return
|
|
|
+ logLoading.value = true
|
|
|
+ try {
|
|
|
+ const res = await pageComplaintByFulfiller({
|
|
|
+ fulfiller: id,
|
|
|
+ pageNum: complaintPagination.pageNum,
|
|
|
+ pageSize: complaintPagination.pageSize
|
|
|
+ })
|
|
|
+ complaintLogData.value = res.rows || []
|
|
|
+ complaintPagination.total = res.total || 0
|
|
|
+ } catch { /* ignore */ } finally {
|
|
|
+ logLoading.value = false
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
const handleDetail = async (row: FlfFulfillerVO) => {
|
|
|
@@ -938,7 +1009,7 @@ const handleEdit = (row: FlfFulfillerVO) => {
|
|
|
cityCode: row.cityCode,
|
|
|
cityName: row.cityName,
|
|
|
stationId: row.stationId,
|
|
|
- levelId: row.levelId,
|
|
|
+ level: row.level,
|
|
|
status: row.status,
|
|
|
authId: row.authId,
|
|
|
authQual: row.authQual,
|
|
|
@@ -1053,12 +1124,27 @@ const handleCommand = async (cmd: string, row: FlfFulfillerVO) => {
|
|
|
} catch { /* handled by interceptor */ }
|
|
|
} else if (cmd === 'violation') {
|
|
|
violationDialog.fulfillerId = row.id
|
|
|
- violationDialog.form = {
|
|
|
- count: 1,
|
|
|
- violationTime: new Date().toISOString().replace('T', ' ').split('.')[0],
|
|
|
- reason: ''
|
|
|
+ // 获取当前履约者等级对应的违规扣罚积分
|
|
|
+ const getDefaultPoints = async () => {
|
|
|
+ try {
|
|
|
+ const levelConfigRes = await listAllLevelConfig()
|
|
|
+ const currentLevelConfig = levelConfigRes.data.find((config: any) => config.lvNo === row.level)
|
|
|
+ const defaultPoints = currentLevelConfig?.degradeViolationsScore || 0
|
|
|
+ return defaultPoints
|
|
|
+ } catch {
|
|
|
+ return 0
|
|
|
+ }
|
|
|
}
|
|
|
- violationDialog.visible = true
|
|
|
+
|
|
|
+ getDefaultPoints().then(defaultPoints => {
|
|
|
+ violationDialog.form = {
|
|
|
+ count: 1,
|
|
|
+ violationTime: new Date().toISOString().replace('T', ' ').split('.')[0],
|
|
|
+ reason: '',
|
|
|
+ points: defaultPoints
|
|
|
+ }
|
|
|
+ violationDialog.visible = true
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1167,47 +1253,168 @@ onMounted(() => {
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.page-container { padding: 20px; }
|
|
|
-.table-card { border-radius: 8px; border: none; }
|
|
|
-.card-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
|
|
+.page-container {
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.table-card {
|
|
|
+ border-radius: 8px;
|
|
|
+ border: none;
|
|
|
+}
|
|
|
+
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.status-tabs {
|
|
|
+ margin-top: -15px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-tabs__header) {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
|
|
|
-.status-tabs { margin-top: -15px; }
|
|
|
-:deep(.el-tabs__header) { margin-bottom: 0; }
|
|
|
-:deep(.el-tabs__nav-wrap::after) { height: 1px; background-color: #f0f2f5; }
|
|
|
+:deep(.el-tabs__nav-wrap::after) {
|
|
|
+ height: 1px;
|
|
|
+ background-color: #f0f2f5;
|
|
|
+}
|
|
|
+
|
|
|
+.title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
|
|
|
-.title { font-size: 18px; font-weight: bold; color: #303133; }
|
|
|
-.right-panel { display: flex; align-items: center; }
|
|
|
-.search-input { width: 240px; }
|
|
|
+.right-panel {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.search-input {
|
|
|
+ width: 240px;
|
|
|
+}
|
|
|
|
|
|
/* Table Content Styles */
|
|
|
-.user-info { display: flex; align-items: center; }
|
|
|
-.text-col { margin-left: 10px; display: flex; flex-direction: column; justify-content: center; }
|
|
|
-.name-row { font-weight: bold; font-size: 14px; color: #333; display: flex; align-items: center; }
|
|
|
-.gender-tag { margin-left: 5px; display: flex; align-items: center; }
|
|
|
-.sub-text { font-size: 12px; color: #999; margin-top: 2px; }
|
|
|
+.user-info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.text-col {
|
|
|
+ margin-left: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.name-row {
|
|
|
+ font-weight: bold;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #333;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.gender-tag {
|
|
|
+ margin-left: 5px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.sub-text {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #999;
|
|
|
+ margin-top: 2px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 8px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
|
|
|
-.auth-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
|
|
.auth-card {
|
|
|
- font-size: 12px; padding: 2px 6px; border-radius: 4px; background: #f4f4f5; color: #909399;
|
|
|
- display: flex; align-items: center; gap: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 2px 6px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #f4f4f5;
|
|
|
+ color: #909399;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-card.active {
|
|
|
+ background: #ecf5ff;
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.auth-card.need-review {
|
|
|
+ background: #fef0f0;
|
|
|
+ color: #f56c6c;
|
|
|
+ border: 1px dashed #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.finance-item {
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+.num {
|
|
|
+ font-weight: bold;
|
|
|
+ font-family: DIN, sans-serif;
|
|
|
+ margin-left: 5px;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.num.error {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.status-cell {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.status-dot {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ margin-right: 6px;
|
|
|
}
|
|
|
-.auth-card.active { background: #ecf5ff; color: #409eff; }
|
|
|
-.auth-card.need-review { background: #fef0f0; color: #f56c6c; border: 1px dashed #f56c6c; }
|
|
|
|
|
|
-.finance-item { font-size: 13px; color: #606266; line-height: 1.6; }
|
|
|
-.num { font-weight: bold; font-family: DIN, sans-serif; margin-left: 5px; color: #303133; }
|
|
|
-.num.error { color: #f56c6c; }
|
|
|
+.status-dot.resting {
|
|
|
+ background: #e6a23c;
|
|
|
+}
|
|
|
|
|
|
-.status-cell { display: flex; align-items: center; }
|
|
|
-.status-dot { width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; }
|
|
|
-.status-dot.resting { background: #e6a23c; }
|
|
|
-.status-dot.busy { background: #409eff; }
|
|
|
-.status-dot.disabled { background: #f56c6c; }
|
|
|
-.status-dot.frozen { background: #909399; }
|
|
|
+.status-dot.busy {
|
|
|
+ background: #409eff;
|
|
|
+}
|
|
|
|
|
|
-.op-cell { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
|
|
|
+.status-dot.disabled {
|
|
|
+ background: #f56c6c;
|
|
|
+}
|
|
|
|
|
|
-.pagination-container { display: flex; justify-content: flex-end; margin-top: 20px; }
|
|
|
+.status-dot.frozen {
|
|
|
+ background: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.op-cell {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 5px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
|
|
|
/* Drawer Styles */
|
|
|
.user-header-card {
|
|
|
@@ -1218,24 +1425,77 @@ onMounted(() => {
|
|
|
border-radius: 8px;
|
|
|
margin-bottom: 25px;
|
|
|
}
|
|
|
-.header-info { margin-left: 20px; flex: 1; }
|
|
|
-.top-row { display: flex; align-items: center; margin-bottom: 8px; }
|
|
|
-.user-name { font-size: 20px; font-weight: bold; color: #303133; }
|
|
|
+
|
|
|
+.header-info {
|
|
|
+ margin-left: 20px;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.top-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.user-name {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
.status-badge {
|
|
|
margin-left: auto;
|
|
|
- font-size: 12px; padding: 4px 10px; border-radius: 12px;
|
|
|
- background: #e1f3d8; color: #67c23a;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 4px 10px;
|
|
|
+ border-radius: 12px;
|
|
|
+ background: #e1f3d8;
|
|
|
+ color: #67c23a;
|
|
|
+}
|
|
|
+
|
|
|
+.status-badge.resting {
|
|
|
+ background: #faecd8;
|
|
|
+ color: #e6a23c;
|
|
|
}
|
|
|
-.status-badge.resting { background: #faecd8; color: #e6a23c; }
|
|
|
-.status-badge.disabled { background: #fde2e2; color: #f56c6c; }
|
|
|
-.status-badge.busy { background: #d9ecff; color: #409eff; }
|
|
|
-.status-badge.frozen { background: #f0f9eb; color: #909399; }
|
|
|
|
|
|
-.sub-row { display: flex; align-items: center; font-size: 13px; color: #606266; margin-bottom: 8px; }
|
|
|
-.info-item { display: flex; align-items: center; gap: 4px; }
|
|
|
-.divider { margin: 0 10px; color: #dcdfe6; }
|
|
|
+.status-badge.disabled {
|
|
|
+ background: #fde2e2;
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
|
|
|
-.tags-row { display: flex; align-items: center; gap: 5px; }
|
|
|
+.status-badge.busy {
|
|
|
+ background: #d9ecff;
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.status-badge.frozen {
|
|
|
+ background: #f0f9eb;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.sub-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.info-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.divider {
|
|
|
+ margin: 0 10px;
|
|
|
+ color: #dcdfe6;
|
|
|
+}
|
|
|
+
|
|
|
+.tags-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 5px;
|
|
|
+}
|
|
|
|
|
|
.data-metrics-row {
|
|
|
display: flex;
|
|
|
@@ -1245,25 +1505,104 @@ onMounted(() => {
|
|
|
background: #fff;
|
|
|
border-bottom: 1px solid #f0f0f0;
|
|
|
}
|
|
|
-.metric-item { text-align: center; flex: 1; }
|
|
|
-.val { font-size: 20px; font-weight: bold; color: #303133; font-family: DIN, sans-serif; margin-bottom: 4px; }
|
|
|
-.lbl { font-size: 12px; color: #909399; }
|
|
|
-.text-primary { color: #409eff; }
|
|
|
-.text-danger { color: #f56c6c; }
|
|
|
-.text-warning { color: #e6a23c; }
|
|
|
-.divider-v { width: 1px; background: #e0e0e0; height: 30px; align-self: center; }
|
|
|
-
|
|
|
-.detail-tabs { margin-top: 0; }
|
|
|
-.section-block { margin-bottom: 25px; }
|
|
|
-.section-title { font-size: 15px; font-weight: bold; margin-bottom: 15px; border-left: 4px solid #409eff; padding-left: 10px; }
|
|
|
-
|
|
|
-.cert-row { display: flex; gap: 15px; }
|
|
|
-.cert-item { text-align: center; cursor: pointer; }
|
|
|
-.cert-img { width: 120px; height: 80px; border-radius: 6px; border: 1px solid #dcdfe6; background: #f5f7fa; }
|
|
|
-.img-slot { display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; color: #909399; font-size: 24px; }
|
|
|
-.cert-name { font-size: 12px; color: #606266; margin-top: 5px; }
|
|
|
-
|
|
|
-.tag-list { display: flex; flex-wrap: wrap; }
|
|
|
-.tab-content-wrapper { padding: 10px 0; }
|
|
|
-:deep(.el-table .el-table__cell) { padding: 12px 0; }
|
|
|
+
|
|
|
+.metric-item {
|
|
|
+ text-align: center;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+
|
|
|
+.val {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #303133;
|
|
|
+ font-family: DIN, sans-serif;
|
|
|
+ margin-bottom: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.lbl {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.text-primary {
|
|
|
+ color: #409eff;
|
|
|
+}
|
|
|
+
|
|
|
+.text-danger {
|
|
|
+ color: #f56c6c;
|
|
|
+}
|
|
|
+
|
|
|
+.text-warning {
|
|
|
+ color: #e6a23c;
|
|
|
+}
|
|
|
+
|
|
|
+.divider-v {
|
|
|
+ width: 1px;
|
|
|
+ background: #e0e0e0;
|
|
|
+ height: 30px;
|
|
|
+ align-self: center;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-tabs {
|
|
|
+ margin-top: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.section-block {
|
|
|
+ margin-bottom: 25px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ border-left: 4px solid #409eff;
|
|
|
+ padding-left: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.cert-row {
|
|
|
+ display: flex;
|
|
|
+ gap: 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.cert-item {
|
|
|
+ text-align: center;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.cert-img {
|
|
|
+ width: 120px;
|
|
|
+ height: 80px;
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ background: #f5f7fa;
|
|
|
+}
|
|
|
+
|
|
|
+.img-slot {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ color: #909399;
|
|
|
+ font-size: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.cert-name {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #606266;
|
|
|
+ margin-top: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.tag-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.tab-content-wrapper {
|
|
|
+ padding: 10px 0;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-table .el-table__cell) {
|
|
|
+ padding: 12px 0;
|
|
|
+}
|
|
|
</style>
|