daShangDao_psiWebApp/backups/EmployeeList.vue.bak
97694731 0543936df8
Some checks failed
CI / build (20.x) (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (push) Waiting to run
CI / deploy-preview (push) Blocked by required conditions
CI / security (push) Waiting to run
CI / build (18.x) (push) Has been cancelled
change store
2026-06-04 11:18:46 +08:00

494 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="employee-list">
<el-card>
<template #header>
<div class="card-header">
<span>代理列表</span>
<div class="header-actions">
<el-button type="primary" @click="$router.push('/admin/employees/add')">
<el-icon>
<Plus />
</el-icon>
</el-button>
</div>
</div>
</template>
<!-- 搜索条件 -->
<div class="search-form">
<el-form :inline="true" :model="queryParams">
<el-form-item label="状态">
<el-select v-model="queryParams.status" placeholder="全部状态" clearable style="width: 150px">
<el-option label="正常" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="搜索">
<el-input v-model="queryParams.keyword" placeholder="工号/姓名/账号" clearable style="width: 200px"
:prefix-icon="Search" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">
<el-icon>
<Search />
</el-icon>搜索
</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 统计卡片 -->
<el-row :gutter="20" class="stat-cards">
<el-col :span="6">
<el-card shadow="hover" class="stat-card">
<div class="stat-item">
<div class="stat-label">总代理数</div>
<div class="stat-value">{{ total }}</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card">
<div class="stat-item">
<div class="stat-label">正常代理</div>
<div class="stat-value success">{{ activeCount }}</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card">
<div class="stat-item">
<div class="stat-label">总积分</div>
<div class="stat-value warning">{{ totalPoints }}</div>
</div>
</el-card>
</el-col>
<el-col :span="6">
<el-card shadow="hover" class="stat-card">
<div class="stat-item">
<div class="stat-label">平均积分</div>
<div class="stat-value info">{{ averagePoints }}</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 代理列表 -->
<el-table :data="employeeList" v-loading="loading" border style="width: 100%">
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="employee_id" label="工号" width="100" align="center" />
<el-table-column prop="username" label="账号" width="150" align="center" />
<el-table-column prop="name" label="姓名" width="120" align="center" />
<el-table-column prop="phone" label="手机号" width="120" align="center" />
<el-table-column prop="score" label="积分" width="100" align="center">
<template #default="{ row }">
<span :class="{ 'points-warning': row.score < 100 }">{{ row.score }}</span>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'danger'" size="small">
{{ row.status === 1 ? '正常' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="code" label="机械码" width="240" align="center" />
<el-table-column prop="level_info" label="等级" width="60" align="center" />
<el-table-column prop="last_login_at" label="最后登录" width="160" align="center">
<template #default="{ row }">
{{ row.last_login_at ? formatDate(row.last_login_at) : '-' }}
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="160" align="center" >
<template #default="{ row }">
{{ formatDate(row.created_at) }}
</template>
</el-table-column>
<!-- <el-table-column label="操作" width="320" fixed="right">
<template #default="{ row }">
<el-button type="primary" size="small" @click="showTopUp(row)">
<el-icon><Coin /></el-icon>充值
</el-button>
<el-button type="success" size="small" @click="viewAccess(row)">
<el-icon><DataLine /></el-icon>积分记录
</el-button>
<el-button
v-if="row.status === 1"
type="warning"
size="small"
@click="toggleStatus(row, 'disable')"
>
<el-icon><Switch /></el-icon>禁用
</el-button>
<el-button
v-else
type="success"
size="small"
@click="toggleStatus(row, 'enable')"
>
<el-icon><Check /></el-icon>启用
</el-button>
<el-button type="danger" size="small" @click="showDeduct(row)">
<el-icon><Coin /></el-icon>扣减
</el-button>
</template>
</el-table-column> -->
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination v-model:current-page="queryParams.page" v-model:page-size="queryParams.page_size" :total="total"
:page-sizes="[10, 20, 50, 100]" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
</el-card>
<!-- 充值弹窗 -->
<el-dialog v-model="topUpVisible" title="积分充值" width="400px">
<el-form :model="topUpForm" ref="topUpFormRef" :rules="topUpRules" label-width="80px">
<el-form-item label="代理">
<span>{{ currentEmployee?.name }} ({{ currentEmployee?.employee_id }})</span>
</el-form-item>
<el-form-item label="当前积分">
<span>{{ currentEmployee?.points }}</span>
</el-form-item>
<el-form-item label="充值数量" prop="amount">
<el-input-number v-model="topUpForm.amount" :min="1" :max="100000" style="width: 200px" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="topUpForm.remark" placeholder="选填" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="topUpVisible = false">取消</el-button>
<el-button type="primary" @click="submitTopUp" :loading="topUpLoading">确认充值</el-button>
</span>
</template>
</el-dialog>
<!-- 扣减弹窗 -->
<el-dialog v-model="deductVisible" title="积分扣减" width="400px">
<el-form :model="deductForm" ref="deductFormRef" :rules="deductRules" label-width="80px">
<el-form-item label="代理">
<span>{{ currentEmployee?.name }} ({{ currentEmployee?.employee_id }})</span>
</el-form-item>
<el-form-item label="当前积分">
<span>{{ currentEmployee?.points }}</span>
</el-form-item>
<el-form-item label="扣减数量" prop="amount" class="deduct-label">
<el-input-number class="deduct-input" v-model="deductForm.amount" :min="1" :max="currentEmployee?.points || 1"
style="width: 200px" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="deductForm.remark" placeholder="选填" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="deductVisible = false">取消</el-button>
<el-button type="danger" @click="submitDeduct" :loading="deductLoading">确认扣减</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Search, Coin, DataLine, Switch, Check } from '@element-plus/icons-vue'
import request from '@/utils/request'
const router = useRouter() // 导入 router
const loading = ref(false)
const employeeList = ref([])
const total = ref(0)
const topUpVisible = ref(false)
const topUpLoading = ref(false)
const deductVisible = ref(false)
const deductLoading = ref(false)
const currentEmployee = ref(null)
const queryParams = reactive({
page: 1,
page_size: 20,
status: '',
keyword: ''
})
const topUpForm = reactive({
amount: 100,
remark: ''
})
const deductForm = reactive({
amount: 100,
remark: ''
})
const topUpRules = {
amount: [
{ required: true, message: '请输入充值数量', trigger: 'blur' },
{ type: 'number', min: 1, message: '充值数量必须大于0', trigger: 'blur' }
]
}
const deductRules = {
amount: [
{ required: true, message: '请输入扣减数量', trigger: 'blur' },
{ type: 'number', min: 1, message: '扣减数量必须大于0', trigger: 'blur' }
]
}
// 计算统计信息
const activeCount = computed(() => {
return employeeList.value.filter(e => e.status === 1).length
})
const totalPoints = computed(() => {
return employeeList.value.reduce((sum, e) => sum + e.score, 0)
})
const averagePoints = computed(() => {
if (employeeList.value.length === 0) return 0
return Math.round(totalPoints.value / employeeList.value.length)
})
// 格式化日期
const formatDate = (timestamp) => {
if (!timestamp) return '-'
const date = new Date(timestamp * 1000)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hour = String(date.getHours()).padStart(2, '0')
const minute = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hour}:${minute}`
}
// 获取代理列表
const fetchEmployeeList = async () => {
loading.value = true
try {
const params = {
page: queryParams.page,
page_size: queryParams.page_size
}
if (queryParams.status !== '') {
params.status = queryParams.status
}
if (queryParams.keyword) {
params.keyword = queryParams.keyword
}
const res = await request.get('/admin/employee/list', { params })
if (res.code === 200) {
employeeList.value = res.data.list
total.value = res.data.total
}
} catch (error) {
// console.error('获取代理列表失败:', error)
} finally {
loading.value = false
}
}
// 搜索
const handleSearch = () => {
queryParams.page = 1
fetchEmployeeList()
}
// 重置搜索
const resetSearch = () => {
queryParams.status = ''
queryParams.keyword = ''
queryParams.page = 1
fetchEmployeeList()
}
// 分页大小变化
const handleSizeChange = (size) => {
queryParams.page_size = size
fetchEmployeeList()
}
// 页码变化
const handleCurrentChange = (page) => {
queryParams.page = page
fetchEmployeeList()
}
// 显示充值弹窗
const showTopUp = (row) => {
currentEmployee.value = row
topUpForm.amount = 100
topUpForm.remark = ''
topUpVisible.value = true
}
// 提交充值
const submitTopUp = async () => {
topUpLoading.value = true
try {
const res = await request.post(`/admin/employee/topup/${currentEmployee.value.employee_id}`, {
amount: topUpForm.amount,
remark: topUpForm.remark
})
if (res.code === 200) {
ElMessage.success('充值成功')
topUpVisible.value = false
fetchEmployeeList() // 刷新列表
}
} catch (error) {
// console.error('充值失败:', error)
} finally {
topUpLoading.value = false
}
}
// 显示扣减弹窗
const showDeduct = (row) => {
currentEmployee.value = row
deductForm.amount = 100
deductForm.remark = ''
deductVisible.value = true
}
// 提交扣减
const submitDeduct = async () => {
deductLoading.value = true
try {
const res = await request.post(`/admin/employee/deduct/${currentEmployee.value.employee_id}`, {
amount: deductForm.amount,
remark: deductForm.remark
})
if (res.code === 200) {
ElMessage.success('扣减成功')
deductVisible.value = false
fetchEmployeeList() // 刷新列表
}
} catch (error) {
// console.error('扣减失败:', error)
} finally {
deductLoading.value = false
}
}
// 切换代理状态
const toggleStatus = async (row, action) => {
const actionText = action === 'enable' ? '启用' : '禁用'
try {
await ElMessageBox.confirm(`确定要${actionText}代理 ${row.name} 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const res = await request.post(`/admin/employee/${action}/${row.employee_id}`)
if (res.code === 200) {
ElMessage.success(`${actionText}成功`)
fetchEmployeeList() // 刷新列表
}
} catch (error) {
if (error !== 'cancel') {
// console.error('操作失败:', error)
}
}
}
// 查看积分记录
const viewAccess = (row) => {
// 跳转到积分记录页面并传递代理ID参数
router.push({
path: '/admin/access',
query: {
id: row.id,
}
})
}
// 初始化
onMounted(() => {
fetchEmployeeList()
})
</script>
<style scoped>
.employee-list {
padding: 0;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
/* 可根据需要保留原有的字体、颜色等样式 */
font-size: 16px;
font-weight: 600;
color: #303133;
}
.search-form {
margin-bottom: 20px;
padding: 20px;
background-color: #f8f9fa;
border-radius: 4px;
}
.stat-cards {
margin-bottom: 20px;
}
.stat-card {
text-align: center;
}
.stat-item {
padding: 10px;
}
.stat-label {
font-size: 14px;
color: #909399;
margin-bottom: 8px;
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #303133;
}
.stat-value.success {
color: #67c23a;
}
.stat-value.warning {
color: #e6a23c;
}
.stat-value.info {
color: #409eff;
}
.pagination {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
.points-warning {
color: #f56c6c;
font-weight: bold;
}
.deduct-input :deep(.el-input-number__decrease):hover,
.deduct-input :deep(.el-input-number__increase):hover {
color: #fff;
background-color: #f56c6c;
}
.deduct-label :deep(.el-form-item__label) {
color: #f56c6c;
font-weight: bold;
}
</style>