977 lines
30 KiB
Vue
977 lines
30 KiB
Vue
<template>
|
||
<div class="page-section active" id="page-consultation-form">
|
||
<div class="page-padding">
|
||
<div class="title-wrap">
|
||
<h1 class="page-title">咨询表单</h1>
|
||
</div>
|
||
|
||
<div class="stats-grid">
|
||
<div class="stats-card">
|
||
<p class="stats-label">总咨询量</p>
|
||
<p class="stats-value stats-value-dark">{{ formatCount(totalCount) }}</p>
|
||
</div>
|
||
<div class="stats-card">
|
||
<p class="stats-label">微信公众号渠道</p>
|
||
<p class="stats-value stats-value-green">{{ formatCount(wechatCount) }}</p>
|
||
</div>
|
||
<div class="stats-card">
|
||
<p class="stats-label">官网渠道</p>
|
||
<p class="stats-value stats-value-purple">{{ formatCount(webCount) }}</p>
|
||
</div>
|
||
<div class="stats-card">
|
||
<p class="stats-label">待回复</p>
|
||
<p class="stats-value stats-value-orange">{{ formatCount(pendingCount) }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="filter-card">
|
||
<el-form :model="queryForm" inline class="filter-form">
|
||
<el-form-item label="姓名">
|
||
<el-input v-model.trim="queryForm.name" size="small" clearable placeholder="请输入姓名" @keyup.enter.native="handleSearch" />
|
||
</el-form-item>
|
||
<el-form-item label="手机号">
|
||
<el-input v-model.trim="queryForm.phone" size="small" clearable placeholder="请输入手机号" @keyup.enter.native="handleSearch" />
|
||
</el-form-item>
|
||
<el-form-item label="邮箱">
|
||
<el-input v-model.trim="queryForm.email" size="small" clearable placeholder="请输入邮箱" @keyup.enter.native="handleSearch" />
|
||
</el-form-item>
|
||
<el-form-item label="渠道来源">
|
||
<el-select v-model="queryForm.source" size="small" clearable placeholder="全部渠道">
|
||
<el-option label="全部渠道" value="" />
|
||
<el-option v-for="item in sourceList" :key="item" :label="item" :value="item" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="回复状态">
|
||
<el-select v-model="queryForm.feedback" size="small" clearable placeholder="全部状态">
|
||
<el-option label="全部状态" value="" />
|
||
<el-option v-for="item in feedbackOptions" :key="item.id" :label="item.name" :value="String(item.id)" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" size="small" @click="handleSearch">查询</el-button>
|
||
<el-button size="small" @click="resetSearch">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<div class="action-bar">
|
||
<div class="batch-actions">
|
||
<el-button
|
||
type="success"
|
||
icon="el-icon-download"
|
||
size="small"
|
||
:loading="exportLoading"
|
||
@click="getTableData('1')"
|
||
>
|
||
导出Excel
|
||
</el-button>
|
||
<el-button type="primary" size="small" :loading="actionLoading" :disabled="!selectedRows.length" @click="batchUpdateFeedback('1')">
|
||
批量标记沟通中
|
||
</el-button>
|
||
<el-button type="warning" size="small" :loading="actionLoading" :disabled="!selectedRows.length" @click="batchUpdateFeedback('0')">
|
||
批量标记待回复
|
||
</el-button>
|
||
<el-button type="danger" size="small" :loading="actionLoading" :disabled="!selectedRows.length" @click="batchDelete">
|
||
批量删除
|
||
</el-button>
|
||
</div>
|
||
<div class="record-count">共 {{ totalCount }} 条记录</div>
|
||
</div>
|
||
|
||
<div class="table-card">
|
||
<el-table
|
||
v-loading="tableLoading"
|
||
:data="tableData"
|
||
class="consulting-table"
|
||
empty-text="暂无咨询数据"
|
||
style="width: 100%"
|
||
@selection-change="handleSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="46" align="center" />
|
||
<el-table-column label="ID" width="80" align="center">
|
||
<template slot-scope="scope">
|
||
{{ getRowNo(scope.$index) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="name" label="姓名" min-width="90" />
|
||
<el-table-column prop="phone" label="手机号" min-width="120" />
|
||
<el-table-column prop="email" label="邮箱" min-width="180" show-overflow-tooltip />
|
||
<el-table-column label="公司名称/企业规模" min-width="180" show-overflow-tooltip>
|
||
<template slot-scope="scope">
|
||
<div class="company-cell">
|
||
<span class="company-name">{{ scope.row.company || '-' }}</span>
|
||
<span class="company-scale">企业规模:{{ scope.row.enterprise_type_name || '-' }}</span>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="咨询渠道" min-width="120" align="center">
|
||
<template slot-scope="scope">
|
||
<span :class="['source-tag', getSourceClass(scope.row.source)]">
|
||
{{ scope.row.source || '-' }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="consult_direction_name" label="咨询方向" min-width="220" show-overflow-tooltip />
|
||
<el-table-column prop="content" label="需求描述" min-width="220" show-overflow-tooltip />
|
||
<el-table-column prop="update_time" label="提交时间" min-width="160" />
|
||
<el-table-column label="回复状态" min-width="110" align="center">
|
||
<template slot-scope="scope">
|
||
<el-tag
|
||
size="mini"
|
||
effect="plain"
|
||
class="feedback-tag"
|
||
:type="feedbackTagType(scope.row.feedback)"
|
||
@click="toggleFeedback(scope.row)"
|
||
>
|
||
{{ feedbackText(scope.row) }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="110" align="center" fixed="right">
|
||
<template slot-scope="scope">
|
||
<el-button type="text" size="small" @click="viewUser(scope.row)">详情</el-button>
|
||
<el-button type="text" size="small" text="warning" @click="openRemark(scope.row)">备注</el-button>
|
||
<!-- <el-button type="text" size="small" class="danger-text" @click="deleteRows([scope.row])">删除</el-button> -->
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<div class="pager-wrap">
|
||
<div class="pager-info">显示 {{ pageStart }}-{{ pageEnd }} 条,共 {{ totalCount }} 条</div>
|
||
<el-pagination
|
||
background
|
||
layout="prev, pager, next"
|
||
:total="totalCount"
|
||
:page-size="pageSize"
|
||
:current-page.sync="page"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<el-dialog
|
||
title="咨询详情"
|
||
:visible.sync="detailVisible"
|
||
width="600px"
|
||
|
||
append-to-body
|
||
custom-class="detail-dialog"
|
||
top="8vh"
|
||
>
|
||
<div v-if="currentRow" class="detail-panel">
|
||
<div class="detail-grid">
|
||
<div class="detail-item">
|
||
<span class="detail-label">姓名</span>
|
||
<strong>{{ currentRow.name || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">联系电话</span>
|
||
<strong>{{ currentRow.phone || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">邮箱</span>
|
||
<strong>{{ currentRow.email || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">公司名称</span>
|
||
<strong>{{ currentRow.company || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">企业类型</span>
|
||
<strong>{{ currentRow.enterprise_type_name || currentRow.custom_type_name || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">咨询渠道</span>
|
||
<strong>{{ currentRow.source || '-' }}</strong>
|
||
</div>
|
||
<div class="detail-item">
|
||
<span class="detail-label">提交时间</span>
|
||
<strong>{{ currentRow.update_time || currentRow.create_at || '-' }}</strong>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<span class="detail-label">咨询方向</span>
|
||
<strong>{{ currentRow.consult_direction_name || '-' }}</strong>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<span class="detail-label">需求描述/留言</span>
|
||
<div class="detail-content-box">{{ currentRow.content || '-' }}</div>
|
||
</div>
|
||
|
||
<div class="detail-divider"></div>
|
||
|
||
<div class="detail-section">
|
||
<span class="detail-label">回复状态</span>
|
||
<el-tag size="small" effect="plain" :type="feedbackTagType(currentRow.feedback)">
|
||
{{ feedbackText(currentRow) }}
|
||
</el-tag>
|
||
</div>
|
||
|
||
<div class="detail-section">
|
||
<span class="detail-label">备注信息</span>
|
||
<div class="detail-content-box detail-remark-text">{{ currentRow.remark || '暂无备注' }}</div>
|
||
<div class="detail-remark-row">
|
||
<el-input
|
||
v-model.trim="detailRemarkText"
|
||
maxlength="300"
|
||
placeholder="添加备注..."
|
||
@keyup.enter.native="saveDetailRemark"
|
||
/>
|
||
<el-button type="primary" class="detail-save-btn" :loading="actionLoading" @click="saveDetailRemark">
|
||
保存
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog
|
||
title="添加备注"
|
||
:visible.sync="remarkVisible"
|
||
width="520px"
|
||
append-to-body
|
||
custom-class="remark-dialog"
|
||
:close-on-click-modal="true"
|
||
@close="saveRemarkOnClose"
|
||
>
|
||
<div class="remark-content">
|
||
<label class="remark-label">备注内容</label>
|
||
<el-input
|
||
v-model.trim="remarkText"
|
||
type="textarea"
|
||
:rows="6"
|
||
maxlength="300"
|
||
show-word-limit
|
||
placeholder="请输入备注信息..."
|
||
/>
|
||
<p class="remark-tip">点击弹窗外任意位置或关闭弹窗,将自动保存备注。</p>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { reqSearchUserInquiry, reqUserInquiryDelete, reqUserInquiryStatusSwitch } from '@/api/ncmatch'
|
||
import XLSX from 'xlsx'
|
||
|
||
export default {
|
||
name: 'ConsultingMangement',
|
||
data() {
|
||
return {
|
||
tableData: [],
|
||
tableLoading: false,
|
||
exportLoading: false,
|
||
actionLoading: false,
|
||
page: 1,
|
||
pageSize: 10,
|
||
totalCount: 0,
|
||
selectedRows: [],
|
||
detailVisible: false,
|
||
remarkVisible: false,
|
||
remarkText: '',
|
||
detailRemarkText: '',
|
||
originalRemarkText: '',
|
||
currentRow: null,
|
||
sourceList: [],
|
||
queryForm: {
|
||
name: '',
|
||
phone: '',
|
||
email: '',
|
||
source: '',
|
||
feedback: ''
|
||
},
|
||
feedbackOptions: [
|
||
{ id: 0, name: '待回复' },
|
||
{ id: 1, name: '沟通中' },
|
||
{ id: 2, name: '已关闭' },
|
||
{ id: 3, name: '号码错误' }
|
||
]
|
||
}
|
||
},
|
||
computed: {
|
||
pageStart() {
|
||
if (!this.tableData.length) return 0
|
||
return (this.page - 1) * this.pageSize + 1
|
||
},
|
||
pageEnd() {
|
||
if (!this.tableData.length) return 0
|
||
return (this.page - 1) * this.pageSize + this.tableData.length
|
||
},
|
||
wechatCount() {
|
||
return this.tableData.filter(item => /微信|云宝/.test(String(item.source || ''))).length
|
||
},
|
||
webCount() {
|
||
return this.tableData.filter(item => !/微信|云宝/.test(String(item.source || ''))).length
|
||
},
|
||
pendingCount() {
|
||
return this.tableData.filter(item => String(item.feedback) === '0').length
|
||
}
|
||
},
|
||
created() {
|
||
this.getTableData('0')
|
||
},
|
||
methods: {
|
||
formatCount(value) {
|
||
return Number(value || 0).toLocaleString('en-US')
|
||
},
|
||
feedbackText(row) {
|
||
if (row.feedback_name) return row.feedback_name
|
||
const found = this.feedbackOptions.find(item => String(item.id) === String(row.feedback))
|
||
return found ? found.name : '待回复'
|
||
},
|
||
feedbackTagType(feedback) {
|
||
const value = String(feedback)
|
||
if (value === '2') return 'success'
|
||
if (value === '1') return ''
|
||
if (value === '3') return 'info'
|
||
return 'warning'
|
||
},
|
||
getSourceClass(source) {
|
||
const value = String(source || '')
|
||
if (value.includes('公众号')) return 'source-tag-green'
|
||
if (value.includes('官网')) return 'source-tag-blue'
|
||
return 'source-tag-gray'
|
||
},
|
||
getRowId(row) {
|
||
return row && (row.id || row.inquiry_id || row.user_inquiry_id)
|
||
},
|
||
buildIds(rows) {
|
||
return JSON.stringify(rows.map(row => this.getRowId(row)).filter(Boolean))
|
||
},
|
||
getRowNo(index) {
|
||
return (this.page - 1) * this.pageSize + index + 1
|
||
},
|
||
buildSearchParams(to_excel) {
|
||
return {
|
||
url_link: window.location.href.split('#')[0] || window.location.href,
|
||
to_excel: String(to_excel),
|
||
page: String(this.page),
|
||
page_size: String(this.pageSize),
|
||
name: (this.queryForm.name || '').trim(),
|
||
phone: (this.queryForm.phone || '').trim(),
|
||
email: (this.queryForm.email || '').trim(),
|
||
source: this.queryForm.source || '',
|
||
feedback: this.queryForm.feedback === null || this.queryForm.feedback === undefined
|
||
? ''
|
||
: String(this.queryForm.feedback)
|
||
}
|
||
},
|
||
extractRows(res) {
|
||
const data = (res && res.data) || {}
|
||
if (Array.isArray(res && res.data)) return res.data
|
||
if (Array.isArray(data.list)) return data.list
|
||
if (Array.isArray(data.data)) return data.data
|
||
if (Array.isArray(data.rows)) return data.rows
|
||
if (Array.isArray(data.records)) return data.records
|
||
return []
|
||
},
|
||
extractTotal(res, listLength) {
|
||
const data = (res && res.data) || {}
|
||
const total = Number(
|
||
data.total_count ||
|
||
data.total ||
|
||
data.count ||
|
||
data.totalCount ||
|
||
res.total_count ||
|
||
res.total ||
|
||
res.count
|
||
)
|
||
return Number.isFinite(total) && total >= 0 ? total : listLength
|
||
},
|
||
extractSourceList(res, rows = []) {
|
||
const data = (res && res.data) || {}
|
||
const fromApi = data.source_list || data.sourceList || res.source_list || res.sourceList
|
||
const apiList = Array.isArray(fromApi) ? fromApi : []
|
||
const rowList = rows.map(item => item.source)
|
||
return [...new Set(
|
||
[...this.sourceList, ...apiList, ...rowList]
|
||
.map(item => String(item || '').trim())
|
||
.filter(Boolean)
|
||
)]
|
||
},
|
||
getTableData(to_excel) {
|
||
const params = this.buildSearchParams(to_excel)
|
||
if (to_excel === '0') this.tableLoading = true
|
||
if (to_excel === '1') this.exportLoading = true
|
||
|
||
reqSearchUserInquiry(params).then(res => {
|
||
if (!res || !res.status) {
|
||
this.$message.warning((res && res.msg) || '暂无咨询数据')
|
||
return
|
||
}
|
||
|
||
const rows = this.extractRows(res)
|
||
|
||
if (to_excel === '0') {
|
||
this.tableData = rows
|
||
this.totalCount = this.extractTotal(res, rows.length)
|
||
this.sourceList = this.extractSourceList(res, rows)
|
||
this.selectedRows = []
|
||
return
|
||
}
|
||
|
||
if (!rows.length) {
|
||
this.$message.warning('暂无可导出的数据')
|
||
return
|
||
}
|
||
|
||
const wb = XLSX.utils.book_new()
|
||
const ws1 = XLSX.utils.json_to_sheet(rows)
|
||
XLSX.utils.book_append_sheet(wb, ws1, 'sheet1')
|
||
XLSX.writeFile(wb, '咨询列表.xlsx')
|
||
this.$message.success('导出成功')
|
||
}).catch(() => {
|
||
this.$message.error('咨询列表加载失败,请稍后重试')
|
||
}).finally(() => {
|
||
this.tableLoading = false
|
||
this.exportLoading = false
|
||
})
|
||
},
|
||
handleSearch() {
|
||
this.page = 1
|
||
this.getTableData('0')
|
||
},
|
||
resetSearch() {
|
||
this.queryForm = {
|
||
name: '',
|
||
phone: '',
|
||
email: '',
|
||
source: '',
|
||
feedback: ''
|
||
}
|
||
this.page = 1
|
||
this.getTableData('0')
|
||
},
|
||
handleCurrentChange(page) {
|
||
this.page = page
|
||
this.getTableData('0')
|
||
},
|
||
handleSelectionChange(rows) {
|
||
this.selectedRows = rows
|
||
},
|
||
async updateInquiryStatus(rows, feedback, remark) {
|
||
const ids = this.buildIds(rows)
|
||
if (!ids || ids === '[]') {
|
||
this.$message.warning('请选择有效数据')
|
||
return false
|
||
}
|
||
|
||
const params = {
|
||
ids,
|
||
feedback: String(feedback)
|
||
}
|
||
if (remark !== undefined) params.remark = remark
|
||
|
||
this.actionLoading = true
|
||
try {
|
||
const res = await reqUserInquiryStatusSwitch(params)
|
||
if (res && res.status) {
|
||
this.$message.success('操作成功')
|
||
this.getTableData('0')
|
||
return true
|
||
}
|
||
this.$message.error((res && res.msg) || '操作失败')
|
||
return false
|
||
} catch (error) {
|
||
this.$message.error('操作失败,请稍后重试')
|
||
return false
|
||
} finally {
|
||
this.actionLoading = false
|
||
}
|
||
},
|
||
toggleFeedback(row) {
|
||
const nextFeedback = String(row.feedback) === '0' ? '1' : '0'
|
||
this.updateInquiryStatus([row], nextFeedback)
|
||
},
|
||
batchUpdateFeedback(feedback) {
|
||
this.updateInquiryStatus(this.selectedRows, feedback)
|
||
},
|
||
async deleteRows(rows) {
|
||
const ids = this.buildIds(rows)
|
||
if (!ids || ids === '[]') {
|
||
this.$message.warning('请选择有效数据')
|
||
return
|
||
}
|
||
|
||
try {
|
||
await this.$confirm('确认删除选中的咨询记录吗?', '提示', {
|
||
confirmButtonText: '确认',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
})
|
||
} catch (error) {
|
||
return
|
||
}
|
||
|
||
this.actionLoading = true
|
||
try {
|
||
const res = await reqUserInquiryDelete({ ids })
|
||
if (res && res.status) {
|
||
this.$message.success('删除成功')
|
||
this.getTableData('0')
|
||
return
|
||
}
|
||
this.$message.error((res && res.msg) || '删除失败')
|
||
} catch (error) {
|
||
this.$message.error('删除失败,请稍后重试')
|
||
} finally {
|
||
this.actionLoading = false
|
||
}
|
||
},
|
||
batchDelete() {
|
||
this.deleteRows(this.selectedRows)
|
||
},
|
||
viewUser(row) {
|
||
this.currentRow = row
|
||
this.detailRemarkText = row.remark || ''
|
||
this.detailVisible = true
|
||
},
|
||
openRemark(row) {
|
||
this.currentRow = row
|
||
this.remarkText = row.remark || ''
|
||
this.originalRemarkText = this.remarkText
|
||
this.remarkVisible = true
|
||
},
|
||
saveRemarkOnClose() {
|
||
if (!this.currentRow) return
|
||
if (this.remarkText === this.originalRemarkText) return
|
||
|
||
this.updateInquiryStatus(
|
||
[this.currentRow],
|
||
this.currentRow.feedback === undefined || this.currentRow.feedback === null ? '0' : this.currentRow.feedback,
|
||
this.remarkText
|
||
)
|
||
},
|
||
async saveDetailRemark() {
|
||
if (!this.currentRow) return
|
||
const success = await this.updateInquiryStatus(
|
||
[this.currentRow],
|
||
this.currentRow.feedback === undefined || this.currentRow.feedback === null ? '0' : this.currentRow.feedback,
|
||
this.detailRemarkText
|
||
)
|
||
if (success) {
|
||
this.currentRow.remark = this.detailRemarkText
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-section {
|
||
min-height: calc(100vh - 84px);
|
||
background: #eef3f9;
|
||
}
|
||
|
||
.page-padding {
|
||
padding: 24px;
|
||
}
|
||
|
||
.title-wrap {
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.page-title {
|
||
margin: 0;
|
||
color: #1f2937;
|
||
font-size: 30px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.stats-card {
|
||
background: #fff;
|
||
border: 1px solid #edf0f5;
|
||
border-radius: 14px;
|
||
padding: 16px;
|
||
}
|
||
|
||
.stats-label {
|
||
margin: 0;
|
||
color: #6b7280;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.stats-value {
|
||
margin: 6px 0 0;
|
||
font-size: 34px;
|
||
line-height: 1;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.stats-value-dark {
|
||
color: #1f2937;
|
||
}
|
||
|
||
.stats-value-green {
|
||
color: #16a34a;
|
||
}
|
||
|
||
.stats-value-purple {
|
||
color: #9333ea;
|
||
}
|
||
|
||
.stats-value-orange {
|
||
color: #ea580c;
|
||
}
|
||
|
||
.filter-card {
|
||
background: #fff;
|
||
border: 1px solid #edf0f5;
|
||
border-radius: 14px;
|
||
padding: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.filter-form {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.filter-form ::v-deep .el-form-item {
|
||
margin-right: 14px;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.filter-form ::v-deep .el-form-item__label {
|
||
color: #4b5563;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.filter-form ::v-deep .el-input,
|
||
.filter-form ::v-deep .el-select {
|
||
width: 180px;
|
||
}
|
||
|
||
.filter-form ::v-deep .el-input__inner {
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.filter-form ::v-deep .el-button {
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.action-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.batch-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.batch-actions ::v-deep .el-button + .el-button {
|
||
margin-left: 0;
|
||
}
|
||
|
||
.record-count {
|
||
color: #6b7280;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.table-card {
|
||
background: #fff;
|
||
border: 1px solid #edf0f5;
|
||
border-radius: 14px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.consulting-table ::v-deep .el-table__header th {
|
||
background: #f9fafb;
|
||
color: #4b5563;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.consulting-table ::v-deep .el-table__body td {
|
||
color: #374151;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.consulting-table ::v-deep .el-table__body tr:hover > td {
|
||
background: #f9fafb;
|
||
}
|
||
|
||
.company-cell {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.company-name {
|
||
color: #1f2937;
|
||
font-weight: 600;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.company-scale {
|
||
color: #8a94a6;
|
||
font-size: 12px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.source-tag {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-width: 52px;
|
||
height: 24px;
|
||
padding: 0 10px;
|
||
border-radius: 999px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
line-height: 24px;
|
||
}
|
||
|
||
.source-tag-green {
|
||
color: #15803d;
|
||
background: #dcfce7;
|
||
}
|
||
|
||
.source-tag-blue {
|
||
color: #1d4ed8;
|
||
background: #dbeafe;
|
||
}
|
||
|
||
.source-tag-gray {
|
||
color: #64748b;
|
||
background: #f1f5f9;
|
||
}
|
||
|
||
.feedback-tag {
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
|
||
.danger-text {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
::v-deep .detail-dialog {
|
||
border-radius: 24px;
|
||
overflow: hidden;
|
||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
|
||
}
|
||
|
||
::v-deep .detail-dialog .el-dialog__header {
|
||
padding: 28px 34px 22px;
|
||
border-bottom: 1px solid #eef2f7;
|
||
}
|
||
|
||
::v-deep .detail-dialog .el-dialog__title {
|
||
color: #111827;
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
::v-deep .detail-dialog .el-dialog__headerbtn {
|
||
top: 30px;
|
||
right: 34px;
|
||
font-size: 22px;
|
||
}
|
||
|
||
::v-deep .detail-dialog .el-dialog__body {
|
||
padding: 28px 34px 30px;
|
||
}
|
||
|
||
.detail-panel {
|
||
color: #111827;
|
||
}
|
||
|
||
.detail-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 28px 72px;
|
||
}
|
||
|
||
.detail-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.detail-label {
|
||
display: block;
|
||
margin-bottom: 8px;
|
||
color: #8a94a6;
|
||
font-size: 14px;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.detail-item strong,
|
||
.detail-section strong {
|
||
color: #111827;
|
||
font-size: 16px;
|
||
line-height: 1.5;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.detail-section {
|
||
margin-top: 28px;
|
||
}
|
||
|
||
.detail-content-box {
|
||
min-height: 42px;
|
||
padding: 14px 16px;
|
||
border-radius: 8px;
|
||
background: #f8fafc;
|
||
color: #1f2937;
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.detail-remark-text {
|
||
color: #d97706;
|
||
}
|
||
|
||
.detail-divider {
|
||
height: 1px;
|
||
margin: 24px 0;
|
||
background: #edf1f7;
|
||
}
|
||
|
||
.detail-remark-row {
|
||
margin-top: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.detail-remark-row ::v-deep .el-input__inner {
|
||
height: 42px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.detail-save-btn {
|
||
width: 72px;
|
||
height: 42px;
|
||
border: 0;
|
||
border-radius: 8px;
|
||
background: #9333ea;
|
||
font-weight: 600;
|
||
}
|
||
|
||
::v-deep .remark-dialog {
|
||
border-radius: 24px;
|
||
overflow: hidden;
|
||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
|
||
}
|
||
|
||
::v-deep .remark-dialog .el-dialog__header {
|
||
padding: 28px 34px 22px;
|
||
border-bottom: 1px solid #eef2f7;
|
||
}
|
||
|
||
::v-deep .remark-dialog .el-dialog__title {
|
||
color: #111827;
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
::v-deep .remark-dialog .el-dialog__headerbtn {
|
||
top: 30px;
|
||
right: 34px;
|
||
font-size: 22px;
|
||
}
|
||
|
||
::v-deep .remark-dialog .el-dialog__body {
|
||
padding: 28px 34px 30px;
|
||
}
|
||
|
||
.remark-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.remark-label {
|
||
margin-bottom: 12px;
|
||
color: #1f2937;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.remark-content ::v-deep .el-textarea__inner {
|
||
min-height: 150px !important;
|
||
padding: 16px 18px;
|
||
border: 1px solid #dfe6f0;
|
||
border-radius: 12px;
|
||
color: #111827;
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
resize: vertical;
|
||
}
|
||
|
||
.remark-content ::v-deep .el-textarea__inner::placeholder {
|
||
color: #a0aec0;
|
||
}
|
||
|
||
.remark-content ::v-deep .el-input__count {
|
||
right: 14px;
|
||
bottom: 10px;
|
||
color: #9ca3af;
|
||
background: transparent;
|
||
}
|
||
|
||
.remark-tip {
|
||
margin: 12px 0 0;
|
||
color: #8a94a6;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.pager-wrap {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.pager-info {
|
||
color: #6b7280;
|
||
font-size: 13px;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.stats-grid {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.page-padding {
|
||
padding: 12px;
|
||
}
|
||
|
||
.stats-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.pager-wrap {
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
align-items: flex-start;
|
||
}
|
||
}
|
||
</style> |