javacodeadmin/ruoyi-ui/src/views/system/UsersWorker/index.vue

1369 lines
43 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="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="姓名" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入昵称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="电话" prop="phone">
<el-input
v-model="queryParams.phone"
placeholder="请输入电话"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="工号" prop="jobNumber">
<el-input
v-model="queryParams.jobNumber"
placeholder="请输入工号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option
v-for="dict in dict.type.users_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="等级" prop="level">
<el-input
v-model="queryParams.level"
placeholder="请输入工号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="使用状态" prop="loginStatus">
<el-select v-model="queryParams.loginStatus" placeholder="请选择使用状态" clearable>
<el-option
v-for="dict in dict.type.users_login_status"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item label="当前佣金" prop="priceRange" label-width="auto">
<el-input
v-model="queryParams.commissionMin"
placeholder="最低价"
style="width: 100px; margin-right: 10px;"
type="number"
min="0"
clearable
/>
<span style="margin: 0 5px;">-</span>
<el-input
v-model="queryParams.commissionMax"
placeholder="最高价"
style="width: 100px;"
type="number"
min="0"
clearable
/>
</el-form-item>
<el-form-item label="质保金" prop="priceRange" label-width="auto">
<el-input
v-model="queryParams.marginMin"
placeholder="最低价"
style="width: 100px; margin-right: 10px;"
type="number"
min="0"
clearable
/>
<span style="margin: 0 5px;">-</span>
<el-input
v-model="queryParams.marginMax"
placeholder="最高价"
style="width: 100px;"
type="number"
min="0"
clearable
/>
</el-form-item>
<el-form-item label="累计提现" prop="priceRange" label-width="auto">
<el-input
v-model="queryParams.totalCommMin"
placeholder="最低价"
style="width: 100px; margin-right: 10px;"
type="number"
min="0"
clearable
/>
<span style="margin: 0 5px;">-</span>
<el-input
v-model="queryParams.totalCommMax"
placeholder="最高价"
style="width: 100px;"
type="number"
min="0"
clearable
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</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="handleAdd"
v-hasPermi="['system:users:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:users:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:users:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-refresh"
size="mini"
@click="handleManualResumeWorkerStatus"
v-hasPermi="['system:users:edit']"
>恢复过期暂停</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="usersList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" align="center" width="55" prop="id" />
<el-table-column label="工号" align="center" prop="jobNumber" />
<el-table-column label="姓名" align="center" prop="name" />
<el-table-column label="电话" align="center" prop="phone" />
<el-table-column label="openid" align="center" prop="openid" />
<el-table-column label="头像" align="center" prop="avatar" width="100">
<template slot-scope="scope">
<image-preview :src="scope.row.avatar" :width="50" :height="50"/>
</template>
</el-table-column>
<el-table-column label="使用状态" align="center" prop="loginStatus">
<template slot-scope="scope">
<dict-tag :options="dict.type.users_login_status" :value="scope.row.loginStatus"/>
</template>
</el-table-column>
<el-table-column label="状态" width="85" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
:active-value="1"
:inactive-value="0"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="本月累计单量" align="center" prop="toa" />
<el-table-column label="签到时间" align="center" prop="createdAt" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.workerTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="等级" align="center" prop="level" width="100">
<template slot-scope="scope">
<div class="level-container">
<el-select
v-model="scope.row.level"
@change="handleRowClick(scope.row)"
size="small"
class="level-select-custom"
:class="'level-' + scope.row.level"
placeholder="选择等级"
>
<el-option
v-for="item in levelList"
:key="item.id"
:label="item.title"
:value="item.id"
class="level-option-item"
>
<div class="level-option-wrapper">
<span class="level-text">{{ item.title }}</span>
<span class="level-number">{{ item.id }}</span>
</div>
</el-option>
</el-select>
</div>
</template>
</el-table-column>
<el-table-column label="当前佣金" align="center" prop="commission" />
<el-table-column label="累计佣金" align="center" prop="totalComm">
<template slot-scope="scope">
<el-link
type="primary"
@click="showWorkerMoneyLog(scope.row)"
v-hasPermi="['system:workerMoneyLog:list']"
>{{ scope.row.totalComm }}</el-link>
</template>
</el-table-column>
<el-table-column label="质保金" align="center" prop="margin">
<template slot-scope="scope">
<el-link
type="primary"
@click="showWorkerMarginLog(scope.row)"
v-hasPermi="['system:WorkerMarginLog:list']"
>{{ scope.row.margin }}</el-link>
</template>
</el-table-column>
<el-table-column label="累计提现" align="center" prop="propose" />
<el-table-column label="接单状态" align="center" prop="isStop" width="100">
<template slot-scope="scope">
<el-tag v-if="scope.row.isStop === 1 && !scope.row.isExpired" type="danger">已暂停</el-tag>
<el-tag v-else-if="scope.row.isStop === 1 && scope.row.isExpired" type="warning">已过期</el-tag>
<el-tag v-else type="success">正常</el-tag>
</template>
</el-table-column>
<el-table-column label="暂停时长" align="center" prop="prohibitTimeNum" width="80">
<template slot-scope="scope">
<span v-if="scope.row.isStop === 1 && scope.row.prohibitTimeNum">{{ scope.row.prohibitTimeNum }}小时</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="暂停到期时间" align="center" prop="prohibitTime" width="150">
<template slot-scope="scope">
<span v-if="scope.row.isStop === 1 && scope.row.prohibitTime" :class="{'expired-time': scope.row.isExpired}">
{{ parseTime(scope.row.prohibitTime, '{y}-{m}-{d} {h}:{i}') }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="服务区域" align="center" prop="serviceCityIds" width="150">
<template slot-scope="scope">
<span v-if="scope.row.serviceCityIds">{{ formatServiceAreas(scope.row.serviceCityIds) }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="技能" align="center" prop="skillIds" width="150">
<template slot-scope="scope">
<span v-if="scope.row.skillIds">{{ formatSkillNames(scope.row.skillIds) }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['system:users:edit']"
>修改</el-button>
<el-button
v-if="scope.row.isStop !== 1"
size="mini"
type="text"
icon="el-icon-video-pause"
@click="handlePauseOrder(scope.row)"
v-hasPermi="['system:users:edit']"
style="color: #E6A23C;"
>暂停接单</el-button>
<el-button
v-else-if="scope.row.isExpired"
size="mini"
type="text"
icon="el-icon-refresh"
@click="handleResumeOrder(scope.row)"
v-hasPermi="['system:users:edit']"
style="color: #E6A23C;"
>恢复过期</el-button>
<el-button
v-else
size="mini"
type="text"
icon="el-icon-video-play"
@click="handleResumeOrder(scope.row)"
v-hasPermi="['system:users:edit']"
style="color: #67C23A;"
>恢复接单</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['system:users:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<UserEditDialog
:visible.sync="editDialogVisible"
:user="editUser"
:mode="editMode"
@confirm="handleEditConfirm"
@cancel="editDialogVisible = false"
/>
<!-- 师傅佣金明细弹窗 -->
<el-dialog :title="'师傅佣金明细'" :visible.sync="workerMoneyLogDialogVisible" width="70%" top="5vh" append-to-body>
<worker-money-log-table
:worker-id="currentWorkerId"
@close="workerMoneyLogDialogVisible = false"
v-if="workerMoneyLogDialogVisible"
/>
</el-dialog>
<!-- 师傅质保金明细弹窗 -->
<el-dialog :title="'师傅质保金明细'" :visible.sync="workerMarginLogDialogVisible" width="70%" top="5vh" append-to-body>
<worker-margin-log-detail-table
:worker-id="currentWorkerId"
@close="workerMarginLogDialogVisible = false"
@margin-changed="handleMarginChanged"
v-if="workerMarginLogDialogVisible"
:key="'margin-log-' + currentWorkerId"
/>
</el-dialog>
<WorkerLevelSelectDialog
:visible.sync="workerLevelDialogVisible"
:user-id="workerLevelUserId"
:user-name="workerLevelUserName"
@level-selected="handleWorkerLevelSelected"
/>
<!-- 暂停接单弹窗 -->
<el-dialog title="暂停接单" :visible.sync="pauseOrderDialogVisible" width="500px" append-to-body>
<el-form ref="pauseOrderForm" :model="pauseOrderForm" :rules="pauseOrderRules" label-width="100px">
<el-form-item label="师傅姓名">
<el-input v-model="pauseOrderForm.name" disabled />
</el-form-item>
<el-form-item label="暂停时长" prop="prohibitTimeNum">
<div class="time-input">
<el-button icon="el-icon-minus" @click="decreasePauseTime" size="small"></el-button>
<el-input-number
v-model="pauseOrderForm.prohibitTimeNum"
:min="1"
:max="168"
:controls="false"
placeholder="1"
style="width: 100px; text-align: center;" />
<el-button icon="el-icon-plus" @click="increasePauseTime" size="small"></el-button>
<span style="margin-left: 10px;">小时</span>
</div>
<div style="margin-top: 5px; color: #909399; font-size: 12px;">
暂停时长范围1-168小时7天
</div>
</el-form-item>
<el-form-item label="暂停原因" prop="reason">
<el-input
v-model="pauseOrderForm.reason"
type="textarea"
:rows="3"
placeholder="请输入暂停接单原因(可选)"
maxlength="200"
show-word-limit
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="pauseOrderDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmPauseOrder" :loading="pauseOrderLoading">确认暂停</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listUsers, getUsers, delUsers, addUsers, updateUsers,getUserDataList,changetypeStatus,pauseOrder } from "@/api/system/users"
import { listWorkerLevel } from '@/api/system/WorkerLevel'
import { datalist, getDiyCity, manualResumeWorkerStatus } from "@/api/system/DiyCity"
import { getSiteSkillList } from "@/api/system/SiteSkill"
import UserEditDialog from './UserEditDialog.vue'
import WorkerMoneyLogTable from '@/views/system/workerMoneyLog/WorkerMoneyLogTable.vue'
import WorkerMarginLogDetailTable from '@/views/system/WorkerMarginLog/WorkerMarginLogTable.vue'
import WorkerLevelSelectDialog from '../workerLevelSelect/WorkerLevelSelectDialog.vue'
export default {
name: "Users",
dicts: ['users_status','users_login_status'],
components: { UserEditDialog, WorkerMoneyLogTable, WorkerMarginLogDetailTable, WorkerLevelSelectDialog },
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
levelList: [],
userDataList: [],
// 用户列表表格数据
usersList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
totalCommMin: null,
totalCommMax: null,
marginMin: null,
marginMax: null,
commissionMin: null,
commissionMax: null,
jobNumber: null,
type: '2',
name: null,
phone: null,
status: null,
},
// 表单参数
form: {},
// 表单校验
rules: {
name: [
{ required: true, message: "昵称不能为空", trigger: "blur" }
],
phone: [
{ required: true, message: "电话不能为空", trigger: "blur" }
],
status: [
{ required: true, message: "1:启用 0关闭不能为空", trigger: "change" }
],
},
editDialogVisible: false,
editUser: {},
editMode: 'add',
workerMoneyLogDialogVisible: false,
currentWorkerId: null,
workerMarginLogDialogVisible: false,
workerLevelDialogVisible: false,
workerLevelUserId: null,
workerLevelUserName: '',
// 地区数据缓存
areaDataCache: {},
// 技能数据缓存
skillDataCache: {},
// 暂停接单弹窗相关
pauseOrderDialogVisible: false,
pauseOrderForm: {
name: '',
prohibitTimeNum: 1,
reason: ''
},
pauseOrderRules: {
prohibitTimeNum: [
{ required: true, message: '请选择暂停时长', trigger: 'change' }
]
},
pauseOrderLoading: false
}
},
created() {
this.getList()
this.getlevelList();
this.initAreaDataCache();
this.initSkillDataCache();
// 添加调试信息
console.log('UsersWorker - 组件创建完成');
},
mounted() {
// 确保在组件挂载后重新获取数据,以便格式化方法能正常工作
this.$nextTick(() => {
// 立即初始化缓存,不需要等待
console.log('UsersWorker - 组件挂载,立即初始化缓存');
this.initAreaDataCache();
this.initSkillDataCache();
// 等待一定时间后重新获取列表,让缓存有时间初始化
setTimeout(() => {
console.log('UsersWorker - 缓存初始化时间结束,重新获取列表数据');
this.getList();
}, 2000);
});
},
methods: {
/** 查询用户列表列表 */
getList() {
this.loading = true
listUsers(this.queryParams).then(response => {
this.usersList = response.rows
this.total = response.total
this.loading = false
// 检查暂停状态是否过期
this.checkExpiredPauseStatus();
// 添加调试信息,查看实际的数据格式
console.log('UsersWorker - 获取到的用户列表:', this.usersList);
if (this.usersList.length > 0) {
console.log('第一个用户的服务地区数据:', this.usersList[0].serviceCityIds, '类型:', typeof this.usersList[0].serviceCityIds);
}
})
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
id: null,
name: null,
nickname: null,
phone: null,
password: null,
rememberToken: null,
openid: null,
avatar: null,
type: null,
workerTime: null,
integral: null,
totalIntegral: null,
status: null,
level: null,
commission: null,
totalComm: null,
margin: null,
jobNumber: null,
prohibitTime: null,
prohibitTimeNum: null,
toa: null,
serviceCityPid: null,
serviceCityIds: null,
skillIds: null,
propose: null,
loginStatus: null,
isStop: null,
middleAuth: null,
createdAt: null,
updatedAt: null
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
getlevelList(){
listWorkerLevel().then(response => {
this.levelList = response.rows
})
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
handleRowClick(row) {
updateUsers(row).then(() => {
this.$message.success('等级修改成功')
}).catch(error => {
console.error('等级修改失败:', error);
this.$message.error('等级修改失败,请重试');
// 如果更新失败,刷新列表恢复原状态
this.getList()
})
},
/** 新增按钮操作 */
handleAdd() {
this.editUser = {
name: undefined,
phone: undefined,
avatar: undefined,
prohibitTime: undefined,
prohibitTimeNum: 0,
serviceCityPid: undefined,
serviceCityIds: undefined,
skillIds: undefined,
commission: undefined,
status: 1
};
this.editMode = 'add';
this.editDialogVisible = true;
},
/** 修改按钮操作 */
handleUpdate(row) {
const id = row.id || this.ids
getUsers(id).then(response => {
this.editUser = response.data;
this.editMode = 'edit';
this.editDialogVisible = true;
})
},
// 状态修改
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.name + '"状态吗?').then(function() {
return changetypeStatus(row.id, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
row.status = row.status === "0" ? "1" : "0"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateUsers(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUsers(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除用户列表编号为"' + ids + '"的数据项?').then(function() {
return delUsers(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('system/users/export', {
...this.queryParams
}, `users_${new Date().getTime()}.xlsx`)
},
handleEditConfirm(user) {
if (this.editMode === 'add') {
addUsers(user).then(response => {
this.$modal.msgSuccess("新增成功");
this.editDialogVisible = false;
this.getList();
});
} else {
updateUsers(user).then(response => {
this.$modal.msgSuccess("修改成功");
this.editDialogVisible = false;
this.getList();
});
}
},
showWorkerMoneyLog(row) {
console.log('点击查看师傅佣金明细,师傅信息:', row);
if (!row || !row.id) {
this.$message.error('师傅信息不完整,无法查看佣金明细');
return;
}
this.currentWorkerId = row.id;
this.workerMoneyLogDialogVisible = true;
console.log('设置currentWorkerId:', this.currentWorkerId);
},
showWorkerMarginLog(row) {
console.log('点击查看师傅质保金明细,师傅信息:', row);
if (!row || !row.id) {
this.$message.error('师傅信息不完整,无法查看质保金明细');
return;
}
this.currentWorkerId = row.id;
this.workerMarginLogDialogVisible = true;
},
showWorkerLevelDialog(row) {
this.workerLevelUserId = row.id;
this.workerLevelUserName = row.name;
this.workerLevelDialogVisible = true;
},
handleWorkerLevelSelected() {
this.workerLevelDialogVisible = false;
this.getList(); // 选中后刷新列表
},
// 处理质保金变动事件
handleMarginChanged() {
console.log('质保金发生变动,刷新师傅列表');
this.getList(); // 刷新师傅列表,更新质保金显示
},
// 格式化服务区域显示
formatServiceAreas(serviceCityIds) {
if (!serviceCityIds) return '-';
try {
console.log('格式化服务区域,原始数据:', serviceCityIds, '类型:', typeof serviceCityIds);
// 如果是字符串,先转换为数组
let areaIds = [];
if (typeof serviceCityIds === 'string') {
// 处理可能是JSON字符串的情况
if (serviceCityIds.startsWith('[') && serviceCityIds.endsWith(']')) {
try {
areaIds = JSON.parse(serviceCityIds);
} catch (e) {
console.warn('JSON解析失败使用逗号分隔:', e);
areaIds = serviceCityIds.replace(/[\[\]]/g, '').split(',').map(id => id.trim()).filter(id => id);
}
} else {
areaIds = serviceCityIds.split(',').map(id => id.trim()).filter(id => id);
}
} else if (Array.isArray(serviceCityIds)) {
areaIds = serviceCityIds;
} else {
areaIds = [serviceCityIds];
}
// 转换为数字数组
areaIds = areaIds.map(id => parseInt(id)).filter(id => !isNaN(id) && id > 0);
console.log('解析后的地区ID数组:', areaIds);
console.log('地区数据缓存:', this.areaDataCache);
if (areaIds.length === 0) return '-';
// 从缓存中获取地区名称
const areaNames = areaIds.map(id => {
const cached = this.areaDataCache[id];
console.log(`地区ID ${id} 对应的缓存数据:`, cached);
if (cached) {
return cached.title;
} else {
// 如果缓存中没有,尝试实时获取
this.loadAreaById(id);
return `区域${id}`; // 临时显示
}
});
const result = areaNames.join(', ');
console.log('格式化结果:', result);
return result;
} catch (error) {
console.error('格式化服务区域失败:', error);
return serviceCityIds;
}
},
// 格式化技能名称显示
formatSkillNames(skillIds) {
if (!skillIds) return '-';
try {
console.log('格式化技能名称,原始数据:', skillIds, '类型:', typeof skillIds);
// 如果是字符串,先转换为数组
let skillIdArray = [];
if (typeof skillIds === 'string') {
// 处理可能是JSON字符串的情况
if (skillIds.startsWith('[') && skillIds.endsWith(']')) {
try {
skillIdArray = JSON.parse(skillIds);
} catch (e) {
skillIdArray = skillIds.split(',').map(id => id.trim()).filter(id => id);
}
} else {
skillIdArray = skillIds.split(',').map(id => id.trim()).filter(id => id);
}
} else if (Array.isArray(skillIds)) {
skillIdArray = skillIds;
}
console.log('解析后的技能ID数组:', skillIdArray);
console.log('技能数据缓存:', this.skillDataCache);
if (skillIdArray.length === 0) return '-';
// 从缓存中获取技能名称
const skillNames = skillIdArray.map(id => {
const cached = this.skillDataCache[id];
console.log(`技能ID ${id} 对应的缓存数据:`, cached);
return cached ? cached.title : id;
});
const result = skillNames.join(', ');
console.log('格式化结果:', result);
return result;
} catch (error) {
console.error('格式化技能名称失败:', error);
return skillIds;
}
},
// 初始化地区数据缓存
initAreaDataCache() {
console.log('开始初始化地区数据缓存');
// 先添加一些常见的地区ID到缓存以防API获取失败
const commonAreas = [
// 陕西省下的地区
{ id: 2, title: "新城区" },
{ id: 5, title: "碑林区" },
{ id: 7, title: "莲湖区" },
{ id: 10, title: "灞桥区" },
{ id: 11, title: "未央区" },
{ id: 12, title: "雁塔区" },
{ id: 13, title: "阎良区" },
{ id: 14, title: "临潼区" },
{ id: 15, title: "长安区" },
{ id: 16, title: "高陵区" },
{ id: 17, title: "鄠邑区" },
// 安徽省下的地区
{ id: 53, title: "瑶海区" },
{ id: 54, title: "庐阳区" },
{ id: 55, title: "蜀山区" },
{ id: 56, title: "包河区" },
{ id: 57, title: "经开区" },
{ id: 58, title: "高新区" }
];
commonAreas.forEach(area => {
this.areaDataCache[area.id] = area;
console.log(`添加常见地区到缓存: ${area.id} -> ${area.title}`);
});
// 获取所有省份数据
const queryParams = {
parentId: 0 // 查询一级城市(省份)
}
datalist(queryParams).then(response => {
console.log('获取省份数据成功:', response);
if (response.code === 200 && response.data) {
// 先缓存省份数据
response.data.forEach(province => {
this.areaDataCache[province.id] = province;
console.log(`添加省份到缓存: ${province.id} -> ${province.title}`);
});
// 为每个省份获取下级地区数据
const loadPromises = response.data.map(province => {
const cityParams = {
parentId: province.id
}
return datalist(cityParams).then(cityResponse => {
console.log(`获取城市数据成功 (${province.id}):`, cityResponse);
if (cityResponse.code === 200 && cityResponse.data) {
cityResponse.data.forEach(city => {
this.areaDataCache[city.id] = city;
console.log(`添加城市到缓存: ${city.id} -> ${city.title}`);
});
}
return cityResponse;
}).catch((error) => {
console.error(`获取城市数据失败 (${province.id}):`, error);
return Promise.resolve();
});
});
// 等待所有城市数据加载完成
Promise.all(loadPromises).then(() => {
console.log('所有地区数据加载完成,最终缓存:', this.areaDataCache);
// 数据加载完成后,重新渲染列表以显示正确的地区名称
this.$forceUpdate();
});
}
}).catch((error) => {
console.error('获取省份数据失败:', error);
// 如果获取省份数据失败,使用默认数据
const defaultProvinces = [
{ id: 1, title: "陕西省" },
{ id: 27, title: "上海市" },
{ id: 44, title: "湖南省" },
{ id: 52, title: "安徽省" }
];
defaultProvinces.forEach(province => {
this.areaDataCache[province.id] = province;
console.log(`添加默认省份到缓存: ${province.id} -> ${province.title}`);
});
});
},
// 初始化技能数据缓存
initSkillDataCache() {
console.log('开始初始化技能数据缓存');
getSiteSkillList().then(response => {
console.log('获取技能数据成功:', response);
if (response.code === 200 && response.data) {
response.data.forEach(skill => {
this.skillDataCache[skill.id] = skill;
console.log(`添加技能到缓存: ${skill.id} -> ${skill.title}`);
});
}
}).catch((error) => {
console.error('获取技能数据失败:', error);
// 如果获取技能数据失败,使用默认数据
const defaultSkills = [
{ id: 1, title: '水电工' },
{ id: 2, title: '油工师傅' },
{ id: 3, title: '改造维修' },
{ id: 4, title: '工程施工' }
];
defaultSkills.forEach(skill => {
this.skillDataCache[skill.id] = skill;
console.log(`添加默认技能到缓存: ${skill.id} -> ${skill.title}`);
});
});
},
// 根据ID加载地区数据
loadAreaById(id) {
if (this.areaDataCache[id]) {
return; // 如果已缓存,则直接返回
}
// 使用getDiyCity API根据ID获取单个地区数据
getDiyCity(id).then(response => {
if (response.code === 200 && response.data) {
this.areaDataCache[id] = response.data;
console.log(`从API加载地区到缓存: ${id} -> ${response.data.title}`);
// 如果加载成功,重新渲染列表以显示正确的地区名称
this.$forceUpdate();
} else {
console.warn(`API加载地区失败ID: ${id}, 响应:`, response);
}
}).catch((error) => {
console.error(`API加载地区失败ID: ${id}:`, error);
});
},
// 暂停接单按钮操作
handlePauseOrder(row) {
console.log('点击暂停接单,师傅信息:', row);
if (!row || !row.id) {
this.$message.error('师傅信息不完整,无法暂停接单');
return;
}
// 重置表单数据
this.pauseOrderForm = {
id: row.id,
name: row.name,
prohibitTimeNum: 1,
reason: ''
};
// 清除表单验证
this.$nextTick(() => {
if (this.$refs.pauseOrderForm) {
this.$refs.pauseOrderForm.clearValidate();
}
});
this.pauseOrderDialogVisible = true;
},
// 减少暂停时间
decreasePauseTime() {
if (this.pauseOrderForm.prohibitTimeNum > 1) {
this.pauseOrderForm.prohibitTimeNum--;
}
},
// 增加暂停时间
increasePauseTime() {
if (this.pauseOrderForm.prohibitTimeNum < 168) {
this.pauseOrderForm.prohibitTimeNum++;
}
},
// 确认暂停接单
confirmPauseOrder() {
this.$refs.pauseOrderForm.validate(valid => {
if (valid) {
this.pauseOrderLoading = true;
const pauseData = {
id: this.pauseOrderForm.id,
prohibitTimeNum: this.pauseOrderForm.prohibitTimeNum
};
pauseOrder(pauseData).then(response => {
this.$modal.msgSuccess(`已成功暂停师傅"${this.pauseOrderForm.name}"接单${this.pauseOrderForm.prohibitTimeNum}小时`);
this.pauseOrderDialogVisible = false;
this.getList(); // 刷新列表
}).catch(error => {
console.error('暂停接单失败:', error);
this.$modal.msgError('暂停接单失败,请重试');
}).finally(() => {
this.pauseOrderLoading = false;
});
}
});
},
// 恢复接单按钮操作
handleResumeOrder(row) {
console.log('点击恢复接单,师傅信息:', row);
if (!row || !row.id) {
this.$message.error('师傅信息不完整,无法恢复接单');
return;
}
this.$modal.confirm(`确认要恢复师傅"${row.name}"的接单状态吗?`).then(() => {
this.resumeOrder(row.id, row.name);
}).catch(() => {
console.log('用户取消恢复接单操作');
});
},
// 恢复接单
resumeOrder(userId, userName) {
const resumeData = {
id: userId,
prohibitTimeNum: 0,
isStop: 0
};
updateUsers(resumeData).then(response => {
this.$modal.msgSuccess(`已成功恢复师傅"${userName}"的接单状态`);
this.getList(); // 刷新列表
}).catch(error => {
console.error('恢复接单失败:', error);
this.$modal.msgError('恢复接单失败,请重试');
});
},
// 检查并更新过期暂停状态
checkExpiredPauseStatus() {
const now = new Date();
let hasExpired = false;
this.usersList.forEach(user => {
if (user.isStop === 1 && user.prohibitTime) {
const prohibitTime = new Date(user.prohibitTime);
if (prohibitTime < now) {
// 如果暂停时间已过期,标记为已过期但不立即更新数据库
user.isExpired = true;
hasExpired = true;
console.log(`师傅"${user.name}"的暂停时间已过期`);
}
}
});
// 如果有过期的暂停状态,显示提示信息
if (hasExpired) {
this.$message.info('检测到部分师傅的暂停时间已过期,请手动恢复接单状态。');
}
},
// 更新用户状态
updateUserStatus(id, status) {
changetypeStatus(id, status).then(() => {
this.$message.success(`用户状态更新成功`);
this.getList(); // 刷新列表以显示最新的状态
}).catch(error => {
console.error('更新用户状态失败:', error);
this.$message.error('更新用户状态失败,请重试');
});
},
// 手动恢复师傅暂停状态
handleManualResumeWorkerStatus() {
this.$modal.confirm('确认要执行师傅暂停状态自动恢复任务吗?此操作将检查所有暂停的师傅,并自动恢复已过期的师傅接单状态。').then(() => {
this.executeManualResumeWorkerStatus();
}).catch(() => {
console.log('用户取消手动恢复过期暂停操作');
});
},
// 执行师傅暂停状态自动恢复
executeManualResumeWorkerStatus() {
// 显示加载状态
const loading = this.$loading({
lock: true,
text: '正在执行师傅暂停状态恢复任务...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
manualResumeWorkerStatus().then(response => {
loading.close();
if (response.code === 200) {
this.$message.success(response.msg || '师傅暂停状态自动恢复任务执行成功');
// 刷新列表以显示最新状态
this.getList();
} else {
this.$message.error(response.msg || '师傅暂停状态自动恢复任务执行失败');
}
}).catch(error => {
loading.close();
console.error('执行师傅暂停状态自动恢复失败:', error);
this.$message.error('执行师傅暂停状态自动恢复失败,请重试');
});
},
// 批量恢复过期暂停状态
resumeAllExpiredWorkers() {
const expiredUsers = this.usersList.filter(user => user.isStop === 1 && user.isExpired);
if (expiredUsers.length === 0) {
this.$message.info('没有过期暂停的师傅。');
return;
}
const userIds = expiredUsers.map(user => user.id);
const userNames = expiredUsers.map(user => user.name);
this.$modal.confirm(`确认要恢复以下${userIds.length}个师傅的接单状态吗?\n${userNames.join('、')}`).then(() => {
const resumePromises = userIds.map(id => {
const resumeData = {
id: id,
prohibitTimeNum: 0,
isStop: 0
};
return updateUsers(resumeData);
});
Promise.all(resumePromises).then(() => {
this.$message.success(`已成功恢复${userIds.length}个师傅的接单状态。`);
this.getList(); // 刷新列表
}).catch(error => {
console.error('批量恢复过期暂停失败:', error);
this.$message.error('批量恢复过期暂停失败,请重试');
});
}).catch(() => {
console.log('用户取消批量恢复过期暂停操作');
});
}
}
}
</script>
<style scoped>
.time-input {
display: flex;
align-items: center;
}
.selected-tags {
margin-top: 8px;
max-width: 100%;
overflow: hidden;
}
.selected-tags .el-tag {
margin: 2px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time-input .el-button {
border-radius: 4px;
margin: 0 5px;
}
.time-input .el-input-number {
margin: 0 5px;
}
.expired-time {
color: #E6A23C;
font-weight: bold;
text-decoration: line-through;
}
/* 等级选择器样式 */
.level-container {
display: flex;
justify-content: center;
align-items: center;
}
.level-select-custom {
width: 80px !important;
font-weight: 600;
border-radius: 20px;
transition: all 0.3s ease;
border-width: 2px;
}
.level-select-custom:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.level-select-custom:focus-within {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
/* 不同等级的颜色样式 */
.level-1 {
background-color: #f8f9fa;
border-color: #6c757d;
color: #495057;
}
.level-1:hover {
border-color: #5a6268;
background-color: #f1f3f4;
}
.level-2 {
background-color: #e8f5e8;
border-color: #28a745;
color: #155724;
}
.level-2:hover {
border-color: #1e7e34;
background-color: #d1ecf1;
}
.level-3 {
background-color: #e3f2fd;
border-color: #2196f3;
color: #0d47a1;
}
.level-3:hover {
border-color: #1976d2;
background-color: #bbdefb;
}
.level-4 {
background-color: #fff3e0;
border-color: #ff9800;
color: #e65100;
}
.level-4:hover {
border-color: #f57c00;
background-color: #ffe0b2;
}
.level-5 {
background-color: #ffebee;
border-color: #f44336;
color: #b71c1c;
}
.level-5:hover {
border-color: #d32f2f;
background-color: #ffcdd2;
}
/* 下拉选项样式 */
.level-option-item {
padding: 8px 16px !important;
border-radius: 6px;
margin: 2px 4px;
transition: all 0.2s ease;
}
.level-option-item:hover {
background-color: #f8f9fa !important;
transform: translateX(4px);
}
.level-option-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.level-text {
font-weight: 500;
color: #333;
}
.level-number {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
margin-left: 8px;
}
/* 选择器下拉箭头样式优化 */
.level-select-custom .el-input__suffix {
right: 8px;
}
.level-select-custom .el-input__suffix .el-input__suffix-inner .el-select__caret {
color: inherit;
font-size: 14px;
transition: transform 0.3s ease;
}
.level-select-custom.is-focus .el-select__caret {
transform: rotateZ(180deg);
}
/* 响应式设计 */
@media (max-width: 768px) {
.level-select-custom {
width: 70px !important;
font-size: 12px;
}
.level-number {
width: 16px;
height: 16px;
font-size: 10px;
}
}
</style>