Merge branch 'master' of https://gitlab.s1f.top/lin/ApiServer-Web-admin_dashboard_pc
This commit is contained in:
@@ -37,7 +37,7 @@ jobs:
|
|||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: hongKong
|
||||||
steps:
|
steps:
|
||||||
- name: Download Artifact
|
- name: Download Artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
|
|||||||
+7
-2
@@ -5,8 +5,13 @@ import request from "@/utils/request.js";
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function getTickerList(count, page, status) {
|
export function getTickerList(count, page, status, orderBy, order) {
|
||||||
return request.get('/api/v1/admin/work_order/list', { count, page, status })
|
const params = { count, page }
|
||||||
|
if (status !== undefined && status !== '') params.status = status
|
||||||
|
if (orderBy) params.orderBy = orderBy
|
||||||
|
if (order) params.order = order
|
||||||
|
console.log('工单列表请求参数:', params) // 调试日志
|
||||||
|
return request.get('/api/v1/admin/work_order/list', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 待处理
|
// 待处理
|
||||||
|
|||||||
+8
-6
@@ -6,8 +6,14 @@ export const menus = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ticket',
|
path: '/ticket',
|
||||||
title: '工单处理',
|
title: '工单管理',
|
||||||
icon: 'DataBoard'
|
icon: 'Tickets',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/ticket/list',
|
||||||
|
title: '工单列表'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/user',
|
path: '/user',
|
||||||
@@ -18,10 +24,6 @@ export const menus = [
|
|||||||
path: '/user/list',
|
path: '/user/list',
|
||||||
title: '用户列表'
|
title: '用户列表'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/user/balance',
|
|
||||||
title: '用户余额管理'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/user/group',
|
path: '/user/group',
|
||||||
title: '用户组管理'
|
title: '用户组管理'
|
||||||
|
|||||||
+21
-1
@@ -39,7 +39,27 @@ const routes = [
|
|||||||
title: '工单管理',
|
title: '工单管理',
|
||||||
icon: 'Tickets'
|
icon: 'Tickets'
|
||||||
},
|
},
|
||||||
component: () => import('../views/ticket/TicketChat.vue'),
|
redirect: '/ticket/list',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'list',
|
||||||
|
name: 'TicketList',
|
||||||
|
component: () => import('../views/ticket/TicketList.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '工单列表'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'detail',
|
||||||
|
name: 'TicketDetail',
|
||||||
|
component: () => import('../views/ticket/TicketDetail.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '工单详情',
|
||||||
|
hidden: true,
|
||||||
|
activeMenu: '/ticket/list'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// ACS管理路由
|
// ACS管理路由
|
||||||
|
|||||||
@@ -706,7 +706,10 @@ const paramValueForm = reactive({
|
|||||||
attr_id: undefined,
|
attr_id: undefined,
|
||||||
attr_name: '',
|
attr_name: '',
|
||||||
attr_value: '',
|
attr_value: '',
|
||||||
attr_price: 0
|
attr_price: 0,
|
||||||
|
index: 0,
|
||||||
|
attr_range: 0,
|
||||||
|
range_type: 'equal'
|
||||||
})
|
})
|
||||||
|
|
||||||
const paramValueRules = {
|
const paramValueRules = {
|
||||||
@@ -853,7 +856,10 @@ const handleAddParamValue = () => {
|
|||||||
attr_id: undefined,
|
attr_id: undefined,
|
||||||
attr_name: '',
|
attr_name: '',
|
||||||
attr_value: '',
|
attr_value: '',
|
||||||
attr_price: 0
|
attr_price: 0,
|
||||||
|
index: 0,
|
||||||
|
attr_range: 0,
|
||||||
|
range_type: 'equal'
|
||||||
})
|
})
|
||||||
paramValueFormRef.value?.resetFields()
|
paramValueFormRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
@@ -866,7 +872,10 @@ const handleEditParamValue = (row) => {
|
|||||||
attr_id: row.id,
|
attr_id: row.id,
|
||||||
attr_name: row.name,
|
attr_name: row.name,
|
||||||
attr_value: row.value,
|
attr_value: row.value,
|
||||||
attr_price: row.price / 100
|
attr_price: row.price / 100,
|
||||||
|
index: row.index || 0,
|
||||||
|
attr_range: row.attr_range || 0,
|
||||||
|
range_type: row.range_type || 'equal'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,7 +909,10 @@ const submitParamValueForm = () => {
|
|||||||
arg_id: Number(currentParam.value.id),
|
arg_id: Number(currentParam.value.id),
|
||||||
attr_name: paramValueForm.attr_name,
|
attr_name: paramValueForm.attr_name,
|
||||||
attr_value: paramValueForm.attr_value,
|
attr_value: paramValueForm.attr_value,
|
||||||
attr_price: paramValueForm.attr_price
|
attr_price: paramValueForm.attr_price,
|
||||||
|
index: Number(paramValueForm.index),
|
||||||
|
attr_range: Number(paramValueForm.attr_range),
|
||||||
|
range_type: paramValueForm.range_type
|
||||||
}
|
}
|
||||||
if (paramValueFormType.value === 'edit') {
|
if (paramValueFormType.value === 'edit') {
|
||||||
submitData.attr_id = paramValueForm.attr_id
|
submitData.attr_id = paramValueForm.attr_id
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,394 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ticket-list-page">
|
||||||
|
<!-- 顶部工具栏 -->
|
||||||
|
<div class="toolbar">
|
||||||
|
<div class="status-tabs">
|
||||||
|
<div class="tab-item pending" :class="{ active: activeStatus === 'pending' }" @click="filterByStatus('pending')">
|
||||||
|
待处理 <span class="count">{{ stats.pending }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item processing" :class="{ active: activeStatus === 'processing' }" @click="filterByStatus('processing')">
|
||||||
|
处理中 <span class="count">{{ stats.processing }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item replied" :class="{ active: activeStatus === 'replied' }" @click="filterByStatus('replied')">
|
||||||
|
已回复 <span class="count">{{ stats.replied }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item completed" :class="{ active: activeStatus === 'completed' }" @click="filterByStatus('completed')">
|
||||||
|
已完成 <span class="count">{{ stats.completed }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tab-item" :class="{ active: activeStatus === '' }" @click="filterByStatus('')">
|
||||||
|
全部 <span class="count">{{ stats.total }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="toolbar-right">
|
||||||
|
<el-select v-model="sortBy" placeholder="排序方式" clearable style="width: 140px" @change="handleSortChange">
|
||||||
|
<el-option label="不排序" value="" />
|
||||||
|
<el-option label="创建时间" value="created_at" />
|
||||||
|
<el-option label="更新时间" value="updated_at" />
|
||||||
|
<el-option label="工单号" value="id" />
|
||||||
|
</el-select>
|
||||||
|
<el-select v-model="sortOrder" placeholder="排序顺序" clearable style="width: 100px" @change="handleSortChange">
|
||||||
|
<el-option label="默认" value="" />
|
||||||
|
<el-option label="降序" value="desc" />
|
||||||
|
<el-option label="升序" value="asc" />
|
||||||
|
</el-select>
|
||||||
|
<el-input
|
||||||
|
v-model="searchKeyword"
|
||||||
|
placeholder="搜索工单号、标题、用户名"
|
||||||
|
prefix-icon="Search"
|
||||||
|
clearable
|
||||||
|
style="width: 240px"
|
||||||
|
@input="handleSearch"
|
||||||
|
/>
|
||||||
|
<el-button icon="Refresh" @click="refreshList">刷新</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 工单表格 -->
|
||||||
|
<el-table
|
||||||
|
v-loading="isLoading"
|
||||||
|
:data="filteredTickets"
|
||||||
|
stripe
|
||||||
|
style="width: 100%"
|
||||||
|
@row-click="handleRowClick"
|
||||||
|
>
|
||||||
|
<el-table-column prop="id" label="工单号" width="100" />
|
||||||
|
<el-table-column label="用户" width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<div class="user-info">
|
||||||
|
<el-avatar :size="32" :src="row.avatar">{{ row.username?.charAt(0) }}</el-avatar>
|
||||||
|
<span class="username">{{ row.username }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="title" label="工单标题" min-width="200" show-overflow-tooltip />
|
||||||
|
<el-table-column label="状态" width="100">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="getStatusType(row.status)" size="small">
|
||||||
|
{{ getStatusText(row.status) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="createTime" label="创建时间" width="180" />
|
||||||
|
<el-table-column prop="lastReplyTime" label="最后回复" width="180" />
|
||||||
|
<el-table-column label="操作" width="150" fixed="right">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-button type="primary" size="small" @click.stop="goToDetail(row)">
|
||||||
|
回复
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="row.status !== 'completed'"
|
||||||
|
type="success"
|
||||||
|
size="small"
|
||||||
|
@click.stop="handleComplete(row)"
|
||||||
|
>
|
||||||
|
结束
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="pagination-wrapper">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
:total="totalCount"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed, onMounted, onActivated } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import {
|
||||||
|
getTickerList,
|
||||||
|
closeTicket,
|
||||||
|
getTicketCount
|
||||||
|
} from '@/api/ticket'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const totalCount = ref(0)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
// 工单数据
|
||||||
|
const ticketList = ref([])
|
||||||
|
const searchKeyword = ref('')
|
||||||
|
const activeStatus = ref('pending') // 默认选中"待处理"
|
||||||
|
|
||||||
|
// 排序
|
||||||
|
const sortBy = ref('') // 默认不排序
|
||||||
|
const sortOrder = ref('') // 默认不选择排序顺序
|
||||||
|
|
||||||
|
// 统计数据
|
||||||
|
const stats = reactive({
|
||||||
|
pending: 0,
|
||||||
|
processing: 0,
|
||||||
|
replied: 0,
|
||||||
|
completed: 0,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 状态转换
|
||||||
|
const convertStatusToString = (status) => {
|
||||||
|
const statusMap = { 0: 'pending', 1: 'processing', 2: 'replied', 3: 'completed' }
|
||||||
|
return statusMap[status] || 'processing'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusText = (status) => {
|
||||||
|
const statusMap = { pending: '待处理', processing: '处理中', replied: '已回复', completed: '已完成' }
|
||||||
|
return statusMap[status] || status
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStatusType = (status) => {
|
||||||
|
const typeMap = { pending: 'warning', processing: 'primary', replied: 'info', completed: 'success' }
|
||||||
|
return typeMap[status] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取工单列表
|
||||||
|
const fetchTicketList = async () => {
|
||||||
|
try {
|
||||||
|
isLoading.value = true
|
||||||
|
let statusParam = ''
|
||||||
|
if (activeStatus.value) {
|
||||||
|
const statusMap = { pending: '0', processing: '1', replied: '2', completed: '3' }
|
||||||
|
statusParam = statusMap[activeStatus.value] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('调用getTickerList,排序参数:', { sortBy: sortBy.value, sortOrder: sortOrder.value })
|
||||||
|
const res = await getTickerList(
|
||||||
|
pageSize.value,
|
||||||
|
currentPage.value,
|
||||||
|
statusParam,
|
||||||
|
sortBy.value,
|
||||||
|
sortOrder.value
|
||||||
|
)
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
ticketList.value = (res.data.data || []).map(item => ({
|
||||||
|
id: item.work_id,
|
||||||
|
title: item.name,
|
||||||
|
username: item.user?.userName || `用户${item.user?.userId || 'Unknown'}`,
|
||||||
|
userId: item.user?.userId,
|
||||||
|
avatar: item.user?.coverUrl || '',
|
||||||
|
createTime: new Date(item.created_at).toLocaleString(),
|
||||||
|
lastReplyTime: new Date(item.update_time).toLocaleString(),
|
||||||
|
status: convertStatusToString(item.status)
|
||||||
|
}))
|
||||||
|
totalCount.value = res.data.all_count || 0
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '获取工单列表失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取工单列表出错:', error)
|
||||||
|
ElMessage.error('网络错误,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取统计数据
|
||||||
|
const fetchStats = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getTicketCount()
|
||||||
|
if (res.code === 200) {
|
||||||
|
const data = res.data
|
||||||
|
stats.total = data.all_count
|
||||||
|
stats.pending = data.wait_count
|
||||||
|
stats.replied = data.reply_count
|
||||||
|
stats.completed = data.close_count
|
||||||
|
stats.processing = data.all_count - data.wait_count - data.reply_count - data.close_count
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取统计数据出错:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤后的工单列表
|
||||||
|
const filteredTickets = computed(() => {
|
||||||
|
if (!searchKeyword.value) return ticketList.value
|
||||||
|
const keyword = searchKeyword.value.toLowerCase()
|
||||||
|
return ticketList.value.filter(ticket =>
|
||||||
|
ticket.title.toLowerCase().includes(keyword) ||
|
||||||
|
ticket.username.toLowerCase().includes(keyword) ||
|
||||||
|
String(ticket.id).includes(keyword)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 按状态过滤
|
||||||
|
const filterByStatus = (status) => {
|
||||||
|
if (activeStatus.value === status) return
|
||||||
|
activeStatus.value = status
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchTicketList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排序变化处理
|
||||||
|
const handleSortChange = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchTicketList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {}
|
||||||
|
|
||||||
|
// 分页处理
|
||||||
|
const handleSizeChange = () => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchTicketList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = () => {
|
||||||
|
fetchTicketList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新列表
|
||||||
|
const refreshList = () => {
|
||||||
|
fetchTicketList()
|
||||||
|
fetchStats()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳转到详情页
|
||||||
|
const goToDetail = (row) => {
|
||||||
|
router.push({ path: '/ticket/detail', query: { id: row.id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRowClick = (row) => {
|
||||||
|
goToDetail(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束工单
|
||||||
|
const handleComplete = (ticket) => {
|
||||||
|
ElMessageBox.confirm('确定要结束此工单吗?结束后将无法继续回复。', '确认操作', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
try {
|
||||||
|
const res = await closeTicket(ticket.id)
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success('工单已成功结束')
|
||||||
|
refreshList()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '结束工单失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('网络错误,请稍后重试')
|
||||||
|
}
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
let isFirstLoad = true
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchTicketList()
|
||||||
|
fetchStats()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当页面被激活时(从详情页返回时)
|
||||||
|
onActivated(() => {
|
||||||
|
// 跳过首次加载,只在从其他页面返回时刷新
|
||||||
|
if (!isFirstLoad) {
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
isFirstLoad = false
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ticket-list-page {
|
||||||
|
padding: 0;
|
||||||
|
height: calc(100vh - 100px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item:hover {
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.active {
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.pending.active { background: #e6a23c; }
|
||||||
|
.tab-item.processing.active { background: #409eff; }
|
||||||
|
.tab-item.replied.active { background: #909399; }
|
||||||
|
.tab-item.completed.active { background: #67c23a; }
|
||||||
|
|
||||||
|
.tab-item .count {
|
||||||
|
margin-left: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table) {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table tr) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+396
-1201
File diff suppressed because it is too large
Load Diff
@@ -393,6 +393,10 @@ const Edit = EditIcon
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 引入tagsViewStore
|
||||||
|
import { useTagsViewStore } from '@/store/tagsViewStore'
|
||||||
|
const tagsViewStore = useTagsViewStore()
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
const userInfo = ref({})
|
const userInfo = ref({})
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -546,6 +550,8 @@ const refreshData = () => {
|
|||||||
|
|
||||||
// 返回上一页
|
// 返回上一页
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
|
// 关闭当前tab
|
||||||
|
tagsViewStore.delVisitedView(route)
|
||||||
router.go(-1)
|
router.go(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-24
@@ -129,6 +129,7 @@
|
|||||||
<el-dropdown-item command="password">修改密码</el-dropdown-item>
|
<el-dropdown-item command="password">修改密码</el-dropdown-item>
|
||||||
<el-dropdown-item command="group">修改用户组</el-dropdown-item>
|
<el-dropdown-item command="group">修改用户组</el-dropdown-item>
|
||||||
<el-dropdown-item command="realname">实名信息</el-dropdown-item>
|
<el-dropdown-item command="realname">实名信息</el-dropdown-item>
|
||||||
|
<el-dropdown-item command="balance">余额管理</el-dropdown-item>
|
||||||
<el-dropdown-item command="loginHistory">登录记录</el-dropdown-item>
|
<el-dropdown-item command="loginHistory">登录记录</el-dropdown-item>
|
||||||
<el-dropdown-item command="operationHistory">操作记录</el-dropdown-item>
|
<el-dropdown-item command="operationHistory">操作记录</el-dropdown-item>
|
||||||
<el-dropdown-item command="simulateLogin">模拟登录</el-dropdown-item>
|
<el-dropdown-item command="simulateLogin">模拟登录</el-dropdown-item>
|
||||||
@@ -512,12 +513,24 @@ const fetchUserList = async () => {
|
|||||||
const res = await getUserList(queryParams)
|
const res = await getUserList(queryParams)
|
||||||
console.log("获取用户列表:", res)
|
console.log("获取用户列表:", res)
|
||||||
if (res.data.code === 200) {
|
if (res.data.code === 200) {
|
||||||
userList.value = res.data.data.data || []
|
// 映射 API 返回的字段到组件使用的字段格式
|
||||||
|
userList.value = (res.data.data.data || []).map(user => ({
|
||||||
|
UserId: user.user_id,
|
||||||
|
UserName: user.user_name,
|
||||||
|
Phone: user.phone,
|
||||||
|
Email: user.email,
|
||||||
|
Sex: user.sex,
|
||||||
|
Age: user.age,
|
||||||
|
IsAdmin: user.is_admin,
|
||||||
|
CoverID: user.cover_id,
|
||||||
|
avatarUrl: user.cover || '', // 直接使用 cover 字段作为头像 URL
|
||||||
|
UserGroup: user.user_group,
|
||||||
|
RealName: user.real_name,
|
||||||
|
IsDeleted: user.is_deleted,
|
||||||
|
CreatedAt: user.created_at
|
||||||
|
}))
|
||||||
console.log("用户列表:", userList.value)
|
console.log("用户列表:", userList.value)
|
||||||
total.value = res.data.data.all_count || 0
|
total.value = res.data.data.all_count || 0
|
||||||
|
|
||||||
// 为每个用户加载头像URL
|
|
||||||
await loadAvatarsForUsers()
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
ElMessage.error('获取用户列表失败')
|
ElMessage.error('获取用户列表失败')
|
||||||
@@ -526,26 +539,6 @@ const fetchUserList = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 为用户列表加载头像URL
|
|
||||||
const loadAvatarsForUsers = async () => {
|
|
||||||
const promises = userList.value.map(async (user) => {
|
|
||||||
if (user.CoverID) {
|
|
||||||
try {
|
|
||||||
const res = await getFileDetail({ file_id: user.CoverID })
|
|
||||||
if (res.data.code === 200) {
|
|
||||||
user.avatarUrl = res.data.data.url
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载头像失败:', error)
|
|
||||||
user.avatarUrl = ''
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
user.avatarUrl = ''
|
|
||||||
}
|
|
||||||
})
|
|
||||||
await Promise.all(promises)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询用户列表
|
// 查询用户列表
|
||||||
const handleQuery = () => {
|
const handleQuery = () => {
|
||||||
queryParams.page = 1
|
queryParams.page = 1
|
||||||
@@ -676,6 +669,9 @@ const handleCommand = (command, row) => {
|
|||||||
case 'realname':
|
case 'realname':
|
||||||
handleRealnameModify(row)
|
handleRealnameModify(row)
|
||||||
break
|
break
|
||||||
|
case 'balance':
|
||||||
|
handleBalanceManage(row)
|
||||||
|
break
|
||||||
case 'loginHistory':
|
case 'loginHistory':
|
||||||
handleLoginHistory(row)
|
handleLoginHistory(row)
|
||||||
break
|
break
|
||||||
@@ -691,6 +687,14 @@ const handleCommand = (command, row) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 余额管理
|
||||||
|
const handleBalanceManage = (row) => {
|
||||||
|
router.push({
|
||||||
|
path: '/user/balance',
|
||||||
|
query: { user_id: row.UserId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// 模拟登录
|
// 模拟登录
|
||||||
const handleSimulateLogin = async (row) => {
|
const handleSimulateLogin = async (row) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user