491 lines
14 KiB
Vue
491 lines
14 KiB
Vue
|
|
<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>
|