Compare commits

...

2 Commits

Author SHA1 Message Date
Lx
de6dc81dce Merge remote-tracking branch 'origin/master' 2025-09-05 16:07:37 +08:00
Lx
d497f158b4 0905 2025-09-05 16:07:20 +08:00
13 changed files with 1864 additions and 432 deletions

View File

@ -15,6 +15,15 @@ export function driverListNew(query) {
params: query
})
}
export function driverAndCarList(query) {
return request({
url: '/system/rescueInfo/driverAndCarList',
method: 'get',
params: query
})
}
export function addDriver(data) {
return request({
url: '/system/rescueInfo/addDriver',
@ -39,7 +48,14 @@ export function updateDriver(data) {
}
export function delDriver(data) {
return request({
url: '/system/rescueInfo/delDriver?ids='+data,
url: '/system/rescueInfo/delDriverNew?ids='+data,
method: 'post'
})
}
export function delDriverStaff(data) {
return request({
url: '/system/rescueInfo/delDriverStaffNew?ids='+data,
method: 'post'
})
}

View File

@ -154,6 +154,7 @@ export const DICT_TYPE = {
Evaluate_type: 'evaluate_type',
Drive_course_subject: 'drive_course_subject',
Drive_card_type: 'drive_card_type',
RESCUE_STAFF_TYPE: 'rescue_staff_type',
File_type: 'file_type',
Cource_type: 'cource_type',
COURCE_TYPE: 'cource_type',

View File

@ -0,0 +1,91 @@
import request from '@/utils/request'
export function fetchList(params) {
return request({
url: '/rescue-channel-source/listByPid',
method: 'get',
params
})
}
export function createChannel(data) {
return request({
url: '/rescue-channel-source/createChannel',
method: 'post',
data
})
}
export function createSource(data) {
return request({
url: '/rescue-channel-source/createSource',
method: 'post',
data
})
}
export function updateItem(data) {
// 根据类型选择不同的更新接口
const url = data.type === 0 ?
'/rescue-channel-source/updateChannel' :
'/rescue-channel-source/updateSource'
return request({
url: url,
method: 'put',
data
})
}
export function deleteItem(id) {
return request({
url: `/rescue-channel-source/delete/${id}`,
method: 'delete'
})
}
//----------------------------------------------------------
export function fetchChannelList(params) {
return request({
url: '/rescue-channel-source/channelPage',
method: 'get',
params
})
}
export function getSourcesByChannelId(channelId) {
return request({
url: `/rescue-channel-source/sources/${channelId}`,
method: 'get'
})
}
export function updateChannel(data) {
return request({
url: '/rescue-channel-source/updateChannel',
method: 'put',
data
})
}
export function updateSource(data) {
return request({
url: '/rescue-channel-source/updateSource',
method: 'put',
data
})
}
export function deleteChannel(id) {
return request({
url: `/rescue-channel-source/deleteChannel/${id}`,
method: 'delete'
})
}
export function deleteSource(id) {
return request({
url: `/rescue-channel-source/deleteSource/${id}`,
method: 'delete'
})
}

View File

@ -0,0 +1,490 @@
<template>
<div class="app-container">
<el-card>
<!-- 搜索区域 -->
<div style="display: flex; justify-content: space-between; align-items: center;">
<div class="filter-container">
<el-input
v-model="listQuery.name"
placeholder="渠道名称"
style="width: 200px;"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>
搜索
</el-button>
<el-button
class="filter-item"
style="margin-left: 10px;"
type="primary"
icon="el-icon-plus"
@click="handleCreateChannel"
>
新增渠道
</el-button>
</div>
<div class="filter-container">
<el-button
class="filter-item"
style="margin-left: auto;"
icon="el-icon-refresh"
:loading="refreshing"
:disabled="refreshing"
@click="handleRefresh"
/>
</div>
</div>
<!-- 表格 -->
<el-table
:data="list"
border
fit
highlight-current-row
style="width: 100%; margin-top: 20px;"
row-key="id"
:expand-row-keys="expandedRows"
@expand-change="handleExpandChange"
>
<el-table-column type="expand">
<template slot-scope="{row}">
<div class="source-container">
<div class="source-header">
<span class="source-title">来源列表</span>
<el-button
type="primary"
size="medium "
icon="el-icon-plus"
@click="handleCreateSource(row)"
>
添加来源
</el-button>
</div>
<el-table
:data="row.sources"
size="medium "
style="width: 100%; margin-top: 10px;"
v-loading="row.loading"
border
>
<el-table-column label="来源名称" prop="name">
<template slot-scope="{row: source}">
<span class="bold-text">{{ source.name }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" align="center" >
<template slot-scope="{row: source}">
{{ source.createTime | parseTime }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="{row: source}">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="handleUpdateSource(source)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDeleteSource(source)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="渠道名称" prop="name">
<template slot-scope="{row}">
<span class="bold-text">{{ row.name }}</span>
</template>
<template slot="header">
<span class="bold-header">渠道名称</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" align="center" >
<template slot-scope="{row}">
{{ row.createTime | parseTime }}
</template>
</el-table-column>
<!-- <el-table-column label="创建人" prop="creator" align="center" />-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="{row}">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="handleUpdateChannel(row)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDeleteChannel(row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList"
/>
</el-card>
<!-- 渠道对话框 -->
<el-dialog
:title="channelDialogTitle"
:visible.sync="channelDialogVisible"
width="500px"
>
<el-form
ref="channelForm"
:rules="rules"
:model="channelTemp"
label-position="left"
label-width="80px"
style="width: 400px; margin-left:50px;"
>
<el-form-item label="渠道名称" prop="name">
<el-input v-model="channelTemp.name" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="channelDialogVisible = false">
取消
</el-button>
<el-button type="primary" @click="saveChannel">
确认
</el-button>
</div>
</el-dialog>
<!-- 来源对话框 -->
<el-dialog
:title="sourceDialogTitle"
:visible.sync="sourceDialogVisible"
width="500px"
>
<el-form
ref="sourceForm"
:rules="rules"
:model="sourceTemp"
label-position="left"
label-width="80px"
style="width: 400px; margin-left:50px;"
>
<el-table-column label="来源名称" prop="name">
<template slot-scope="{row: source}">
<span class="bold-text">{{ source.name }}</span>
</template>
<template slot="header">
<span class="bold-header">来源名称</span>
</template>
</el-table-column>
<el-form-item label="来源名称" prop="name">
<el-input v-model="sourceTemp.name" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="sourceDialogVisible = false">
取消
</el-button>
<el-button type="primary" @click="saveSource">
确认
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import Pagination from '@/components/Pagination'
import { fetchChannelList, getSourcesByChannelId, createChannel, createSource, updateChannel, updateSource, deleteChannel, deleteSource } from './api'
export default {
name: 'RescueChannelSource',
components: { Pagination },
filters: {
parseTime(time) {
if (!time) return ''
return new Date(time).toLocaleString()
}
},
data() {
return {
list: [],
total: 0,
listQuery: {
page: 1,
limit: 20,
name: undefined
},
expandedRows: [],
channelTemp: {
id: undefined,
name: ''
},
sourceTemp: {
id: undefined,
pid: undefined,
name: ''
},
channelDialogVisible: false,
sourceDialogVisible: false,
channelDialogTitle: '',
sourceDialogTitle: '',
refreshing: false, //
rules: {
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
}
}
},
created() {
this.getList()
},
methods: {
async getList() {
try {
const response = await fetchChannelList(this.listQuery)
console.log('获取列表成功:', response)
this.list = response.data.records.map(item => ({
...item,
sources: [],
loading: false
}))
this.total = response.data.total
//
this.expandedRows = []
} catch (error) {
console.error('获取列表失败:', error)
}
},
async handleExpandChange(row, expandedRows) {
if (expandedRows.includes(row)) {
//
if (!row.sources || row.sources.length === 0) {
row.loading = true
try {
const response = await getSourcesByChannelId(row.id)
row.sources = response.data
} catch (error) {
console.error('获取来源列表失败:', error)
} finally {
row.loading = false
}
}
}
},
handleFilter() {
this.listQuery.page = 1
//
this.expandedRows = []
this.getList()
},
handleCreateChannel() {
this.channelTemp = {
id: undefined,
name: ''
}
this.channelDialogTitle = '新增渠道'
this.channelDialogVisible = true
this.$nextTick(() => {
this.$refs.channelForm?.clearValidate()
})
},
handleUpdateChannel(row) {
this.channelTemp = { ...row }
this.channelDialogTitle = '编辑渠道'
this.channelDialogVisible = true
this.$nextTick(() => {
this.$refs.channelForm?.clearValidate()
})
},
handleCreateSource(row) {
this.sourceTemp = {
id: undefined,
pid: row.id,
name: ''
}
this.sourceDialogTitle = '新增来源'
this.sourceDialogVisible = true
this.$nextTick(() => {
this.$refs.sourceForm?.clearValidate()
})
},
handleUpdateSource(source) {
this.sourceTemp = { ...source }
this.sourceDialogTitle = '编辑来源'
this.sourceDialogVisible = true
this.$nextTick(() => {
this.$refs.sourceForm?.clearValidate()
})
},
async handleDeleteChannel(row) {
this.$confirm(`确定要删除渠道"${row.name}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
await deleteChannel(row.id)
this.$message.success('删除成功!')
this.getList()
} catch (error) {
console.error('删除失败:', error)
}
}).catch(() => {})
},
async handleDeleteSource(source) {
this.$confirm(`确定要删除来源"${source.name}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
await deleteSource(source.id)
this.$message.success('删除成功!')
//
const channel = this.list.find(item => item.id === source.pid)
if (channel) {
channel.loading = true
const response = await getSourcesByChannelId(channel.id)
channel.sources = response.data
channel.loading = false
}
} catch (error) {
console.error('删除失败:', error)
}
}).catch(() => {})
},
async saveChannel() {
this.$refs.channelForm.validate(async(valid) => {
if (valid) {
try {
if (this.channelTemp.id) {
await updateChannel(this.channelTemp)
} else {
await createChannel(this.channelTemp)
}
this.channelDialogVisible = false
this.$message.success('保存成功')
this.getList()
} catch (error) {
console.error('保存失败:', error)
}
}
})
},
async saveSource() {
this.$refs.sourceForm.validate(async(valid) => {
if (valid) {
try {
if (this.sourceTemp.id) {
await updateSource(this.sourceTemp)
} else {
await createSource(this.sourceTemp)
}
this.sourceDialogVisible = false
this.$message.success('保存成功')
//
const channel = this.list.find(item => item.id === this.sourceTemp.pid)
if (channel) {
channel.loading = true
const response = await getSourcesByChannelId(channel.id)
channel.sources = response.data
channel.loading = false
}
} catch (error) {
console.error('保存失败:', error)
}
}
})
},
/* handleRefresh() {
this.getList()
this.$message.success('刷新成功')
}, */
async handleRefresh() {
this.refreshing = true
try {
await this.getList()
this.$message.success('刷新成功')
} catch (error) {
console.error('刷新失败:', error)
} finally {
this.refreshing = false
}
},
}
}
</script>
<style scoped>
.filter-container {
margin-bottom: 20px;
}
.filter-item {
margin-right: 10px;
}
.source-container {
padding: 10px;
background: #fafafa;
}
.source-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.source-title {
font-weight: bold;
color: #606266;
}
/* 加粗样式 */
.bold-header {
font-weight: bold;
font-size: 14px;
color: black;
}
.bold-text {
font-weight: bold;
color: black;
}
/* 全局样式,确保表头也加粗 */
.el-table .bold-header {
font-weight: bold !important;
}
.el-table .bold-text {
font-weight: bold !important;
}
</style>

View File

@ -91,3 +91,67 @@ export function getRoleCodeByDictType(dictType) {
method: 'get'
})
}
// 车辆相关
// 根据司机ID获取所有车辆
export function getDriverCars(driverId) {
return request({
url: `/rescue/rescue-driver-car-relation/driver/${driverId}`,
method: 'get'
})
}
// 为司机分配车辆
export function assignCarToDriver(data) {
return request({
url: '/rescue/rescue-driver-car-relation/assign',
method: 'post',
data
})
}
// 批量分配车辆
export function batchAssignCars(data) {
return request({
url: '/rescue/rescue-driver-car-relation/batch-assign',
method: 'post',
data
})
}
// 移除车辆关系
export function removeCarFromDriver(relationId) {
return request({
url: `/rescue/rescue-driver-car-relation/${relationId}`,
method: 'delete'
})
}
// 获取司机的主车
export function getPrimaryCar(driverId) {
return request({
url: `/rescue/rescue-driver-car-relation/driver/${driverId}/primary`,
method: 'get'
})
}
// 获取司机的副车列表
export function getSecondaryCars(driverId) {
return request({
url: `/rescue/rescue-driver-car-relation/driver/${driverId}/secondary`,
method: 'get'
})
}
// _-------------------------------------------------------------------
// 渠道相关
export function channelList() {
return request({
url: '/rescue-channel-source/channelList',
method: 'get'
})
}

View File

@ -3,39 +3,51 @@
<!-- 搜索和新增区域 -->
<div class="operation-bar">
<!-- 搜索表单 -->
<el-form :inline="true" :model="searchForm" class="search-form">
<el-form-item label="姓名">
<el-input
v-model="searchForm.name"
placeholder="请输入姓名"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>
<!-- <el-form-item label="工号">
<el-input
v-model="searchForm.workNo"
placeholder="请输入工号"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>-->
<el-form-item label="手机号">
<el-input
v-model="searchForm.tel"
placeholder="请输入手机号"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<div style="display: flex ; justify-content: space-between; ">
<el-form :inline="true" :model="searchForm" class="search-form">
<el-form-item label="姓名">
<el-input
v-model="searchForm.name"
placeholder="请输入姓名"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>
<!-- <el-form-item label="工号">
<el-input
v-model="searchForm.workNo"
placeholder="请输入工号"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>-->
<el-form-item label="手机号">
<el-input
v-model="searchForm.tel"
placeholder="请输入手机号"
clearable
@clear="handleSearchClear"
@keyup.enter.native="handleSearch"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<div class="search-form">
<el-button
type="success"
@click="handleNavigate"
icon="el-icon-connection"
>
渠道与来源管理
</el-button>
</div>
</div>
<!-- 新增和刷新按钮 -->
<div class="button-row">
@ -52,7 +64,7 @@
style="width: 100%; margin-top: 20px;"
v-loading="loading"
>
<!-- <el-table-column prop="workNo" label="工号" align="center"></el-table-column>-->
<!-- <el-table-column prop="workNo" label="工号" align="center"></el-table-column>-->
<el-table-column prop="name" label="姓名" align="center"></el-table-column>
<el-table-column prop="tel" label="联系电话" align="center"></el-table-column>
<el-table-column prop="sex" label="性别" align="center">
@ -60,8 +72,19 @@
{{ scope.row.sex === '0' ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="channels" label="业务渠道" align="center">
<template slot-scope="scope">
{{ formatChannels(scope.row.channels) }}
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center" fixed="right" v-if="hasRescueFirstViewRole">
<template slot-scope="scope">
<el-button
size="mini"
type="primary"
@click="handleEdit(scope.$index, scope.row)"
icon="el-icon-edit"
>编辑</el-button>
<el-button
size="mini"
type="danger"
@ -88,7 +111,7 @@
<!-- 新增/编辑对话框 -->
<el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="50%">
<el-form :model="form" ref="form" label-width="100px">
<el-form-item label="选择人员" prop="staffId">
<el-form-item label="选择人员" prop="staffId" v-if="!isEdit">
<el-select
v-model="form.selectedStaff"
placeholder="请选择人员"
@ -120,6 +143,24 @@
></el-pagination>
</el-select>
</el-form-item>
<el-form-item label="人员" prop="staffId" v-else>
<el-input v-model="form.selectedStaff.name" disabled></el-input>
</el-form-item>
<el-form-item label="业务渠道" prop="channelIds">
<el-select
v-model="form.selectedChannels"
multiple
placeholder="请选择业务渠道"
style="width: 100%"
>
<el-option
v-for="channel in channelList"
:key="channel.id"
:label="channel.name"
:value="channel.id"
/>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
@ -131,7 +172,7 @@
<script>
import {
assignRole,
assignRole, channelList, saveChannel, getDispatchChannel,
getRoleCodeByDictType,
getStaffInfo,
listStaff,
@ -186,10 +227,13 @@ export default {
dictList: [],
// hasRescueFirstViewRole: false,
// isFirstDispatcher: false
channelList: [],
}
},
created() {
this.getChannelList()
this.initRoleIds().then(() => {
this.fetchData()
})
@ -206,14 +250,17 @@ export default {
this.roleIds = []
}
},
//
handleNavigate() {
this.$router.push('channelSource');
},
async fetchData() {
if (this.hasRescueFirstViewRole === undefined ||
this.isFirstDispatcher === undefined ||
(this.isFirstDispatcher && !this.hasRescueFirstViewRole && this.currentUserId === null)) {
return;
return
}
this.loading = true;
this.loading = true
try {
const params = {
@ -222,63 +269,63 @@ export default {
name: this.searchForm.name,
tel: this.searchForm.tel,
roleIds: this.roleIds
};
}
// first_dispatcherrescue_first_view
if (this.isFirstDispatcher && !this.hasRescueFirstViewRole) {
if (!this.currentUserId) {
const userInfo = await getInfo();
this.currentUserId = userInfo.data?.user?.id;
const userInfo = await getInfo()
this.currentUserId = userInfo.data?.user?.id
}
params.userId = this.currentUserId;
params.userId = this.currentUserId
}
console.log('Request params:', params);
console.log('Request params:', params)
const res = await listStaff(params)
const tableData = res.data.records || []
this.total = res.data.total
//
await Promise.all(tableData.map(async (item) => {
try {
const channelRes = await getDispatchChannel(item.userId)
item.channels = (channelRes.data || []).map(id => {
const channel = this.channelList.find(c => c.id === id)
return channel ? { id, name: channel.name } : { id, name: id }
})
} catch (error) {
console.error(`获取员工${item.name}的渠道失败:`, error)
item.channels = []
}
}))
this.tableData = tableData
const res = await listStaff(params);
this.tableData = res.data.records || [];
this.total = res.data.total;
} catch (error) {
console.error("请求失败:", error);
this.$message.error("获取数据失败");
console.error("请求失败:", error)
this.$message.error("获取数据失败")
} finally {
this.loading = false;
this.loading = false
}
},
/* fetchData() {
const loginInfo = getInfo()
let userId = null
console.log("登录信息:", loginInfo)
if(loginInfo.data.roles[0].roleCode === 'first_dispatcher'){
userId = loginInfo.data.user.id
console.log("一级调度员id:", userId)
}
this.loading = true
const params = {
pageNo: this.currentPage,
pageSize: this.pageSize,
name: this.searchForm.name,
workNo: this.searchForm.workNo,
tel: this.searchForm.tel,
userId: userId,
roleIds: this.roleIds // roleIds
}
listStaff(params).then(res => {
this.tableData = res.data.records || []
this.total = res.data.total
this.loading = false
//
getChannelList() {
channelList().then(res => {
this.channelList = res.data || []
}).catch(() => {
this.loading = false
this.channelList = []
})
}, */
},
//
handleAdd() {
this.dialogTitle = '新增调度中心'
this.isEdit = false
this.form = {
selectedStaff: null
selectedStaff: null,
selectedChannels: []
}
this.dialogVisible = true
this.$nextTick(() => {
@ -330,10 +377,25 @@ export default {
},
//
handleEdit(index, row) {
this.dialogTitle = '编辑调度'
async handleEdit(index, row) {
this.dialogTitle = '编辑调度中心信息'
this.isEdit = true
this.form = JSON.parse(JSON.stringify(row))
//
try {
const channelRes = await getDispatchChannel(row.userId)
this.form = {
selectedStaff: { id: row.id, name: row.name, userId: row.userId },
selectedChannels: channelRes.data || [] //
}
} catch (error) {
console.error('获取渠道失败:', error)
this.form = {
selectedStaff: { id: row.id, name: row.name, userId: row.userId },
selectedChannels: []
}
}
this.dialogVisible = true
this.$nextTick(() => {
this.$refs.form.clearValidate()
@ -348,80 +410,80 @@ export default {
type: 'warning'
}).then(async () => {
try {
// 1.
// 1.
const res = await getStaffInfo(row.id)
const staffInfo = res.data
// 2. roleIdsroleIds
const currentRoleIds = staffInfo.roleIds || []
const updatedRoleIds = currentRoleIds.filter(roleId =>
!this.roleIds.includes(roleId)
)
// 2.
const updatedRoleIds = (staffInfo.roleIds || []).filter(
roleId => !this.roleIds.includes(roleId))
// 3.
const submitData = {
...staffInfo, // 使
roleIds: updatedRoleIds
}
await assignRole({ ...staffInfo, roleIds: updatedRoleIds })
// 4. API
await assignRole(submitData)
this.$message({
type: 'success',
message: '删除成功!'
// 3. ()
await saveChannel({
dispatchId: row.userId,
channelIds: []
})
this.$message.success('删除成功!')
await this.fetchData()
} catch (error) {
this.$message({
type: 'error',
message: '删除失败: ' + (error.message || '未知错误')
})
this.$message.error('删除失败: ' + (error.message || '未知错误'))
}
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
this.$message({ type: 'info', message: '已取消删除' })
})
},
//
formatChannels(channels) {
console.log('channels', channels)
if (!channels || channels.length === 0) return '-'
return channels.map(channel => channel.name).join('') // 使
},
//
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
// 1.
const selectedStaff = this.staffList.find(staff => staff.id === this.form.selectedStaff.id)
async submitForm() {
try {
await this.$refs.form.validate()
if (this.isEdit) {
// -
await saveChannel({
dispatchId: this.form.selectedStaff.userId,
channelIds: this.form.selectedChannels
})
} else {
// -
const selectedStaff = this.staffList.find(staff => staff.userId === this.form.selectedStaff.userId)
if (!selectedStaff) {
this.$message.error('未找到选中的员工信息')
return
}
console.log('selectedStaff', selectedStaff)
// 2. roleIds
const submitData = {
...selectedStaff, //
//
await assignRole({
...selectedStaff,
roleIds: [
...(selectedStaff.roleIdsStr ? selectedStaff.roleIdsStr.split(',') : []),
...(this.roleIds || [])
...this.roleIds
]
}
console.log('selectedStaff.roleIds', selectedStaff.roleIdsStr)
console.log('this.roleIds', this.roleIds)
console.log('submitData', submitData.roleIds)
// 3. API
assignRole(submitData).then(res => {
this.$message.success('分配成功')
this.dialogVisible = false
this.fetchData() //
}).catch(error => {
this.$message.error('分配失败: ' + (error.message || '未知错误'))
})
} else {
return false
//
await saveChannel({
dispatchId: selectedStaff.userId,
channelIds: this.form.selectedChannels
})
}
})
this.$message.success('操作成功')
this.dialogVisible = false
await this.fetchData()
} catch (error) {
this.$message.error('操作失败: ' + (error.message || '未知错误'))
}
},
//

View File

@ -70,11 +70,11 @@
</el-row>
<el-table v-loading="loading" :data="infoList" @selection-change="handleSelectionChange">
<el-table-column label="序号" align="center">
<!-- <el-table-column label="序号" align="center">
<template scope="scope">
<span>{{ scope.$index + 1 }}</span>
</template>
</el-table-column>
</el-table-column>-->
<el-table-column label="姓名" align="center" prop="nickName" width="100">
</el-table-column>
<el-table-column label="性别" align="center" prop="sex" width="100">
@ -104,6 +104,31 @@
</el-table-column>
<!-- <el-table-column label="所属二级调度" align="center" prop="secondDispatcherName" width="100"/>-->
<el-table-column label="所属二级调度" align="center" prop="secondDispatcherName" width="200" />
<el-table-column label="主车" align="center" prop="primaryCar" width="300">
<template slot-scope="scope">
<span v-if="scope.row.primaryCar">
{{ scope.row.primaryCar.rescueCarNum }} - {{ scope.row.primaryCar.carCategory }}
</span>
<span v-else style="color: #909399">未分配</span>
</template>
</el-table-column>
<el-table-column label="副车" align="center" prop="secondaryCars" width="300">
<template slot-scope="scope">
<div v-if="scope.row.secondaryCars && scope.row.secondaryCars.length > 0">
<el-tag
v-for="car in scope.row.secondaryCars"
:key="car.id"
size="small"
style="margin: 2px"
>
{{ car.rescueCarNum }} - {{ car.carCategory }}
</el-tag>
</div>
<span v-else style="color: #909399">未分配</span>
</template>
</el-table-column>
<el-table-column label="接单状态" align="center" prop="driverStatus">
<template slot-scope="scope">
<span v-if="scope.row.driverStatus =='1'">空闲</span>
@ -112,12 +137,12 @@
<span v-if="scope.row.driverStatus =='4'">离线</span>
</template>
</el-table-column>
<el-table-column label="当前所在位置" align="center" prop="driverPositionInfo" width="180"/>
<!-- <el-table-column label="当前所在位置" align="center" prop="driverPositionInfo" width="180"/>
<el-table-column label="司机离线时间" align="center" prop="driverOfflineTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.driverOfflineTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</el-table-column>-->
<el-table-column width="180" label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<!-- <el-button
@ -153,26 +178,7 @@
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- <el-dialog title="认证审核" :visible.sync="authFlag" width="400px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="审核结果" prop="authStatus">
<el-radio-group v-model="form.authStatus">
<el-radio label="2">通过</el-radio>
<el-radio label="3">拒绝</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="拒绝原因" prop="rejectInfo">
<el-input type="textarea" v-model="form.rejectInfo" placeholder="请输入拒绝原因"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="authSubmit"> </el-button>
<el-button @click="authCancel"> </el-button>
</div>
</el-dialog>-->
<!-- 添加或修改请填写功能名称对话框 -->
<el-dialog :title="title" :visible.sync="open" width="1100px" append-to-body>
<el-tabs :value="'first'" @tab-click="handleClick">
@ -251,29 +257,50 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="主车分配">
<el-select
v-model="form.possessorId"
placeholder="可选车辆"
@clear="handleClearPossessorId"
clearable>
v-model="form.primaryCarId"
placeholder="请选择主车"
clearable
filterable
>
<el-option
v-for="item in noAllocationCarList"
v-for="item in availableCars"
:key="item.id"
:label="item.rescueCarNum"
:label="`${item.rescueCarNum} - ${item.rescueCarBrand} - ${item.carCategory}`"
:value="item.id"
>
<div style="display: flex; justify-content: space-between">
<span>{{ item.rescueCarNum }}</span>
<span>{{ item.rescueCarBrand }}</span>
</div>
</el-option>
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-row>
<!-- 车辆分配部分副车 -->
<el-row>
<el-col :span="24">
<el-form-item label="副车分配">
<el-select
v-model="form.secondaryCarIds"
multiple
placeholder="请选择副车"
clearable
filterable
style="width: 100%"
>
<el-option
v-for="item in availableCars"
:key="item.id"
:label="`${item.rescueCarNum} - ${item.rescueCarBrand} - ${item.carCategory}`"
:value="item.id"
:disabled="form.primaryCarId === item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
@ -304,17 +331,26 @@
</el-tab-pane>
</el-tabs>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
<el-button
ype="primary"
@click="submitForm"
:loading="submitLoading"
:disabled="submitLoading"> </el-button>
<el-button
@click="cancel"
:disabled="submitLoading"
> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { driverListNew, delDriver, updateDriver, addDriverNew } from '@/api/rescue/driver'
import { driverListNew, delDriver, updateDriver, addDriverNew, driverAndCarList } from '@/api/rescue/driver'
import {
getAllCar,
assignCarToDriver,
batchAssignCars,
getAllCar, getDriverCars,
getNoAllocationCar,
listStaff,
roleIdByRoleCode,
@ -360,12 +396,18 @@ export default {
noAllocationCarList: [],
allCarList: [],
originalCarInfo: [],
availableCars: [], //
form: {
sex: '1',
secondDispatcherIds: [],
secondDispatcherId: null,
secondDispatcherName: null,
secondDispatcherIds: [], //
primaryCarId: null, // ID
secondaryCarIds: [], // ID
carRelations: [] //
},
//
submitLoading: false,
rules: {
realName: [
{ required: true, message: '不能为空', trigger: 'blur' },
@ -388,18 +430,60 @@ export default {
handleClick(tab, event) {
// console.log(tab, event)
},
/** 查询【请填写功能名称】列表 */
getList() {
/** 查询司机列表 */
async getList() {
this.loading = true
driverListNew(this.queryParams).then(response => {
try {
this.getAvailableCars()
const response = await driverAndCarList(this.queryParams)
this.infoList = response.data.records
if(this.infoList.carInfoList != null){
this.infoList.carNum = this.infoList.carInfoList[0].rescueCarNum
}
console.log('this.infoList', this.infoList)
//
this.infoList.forEach(driver => {
console.log('driver11111111', driver)
//
driver.primaryCar = driver.driverFirstCarRelationList && driver.driverFirstCarRelationList.length > 0
? this.findCarById(driver.driverFirstCarRelationList[0].carId)
: null
//
driver.secondaryCars = driver.driverSecondCarRelationList
? driver.driverSecondCarRelationList.map(relation => this.findCarById(relation.carId)).filter(car => car !== null)
: []
//
driver.secondaryCarCount = driver.secondaryCars.length
})
console.log('infoList111111111111111', this.infoList)
this.total = response.data.total
} catch (error) {
console.error('获取司机列表失败:', error)
} finally {
this.loading = false
})
}
},
// ID
findCarById(carId) {
console.log('carId', carId)
console.log('this.allCarList', this.allCarList)
return this.allCarList.find(car => car.id == carId) || null
},
/** 加载司机的车辆信息 */
async loadDriverCarInfo(driver) {
try {
const carResponse = await getDriverCars(driver.id)
if (carResponse.data) {
//
driver.primaryCar = carResponse.data.primaryCar
driver.secondaryCars = carResponse.data.secondaryCars || []
driver.secondaryCarCount = driver.secondaryCars.length
}
} catch (error) {
console.error(`获取司机${driver.id}的车辆信息失败:`, error)
}
},
//
@ -414,46 +498,20 @@ export default {
})
},
//
/* async getNoAllocationCar() {
const res = await getNoAllocationCar()
this.noAllocationCarList = res.data || []
}, */
async getNoAllocationCar() {
const res = await getNoAllocationCar();
this.noAllocationCarList = res.data || [];
//
if (this.form.id && this.originalCarInfo) {
//
const alreadyExists = this.noAllocationCarList.some(
car => car.id === this.originalCarInfo.id
);
if (!alreadyExists) {
this.noAllocationCarList.unshift(this.originalCarInfo);
}
//
async getAvailableCars() {
try {
const res = await getAllCar()
this.availableCars = res.data || []
this.allCarList = this.availableCars
console.log('获取可用车辆成功:', this.availableCars)
} catch (error) {
console.error('获取可用车辆失败:', error)
this.availableCars = []
this.availableCars = []
}
},
//
async getAllCar() {
const res = await getAllCar()
this.allCarList = res.data || []
},
/* handleSecondDispatcherChange(userId) {
const selectedDispatcher = this.secondDispatcherList.find(item => item.userId === userId)
if (selectedDispatcher) {
this.form.secondDispatcherId = userId
this.form.secondDispatcherName = selectedDispatcher.name
}
},
handleClearSecondDispatcher() {
this.form.secondDispatcherName = ''
this.form.secondDispatcherId = ''
}, */
handleSecondDispatcherChange(selectedUserIds) {
const allSelectedItems = selectedUserIds.map(userId => {
const foundItem = this.secondDispatcherList.find(item => item.userId == userId);
@ -471,43 +529,33 @@ export default {
this.form.secondDispatcherName = '';
},
handleClearPossessorId(){
this.form.possessorId = null
},
//
cancel() {
this.open = false
this.reset()
},
authCancel() {
this.authFlag = false
this.reset()
},
//
/* reset() {
reset() {
this.resetForm('form')
this.form = {
id: null,
userId: null,
// ... other fields
secondDispatcherId: null,
secondDispatcherName: null,
sex: null
}
}, */
reset() {
this.resetForm('form');
this.form = {
id: null,
userId: null,
// ... other fields
realName: null,
phonenumber: null,
sex: '1',
age: null,
driverType: null,
secondDispatcherIds: [],
secondDispatcherId: null,
secondDispatcherName: null,
sex: null
};
this.originalCarInfo = null;
primaryCarId: null,
secondaryCarIds: [],
carRelations: [],
idCardRight: null,
idCardBack: null,
licenseImage: null,
avatar: null
}
},
/** 搜索按钮操作 */
@ -531,181 +579,163 @@ export default {
this.reset()
this.open = true
this.title = '添加司机'
//
//
Promise.all([
this.getSecondDispatcherList(),
this.getNoAllocationCar()
])
},
/** 修改按钮操作 */
/* handleUpdate(row) {
this.reset()
const rowData = { ...row }
this.originalCarInfo = row.carInfoList?.[0] || null;
delete rowData.carInfoList
this.form = {
...rowData,
realName: row.nickName,
secondDispatcherId: row.secondDispatcherId ? row.secondDispatcherId.split(',') : [],
secondDispatcherName: row.secondDispatcherName,
possessorId: this.originalCarInfo?.id || null
}
if (this.form.secondDispatcherName == null) {
this.form.secondDispatcherId = null
}
this.open = true
this.title = '修改司机信息'
Promise.all([
this.getSecondDispatcherList(),
this.getNoAllocationCar()
this.getAvailableCars()
]).then(() => {
if (row.secondDispatcherId) {
this.handleSecondDispatcherChange(row.secondDispatcherId)
}
//
this.form.primaryCarId = null
this.form.secondaryCarIds = []
})
}, */
handleUpdate(row) {
this.reset();
const rowData = { ...row };
this.originalCarInfo = row.carInfoList?.[0] || null;
delete rowData.carInfoList;
},
//
const initialIds = row.secondDispatcherId ? row.secondDispatcherId.split(',') : [];
const initialNames = row.secondDispatcherName ? row.secondDispatcherName.split(',') : [];
/** 修改按钮操作 */
async handleUpdate(row) {
this.reset()
//
//
const rowData = { ...row }
this.form = {
...rowData,
realName: row.nickName,
secondDispatcherIds: initialIds,
secondDispatcherIds: row.secondDispatcherId ? row.secondDispatcherId.split(',') : [],
secondDispatcherId: row.secondDispatcherId || '',
secondDispatcherName: row.secondDispatcherName || '',
possessorId: this.originalCarInfo?.id || null
};
primaryCarId: null, // null
secondaryCarIds: [] //
}
this.open = true;
this.title = '修改司机信息';
this.open = true
this.title = '修改司机信息'
try {
//
await Promise.all([
this.getSecondDispatcherList(),
this.getAvailableCars()
])
Promise.all([
this.getSecondDispatcherList(),
this.getNoAllocationCar()
]).then(() => {
//
const initialIds = row.secondDispatcherId ? row.secondDispatcherId.split(',') : []
const initialNames = row.secondDispatcherName ? row.secondDispatcherName.split(',') : []
if (initialIds.length > 0) {
const missingItems = initialIds.map((userId, index) => {
const found = this.secondDispatcherList.some(item => item.userId === userId);
const found = this.secondDispatcherList.some(item => item.userId == userId)
if (!found) {
return {
userId: userId,
name: initialNames[index] || '未知调度员'
};
}
}
return null;
}).filter(Boolean);
return null
}).filter(Boolean)
if (missingItems.length > 0) {
//
this.secondDispatcherList = [...this.secondDispatcherList, ...missingItems];
this.secondDispatcherList = [...this.secondDispatcherList, ...missingItems]
}
}
});
//
await this.$nextTick()
//
if (row.driverFirstCarRelationList && row.driverFirstCarRelationList.length > 0) {
const primaryCarRelation = row.driverFirstCarRelationList[0]
this.form.primaryCarId = primaryCarRelation.carId
//
if (row.driverSecondCarRelationList) {
const secondaryCarIds = row.driverSecondCarRelationList.map(relation => relation.carId)
// ID
// if (!secondaryCarIds.includes(primaryCarRelation.carId)) {
// secondaryCarIds.push(primaryCarRelation.carId)
// }
this.form.secondaryCarIds = secondaryCarIds
}
} else if (row.driverSecondCarRelationList) {
//
this.form.secondaryCarIds = row.driverSecondCarRelationList.map(relation => relation.carId)
}
} catch (error) {
console.error('获取司机信息失败:', error)
this.$modal.msgError('获取信息失败')
}
},
handleAuth(row) {
this.reset()
this.form = row
this.authFlag = true
},
//
/** 提交按钮 */
/* async submitForm() {
async submitForm() {
if (this.submitLoading) return;
this.$refs['form'].validate(async valid => {
if (valid) {
try {
//
const operation = this.form.id
? updateDriver(this.form)
: addDriverNew(this.form);
const response = await operation;
const userId = response.data || this.form.userId;
const id = this.form.id;
//
if (this.form.id) {
// -
await this.handleCarAssignmentForUpdate(id);
} else {
// -
await this.handleCarAssignmentForAdd(userId);
}
this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功');
this.open = false;
this.getList();
} catch (error) {
console.error('操作失败:', error);
}
}
});
}, */
submitForm() {
this.$refs['form'].validate(async valid => {
if (valid) {
try {
// secondDispatcherIdsecondDispatcherName
const formData = {
//
this.submitLoading = true;
//
const driverData = {
...this.form,
secondDispatcherId: this.form.secondDispatcherId || '',
secondDispatcherName: this.form.secondDispatcherName || ''
};
//
const operation = this.form.id
? updateDriver(formData)
: addDriverNew(formData);
const response = await operation;
const userId = response.data || this.form.userId;
const id = this.form.id;
//
if (this.form.id) {
// -
await this.handleCarAssignmentForUpdate(id);
} else {
// -
await this.handleCarAssignmentForAdd(userId);
secondDispatcherName: this.form.secondDispatcherName || '',
nickName: this.form.realName
}
this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功');
this.open = false;
this.getList();
//
let driverId
if (this.form.id) {
await updateDriver(driverData)
driverId = this.form.id
} else {
const response = await addDriverNew(driverData)
driverId = response.data
}
// -
if (driverId) {
await this.handleCarAssignment(driverId)
}
this.$modal.msgSuccess(this.form.id ? '修改成功' : '新增成功')
this.open = false
this.getList()
} catch (error) {
console.error('操作失败:', error);
this.$modal.msgError('操作失败,请重试');
console.error('操作失败:', error)
this.$modal.msgError('操作失败,请重试')
}finally {
//
this.submitLoading = false;
}
}
});
},
authSubmit() {
updateDriver(this.form).then(response => {
this.$modal.msgSuccess('审核成功')
this.authFlag = false
this.getList()
})
},
/** 处理车辆分配 */
async handleCarAssignment(driverId) {
try {
//
const assignmentData = {
driverId: driverId,
primaryCarId: this.form.primaryCarId,
secondaryCarIds: this.form.secondaryCarIds || []
}
await batchAssignCars(assignmentData)
} catch (error) {
console.error('车辆分配失败:', error)
throw new Error('车辆分配失败')
}
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除编号为"' + ids + '"的数据项?').then(function() {
const ids = row.userId || this.ids
this.$modal.confirm('是否确认删除编号为"' + ids + '"的数据项?').then(() => {
return delDriver(ids)
}).then(() => {
this.getList()
this.$modal.msgSuccess('删除成功')
}).catch(() => {
})
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
@ -714,51 +744,6 @@ export default {
}, `info_${new Date().getTime()}.xlsx`)
},
//
async handleCarAssignmentForAdd(userId) {
if (this.form.possessorId) {
await updateRescueCar({
id: this.form.possessorId,
possessorId: userId
})
}
},
//
async handleCarAssignmentForUpdate(userId) {
const originalCarId = this.infoList.find(item => item.id === this.form.id)?.carInfoList?.[0]?.id
const newCarId = this.form.possessorId
// 1: -
if (originalCarId && !newCarId) {
await updateRescueCar({
id: originalCarId,
possessorId: null
})
}
// 2: -
else if (!originalCarId && newCarId) {
await updateRescueCar({
id: newCarId,
possessorId: userId
})
}
// 3: -
else if (originalCarId && newCarId && originalCarId !== newCarId) {
//
await updateRescueCar({
id: originalCarId,
possessorId: null
})
//
await updateRescueCar({
id: newCarId,
possessorId: userId
})
}
// 4: -
}
}
}
</script>

View File

@ -144,8 +144,8 @@
>
<el-option
v-for="channel in channelList"
:key="channel.value"
:label="channel.label"
:key="channel.id"
:label="channel.name"
:value="channel.id"
/>
</el-select>
@ -161,7 +161,7 @@
<script>
import {
assignRole,
assignRole, channelList,
getChannel,
getDispatchChannel,
getStaffInfo,
@ -276,7 +276,7 @@ export default {
const channelRes = await getDispatchChannel(item.userId);
item.channels = (channelRes.data || []).map(id => {
const channel = this.channelList.find(c => c.id === id);
return channel ? { id, label: channel.label } : { id, label: id };
return channel ? { id, name: channel.name } : { id, name: id };
});
} catch (error) {
console.error(`获取员工${item.name}的渠道失败:`, error);
@ -403,7 +403,7 @@ export default {
//
getChannelList() {
getChannel(getTenantId()).then(res => {
channelList().then(res => {
this.channelList = res.data || []
}).catch(() => {
this.channelList = []
@ -412,8 +412,9 @@ export default {
//
formatChannels(channels) {
console.log('channels', channels)
if (!channels || channels.length === 0) return '-'
return channels.map(channel => channel.label).join('') // 使
return channels.map(channel => channel.name).join('') // 使
},
//

View File

@ -194,6 +194,17 @@
<span>{{ scope.row.payTime }}</span>
</template>
</el-table-column>
<el-table-column label="是否确认收款" align="center" width="100" prop="ifConfirmPay">
<template slot-scope="scope">
<span v-if="scope.row.ifConfirmPay === '0'" style="color: #e6a23c">待确认</span>
<span v-else-if="scope.row.ifConfirmPay === '1'" style="color: #67c23a">已确认</span>
</template>
</el-table-column>
<el-table-column label="确认收款人" align="center" width="100" prop="confirmPaymentPersonName" />
<el-table-column label="确认收款时间" align="center" width="100" prop="confirmPaymentTime" />
<el-table-column label="确认收款备注" align="center" width="100" prop="confirmPaymentPersonRemark" show-overflow-tooltip/>
<!-- 0是未确认 1是已确认-->
<el-table-column fixed="right" label="操作" align="center" width="150" class-name="small-padding fixed-width">
<template slot-scope="scope">
<!-- <el-button-->
@ -232,8 +243,19 @@
icon="el-icon-circle-check"
v-hasPermi="['rescue:finance:confirm']"
@click="confirmPayment(scope.row)"
v-if="scope.row.ifConfirmPay === '0' "
>确认收款
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-view"
v-hasPermi="['rescue:finance:confirm']"
v-else-if="scope.row.ifConfirmPay === '1' "
@click="viewConfirmPayment(scope.row)"
style="color: #c0c4cc"
>已确认收款
</el-button>
<el-button
size="mini"
type="text"
@ -427,6 +449,33 @@
<image-preview v-for="item in watchImgList" :src="item" :width="200" :height="200"/>
</el-dialog>
<!-- 查看确认收款信息弹框 -->
<el-dialog title="查看收款信息" :visible.sync="viewPaymentOpen" width="600px" append-to-body>
<el-form :model="viewPaymentForm" label-width="120px">
<el-form-item label="确认收款人">
<el-input v-model="viewPaymentForm.confirmPaymentPersonName" :disabled="true"/>
</el-form-item>
<el-form-item label="确认收款时间">
<el-input v-model="viewPaymentForm.confirmPaymentTime" :disabled="true"/>
</el-form-item>
<el-form-item label="实收金额">
<el-input :value="(viewPaymentForm.payMoney / 100).toFixed(2)" :disabled="true"/>
</el-form-item>
<el-form-item label="确认收款备注">
<el-input
type="textarea"
:autosize="{ minRows: 2, maxRows: 4}"
:disabled="true"
v-model="viewPaymentForm.confirmPaymentPersonRemark"
>
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="viewPaymentOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
@ -511,6 +560,14 @@ export default {
watchImgList: [],
pickerOptions: null,
loginUserInfo: {},
//
viewPaymentOpen: false,
viewPaymentForm: {
confirmPaymentPersonName: '',
confirmPaymentTime: '',
payMoney: 0,
confirmPaymentPersonRemark: ''
},
//
rules: {
connectionName: [
@ -609,6 +666,7 @@ export default {
this.confirmPaymentForm.payMoney = this.confirmPaymentForm.payMoney * 100
this.confirmPaymentForm.confirmPaymentPersonId = this.loginUserInfo.id
this.confirmPaymentForm.confirmPaymentPersonName = this.loginUserInfo.nickname
this.confirmPaymentForm.ifConfirmPay = '1'
confirmReceipt(this.confirmPaymentForm).then(res => {
this.$modal.msgSuccess('收款成功')
this.confirmPaymentOpen = false
@ -625,6 +683,18 @@ export default {
this.confirmPaymentForm.payMoney = ( data.setMoney / 100).toFixed(2)
},
//
viewConfirmPayment(data) {
console.log('data', data)
this.viewPaymentOpen = true
this.viewPaymentForm = {
confirmPaymentPersonName: data.confirmPaymentPersonName,
confirmPaymentTime: data.confirmPaymentTime,
payMoney: data.payMoney,
confirmPaymentPersonRemark: data.confirmPaymentPersonRemark
}
},
driverOk() {
this.designateFlag = false
designateDriver(this.rescueInfoId, this.chooseDriverId).then(res => {

View File

@ -5,7 +5,8 @@ import { praseStrEmpty } from "@/utils/ruoyi";
export function listUser(query) {
return request({
// url: '/base/dl-drive-school-coach/page',
url: '/system/role/selectListByRoleIdJY',
// url: '/system/role/selectListByRoleIdJY',
url: '/system/role/selectListByRoleIdJYNew',
method: 'get',
params: query
})
@ -38,7 +39,7 @@ export function getDriverLicenseType(userId) {
export function addUser(data) {
return request({
// url: '/inspectionStaff/save',
url: '/system/rescueInfo/addDriverApp',
url: '/system/rescueInfo/addDriverAppNew',
method: 'post',
data: data
})
@ -64,7 +65,7 @@ export function permissionAssign(data) {
export function updateUser(data) {
return request({
// url: '/inspectionStaff/update',
url: '/system/rescueInfo/updateDriver',
url: '/system/rescueInfo/updateDriverNew',
method: 'post',
data: data
})

View File

@ -80,8 +80,8 @@
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入姓名"/>
<el-form-item label="姓名" prop="nickname">
<el-input v-model="form.nickname" placeholder="请输入姓名"/>
</el-form-item>
</el-col>
<el-col :span="12">
@ -110,6 +110,24 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="员工类型" prop="staffType">
<el-select v-model="form.staffType" placeholder="请选择" style="width: 100%" >
<el-option v-for="dict in staffTypeDictDatas" :key="dict.value" :label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位" prop="postId">
<el-select multiple v-model="form.roleIds" placeholder="请选择岗位" @change="onPostChange">
<el-option v-for="item in postOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- <el-row>
<el-col :span="12">
@ -205,7 +223,7 @@ import {DICT_TYPE, getDictDatas} from "@/utils/dict";
import {assignUserRole, listUserRoles} from "@/api/system/permission";
import {listSimpleRoles} from "@/api/system/role";
import {getBaseHeader} from "@/utils/request";
import { delDriver } from '@/api/rescue/driver'
import { delDriver, delDriverStaff } from '@/api/rescue/driver'
export default {
name: "SystemUser",
@ -337,13 +355,14 @@ export default {
//
statusDictDatas: getDictDatas(DICT_TYPE.COMMON_STATUS),
sexDictDatas: getDictDatas(DICT_TYPE.SYSTEM_USER_SEX),
staffTypeDictDatas: getDictDatas(DICT_TYPE.RESCUE_STAFF_TYPE),
singleRoleId: null,
postTypeMapping: {
'教练': 'jl',
'业务经理': 'ywjl',
},
defaultType: 'yg'
defaultType: 'yg',
};
},
watch: {
@ -414,6 +433,18 @@ export default {
this.form.type = this.defaultType;
}
},
onPostChange(val) {
// 使 roleIds ID
this.form.roleIds = val;
// type
const selectedPost = this.postOptions.find(post => post.id === (Array.isArray(val) ? val[0] : val));
if (selectedPost && this.postTypeMapping[selectedPost.name]) {
this.form.type = this.postTypeMapping[selectedPost.name];
} else {
this.form.type = this.defaultType;
}
},
//
filterNode(value, data) {
if (!value) return true;
@ -463,7 +494,8 @@ export default {
status: "0",
remark: undefined,
postIds: [],
roleIds: []
roleIds: [],
staffType: undefined
};
this.fileList = [];
this.singleRoleId = null;
@ -496,7 +528,7 @@ export default {
this.form.type = this.defaultType;
},
/** 修改按钮操作 */
handleUpdate(row) {
/* handleUpdate(row) {
this.reset();
const id = row.id;
this.isInsert = false;
@ -507,6 +539,7 @@ export default {
})
.then(response => {
this.form = response.data;
this.form.roleIds = response.data.roles.map(item => item.id);
this.fileList = this.form.fileList == null ? [] : this.form.fileList;
if (this.form.roleIds && this.form.roleIds.length > 0) {
@ -533,7 +566,38 @@ export default {
console.error("加载数据失败:", error);
this.$message.error("加载员工数据失败");
});
}, */
handleUpdate(row) {
this.reset();
const id = row.id;
this.isInsert = false;
this.getPostsByDeptId()
.then(() => {
return getUser(id);
})
.then(response => {
this.form = response.data;
// 使 roleIds ID
if (response.data.roles && response.data.roles.length > 0) {
this.form.roleIds = response.data.roles.map(role => role.id);
//
const firstRoleId = this.form.roleIds[0];
const currentPost = this.postOptions.find(post => post.id === firstRoleId);
if (currentPost && this.postTypeMapping[currentPost.name]) {
this.form.type = this.postTypeMapping[currentPost.name];
} else {
this.form.type = this.defaultType;
}
}
this.open = true;
this.title = "修改员工";
});
},
/** 重置密码按钮操作 */
handleResetPwd(row) {
this.$prompt('请输入"' + row.username + '"的新密码', "提示", {
@ -584,12 +648,14 @@ export default {
// this.form.id = this.form.driverId;
const requestForm = {
id: this.form.driverId,
realName: this.form.nickName,
realName: this.form.nickname,
userId: this.form.userId,
phonenumber: this.form.mobile,
age: this.form.age,
sex: this.form.sex,
avatar: this.form.avatar,
staffType: this.form.staffType,
roleIds: this.form.roleIds
};
if (this.form.userId !== undefined) {
@ -600,6 +666,7 @@ export default {
let data = {
userId: this.form.userId,
roleIds: this.form.roleIds,
servicePackageId: 'jiuyuan'
};
return permissionAssign(data); // Promise
})
@ -611,6 +678,7 @@ export default {
this.$modal.msgError("操作失败");
});
} else {
requestForm.staffType = this.form.staffType;
this.form.username = this.form.mobile;
this.form.password = "123456";
addUser(requestForm)
@ -620,6 +688,7 @@ export default {
let data = {
userId: response.data,
roleIds: this.form.roleIds,
servicePackageId: 'jiuyuan'
};
return permissionAssign(data); // Promise
})
@ -650,9 +719,10 @@ export default {
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.driverId;
console.log('删除', row)
const ids = row.id;
this.$modal.confirm('是否确认删除员工编号为"' + ids + '"的数据项?').then(function () {
return delDriver(ids);
return delDriverStaff(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");

View File

@ -0,0 +1,91 @@
import request from '@/utils/request'
export function fetchList(params) {
return request({
url: '/rescue-type-phenomenon/listByPid',
method: 'get',
params
})
}
export function createType(data) {
return request({
url: '/rescue-type-phenomenon/createType',
method: 'post',
data
})
}
export function createPhenomenon(data) {
return request({
url: '/rescue-type-phenomenon/createPhenomenon',
method: 'post',
data
})
}
export function updateItem(data) {
// 根据类型选择不同的更新接口
const url = data.type === 0 ?
'/rescue-type-phenomenon/updateType' :
'/rescue-type-phenomenon/updatePhenomenon'
return request({
url: url,
method: 'put',
data
})
}
export function deleteItem(id) {
return request({
url: `/rescue-type-phenomenon/delete/${id}`,
method: 'delete'
})
}
//----------------------------------------------------------
export function fetchTypeList(params) {
return request({
url: '/rescue-type-phenomenon/typePage',
method: 'get',
params
})
}
export function getPhenomenonsByTypeId(typeId) {
return request({
url: `/rescue-type-phenomenon/phenomenon/${typeId}`,
method: 'get'
})
}
export function updateType(data) {
return request({
url: '/rescue-type-phenomenon/updateType',
method: 'put',
data
})
}
export function updatePhenomenon(data) {
return request({
url: '/rescue-type-phenomenon/updatePhenomenon',
method: 'put',
data
})
}
export function deleteType(id) {
return request({
url: `/rescue-type-phenomenon/deleteType/${id}`,
method: 'delete'
})
}
export function deletePhenomenon(id) {
return request({
url: `/rescue-type-phenomenon/deletePhenomenon/${id}`,
method: 'delete'
})
}

View File

@ -0,0 +1,490 @@
<template>
<div class="app-container">
<el-card>
<!-- 搜索区域 -->
<div style="display: flex; justify-content: space-between; align-items: center;">
<div class="filter-container">
<el-input
v-model="listQuery.name"
placeholder="故障类型名称"
style="width: 200px;"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>
搜索
</el-button>
<el-button
class="filter-item"
style="margin-left: 10px;"
type="primary"
icon="el-icon-plus"
@click="handleCreateType"
>
新增故障类型
</el-button>
</div>
<div class="filter-container">
<el-button
class="filter-item"
style="margin-left: auto;"
icon="el-icon-refresh"
:loading="refreshing"
:disabled="refreshing"
@click="handleRefresh"
/>
</div>
</div>
<!-- 表格 -->
<el-table
:data="list"
border
fit
highlight-current-row
style="width: 100%; margin-top: 20px;"
row-key="id"
:expand-row-keys="expandedRows"
@expand-change="handleExpandChange"
>
<el-table-column type="expand">
<template slot-scope="{row}">
<div class="phenomenon-container">
<div class="phenomenon-header">
<span class="phenomenon-title">故障现象列表</span>
<el-button
type="primary"
size="medium "
icon="el-icon-plus"
@click="handleCreatePhenomenon(row)"
>
添加故障现象
</el-button>
</div>
<el-table
:data="row.phenomenons"
size="medium "
style="width: 100%; margin-top: 10px;"
v-loading="row.loading"
border
>
<el-table-column label="故障现象名称" prop="name">
<template slot-scope="{row: phenomenon}">
<span class="bold-text">{{ phenomenon.name }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" align="center" >
<template slot-scope="{row: phenomenon}">
{{ phenomenon.createTime | parseTime }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="{row: phenomenon}">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="handleUpdatePhenomenon(phenomenon)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDeletePhenomenon(phenomenon)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<el-table-column label="故障类型名称" prop="name">
<template slot-scope="{row}">
<span class="bold-text">{{ row.name }}</span>
</template>
<template slot="header">
<span class="bold-header">故障类型名称</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" align="center" >
<template slot-scope="{row}">
{{ row.createTime | parseTime }}
</template>
</el-table-column>
<!-- <el-table-column label="创建人" prop="creator" align="center" />-->
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="{row}">
<el-button
type="primary"
size="small"
icon="el-icon-edit"
@click="handleUpdateType(row)"
>
编辑
</el-button>
<el-button
type="danger"
size="small"
icon="el-icon-delete"
@click="handleDeleteType(row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="listQuery.page"
:limit.sync="listQuery.limit"
@pagination="getList"
/>
</el-card>
<!-- 故障类型对话框 -->
<el-dialog
:title="typeDialogTitle"
:visible.sync="typeDialogVisible"
width="500px"
>
<el-form
ref="typeForm"
:rules="rules"
:model="typeTemp"
label-position="left"
label-width="120px"
style="width: 400px; margin-left:50px;"
>
<el-form-item label="故障类型名称" prop="name">
<el-input v-model="typeTemp.name" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="typeDialogVisible = false">
取消
</el-button>
<el-button type="primary" @click="saveType">
确认
</el-button>
</div>
</el-dialog>
<!-- 故障现象对话框 -->
<el-dialog
:title="phenomenonDialogTitle"
:visible.sync="phenomenonDialogVisible"
width="500px"
>
<el-form
ref="phenomenonForm"
:rules="rules"
:model="phenomenonTemp"
label-position="left"
label-width="120px"
style="width: 400px; margin-left:50px;"
>
<el-table-column label="故障现象名称" prop="name">
<template slot-scope="{row: phenomenon}">
<span class="bold-text">{{ phenomenon.name }}</span>
</template>
<template slot="header">
<span class="bold-header">故障现象名称</span>
</template>
</el-table-column>
<el-form-item label="故障现象名称" prop="name">
<el-input v-model="phenomenonTemp.name" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="phenomenonDialogVisible = false">
取消
</el-button>
<el-button type="primary" @click="savePhenomenon">
确认
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import Pagination from '@/components/Pagination'
import { fetchTypeList, getPhenomenonsByTypeId, createType, createPhenomenon, updateType, updatePhenomenon, deleteType, deletePhenomenon } from './api'
export default {
name: 'RescueTypePhenomenon',
components: { Pagination },
filters: {
parseTime(time) {
if (!time) return ''
return new Date(time).toLocaleString()
}
},
data() {
return {
list: [],
total: 0,
listQuery: {
page: 1,
limit: 20,
name: undefined
},
expandedRows: [],
typeTemp: {
id: undefined,
name: ''
},
phenomenonTemp: {
id: undefined,
pid: undefined,
name: ''
},
typeDialogVisible: false,
phenomenonDialogVisible: false,
typeDialogTitle: '',
phenomenonDialogTitle: '',
refreshing: false, //
rules: {
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
}
}
},
created() {
this.getList()
},
methods: {
async getList() {
try {
const response = await fetchTypeList(this.listQuery)
console.log('获取列表成功:', response)
this.list = response.data.records.map(item => ({
...item,
phenomenons: [],
loading: false
}))
this.total = response.data.total
//
this.expandedRows = []
} catch (error) {
console.error('获取列表失败:', error)
}
},
async handleExpandChange(row, expandedRows) {
if (expandedRows.includes(row)) {
//
if (!row.phenomenons || row.phenomenons.length === 0) {
row.loading = true
try {
const response = await getPhenomenonsByTypeId(row.id)
row.phenomenons = response.data
} catch (error) {
console.error('获取故障现象列表失败:', error)
} finally {
row.loading = false
}
}
}
},
handleFilter() {
this.listQuery.page = 1
//
this.expandedRows = []
this.getList()
},
handleCreateType() {
this.typeTemp = {
id: undefined,
name: ''
}
this.typeDialogTitle = '新增故障类型'
this.typeDialogVisible = true
this.$nextTick(() => {
this.$refs.typeForm?.clearValidate()
})
},
handleUpdateType(row) {
this.typeTemp = { ...row }
this.typeDialogTitle = '编辑故障类型'
this.typeDialogVisible = true
this.$nextTick(() => {
this.$refs.typeForm?.clearValidate()
})
},
handleCreatePhenomenon(row) {
this.phenomenonTemp = {
id: undefined,
pid: row.id,
name: ''
}
this.phenomenonDialogTitle = '新增故障现象'
this.phenomenonDialogVisible = true
this.$nextTick(() => {
this.$refs.phenomenonForm?.clearValidate()
})
},
handleUpdatePhenomenon(phenomenon) {
this.phenomenonTemp = { ...phenomenon }
this.phenomenonDialogTitle = '编辑故障现象'
this.phenomenonDialogVisible = true
this.$nextTick(() => {
this.$refs.phenomenonForm?.clearValidate()
})
},
async handleDeleteType(row) {
this.$confirm(`确定要删除故障类型"${row.name}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
await deleteType(row.id)
this.$message.success('删除成功!')
this.getList()
} catch (error) {
console.error('删除失败:', error)
}
}).catch(() => {})
},
async handleDeletePhenomenon(phenomenon) {
this.$confirm(`确定要删除故障现象"${phenomenon.name}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async() => {
try {
await deletePhenomenon(phenomenon.id)
this.$message.success('删除成功!')
//
const type = this.list.find(item => item.id === phenomenon.pid)
if (type) {
type.loading = true
const response = await getPhenomenonsByTypeId(type.id)
type.phenomenons = response.data
type.loading = false
}
} catch (error) {
console.error('删除失败:', error)
}
}).catch(() => {})
},
async saveType() {
this.$refs.typeForm.validate(async(valid) => {
if (valid) {
try {
if (this.typeTemp.id) {
await updateType(this.typeTemp)
} else {
await createType(this.typeTemp)
}
this.typeDialogVisible = false
this.$message.success('保存成功')
this.getList()
} catch (error) {
console.error('保存失败:', error)
}
}
})
},
async savePhenomenon() {
this.$refs.phenomenonForm.validate(async(valid) => {
if (valid) {
try {
if (this.phenomenonTemp.id) {
await updatePhenomenon(this.phenomenonTemp)
} else {
await createPhenomenon(this.phenomenonTemp)
}
this.phenomenonDialogVisible = false
this.$message.success('保存成功')
//
const type = this.list.find(item => item.id === this.phenomenonTemp.pid)
if (type) {
type.loading = true
const response = await getPhenomenonsByTypeId(type.id)
type.phenomenons = response.data
type.loading = false
}
} catch (error) {
console.error('保存失败:', error)
}
}
})
},
/* handleRefresh() {
this.getList()
this.$message.success('刷新成功')
}, */
async handleRefresh() {
this.refreshing = true
try {
await this.getList()
this.$message.success('刷新成功')
} catch (error) {
console.error('刷新失败:', error)
} finally {
this.refreshing = false
}
},
}
}
</script>
<style scoped>
.filter-container {
margin-bottom: 20px;
}
.filter-item {
margin-right: 10px;
}
.phenomenon-container {
padding: 10px;
background: #fafafa;
}
.phenomenon-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.phenomenon-title {
font-weight: bold;
color: #606266;
}
/* 加粗样式 */
.bold-header {
font-weight: bold;
font-size: 14px;
color: black;
}
.bold-text {
font-weight: bold;
color: black;
}
/* 全局样式,确保表头也加粗 */
.el-table .bold-header {
font-weight: bold !important;
}
.el-table .bold-text {
font-weight: bold !important;
}
</style>