<template>
|
<div class="satisfaction-exception-config">
|
<!-- 页面标题 -->
|
<div class="page-header">
|
<div class="header-content">
|
<h2 class="page-title">满意度题目异常处理配置</h2>
|
<p class="page-description">
|
为满意度题目配置责任科室和报备科室,优化异常反馈流程
|
</p>
|
</div>
|
</div>
|
|
<!-- 搜索区域 -->
|
<div class="search-card">
|
<el-card shadow="never" class="search-container">
|
<el-form :model="queryParams" :inline="true" size="medium">
|
<el-form-item label="问题主题">
|
<el-input
|
v-model="queryParams.scriptTopic"
|
placeholder="请输入问题主题"
|
clearable
|
@keyup.enter.native="handleQuery"
|
/>
|
</el-form-item>
|
<el-form-item label="问题内容">
|
<el-input
|
v-model="queryParams.scriptContent"
|
placeholder="请输入问题内容"
|
clearable
|
@keyup.enter.native="handleQuery"
|
/>
|
</el-form-item>
|
<el-form-item label="是否可用">
|
<el-select
|
v-model="queryParams.isavailable"
|
placeholder="请选择"
|
clearable
|
>
|
<el-option
|
v-for="item in qyoptions"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button
|
type="primary"
|
icon="el-icon-search"
|
@click="handleQuery"
|
>
|
搜索
|
</el-button>
|
<el-button icon="el-icon-refresh" @click="resetQuery">
|
重置
|
</el-button>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
</div>
|
|
<!-- 配置列表 -->
|
<div class="config-content">
|
<!-- 批量操作栏 -->
|
<div v-if="questionList.length > 0" class="batch-actions-card">
|
<el-card shadow="never">
|
<div class="batch-actions">
|
<el-button
|
type="success"
|
icon="el-icon-check"
|
:loading="batchSaving"
|
:disabled="!hasChanges || batchSaving"
|
@click="handleBatchSave"
|
size="medium"
|
>
|
{{ batchSaving ? "批量保存中..." : "批量保存配置" }}
|
</el-button>
|
<span v-if="changedCount > 0" class="change-count">
|
有 {{ changedCount }} 项配置需要保存
|
</span>
|
<div class="total-count">共 {{ total }} 条记录</div>
|
</div>
|
</el-card>
|
</div>
|
|
<div v-if="loading" class="loading-wrapper">
|
<div class="loading-spinner">
|
<i class="el-icon-loading"></i>
|
<span>加载中...</span>
|
</div>
|
</div>
|
|
<div v-else-if="questionList.length === 0" class="empty-wrapper">
|
<el-empty description="暂无满意度题目数据">
|
<el-button type="primary" @click="getQuestionList"
|
>刷新数据</el-button
|
>
|
</el-empty>
|
</div>
|
|
<!-- 一行一行的卡片列表 -->
|
<div v-else class="question-list">
|
<div
|
v-for="(question, index) in questionList"
|
:key="question.id"
|
class="question-item"
|
>
|
<el-card
|
shadow="hover"
|
class="question-card"
|
:class="{ 'has-changes': question.hasChanges }"
|
>
|
<!-- 卡片头部 -->
|
<div class="card-header">
|
<div class="header-left">
|
<div class="question-index">
|
<span class="index-number">{{ index + 1 }}</span>
|
<div class="index-line"></div>
|
</div>
|
<div class="question-basic-info">
|
<div class="question-title-section">
|
<h3 class="question-topic" :title="question.scriptTopic">
|
{{ question.scriptTopic || "无主题" }}
|
</h3>
|
<div class="question-tags">
|
<el-tag
|
:type="question.isavailable == 1 ? 'danger' : 'success'"
|
size="small"
|
>
|
{{ question.isavailable == 1 ? "不可用" : "可用" }}
|
</el-tag>
|
<dict-tag
|
:options="askvaluetype"
|
:value="question.scriptType"
|
size="small"
|
/>
|
<el-tag
|
v-if="question.targetname"
|
size="small"
|
type="info"
|
>
|
{{ question.targetname }}
|
</el-tag>
|
</div>
|
</div>
|
<div class="question-content-section">
|
<span class="content-label">题目内容:</span>
|
<span class="content-text">{{
|
question.scriptContent
|
}}</span>
|
</div>
|
</div>
|
</div>
|
<div class="header-right">
|
<el-button
|
type="text"
|
icon="el-icon-view"
|
@click="previewQuestion(question)"
|
size="small"
|
>
|
预览
|
</el-button>
|
</div>
|
</div>
|
|
<!-- 异常处理配置 -->
|
<div class="config-section">
|
<div class="config-title">
|
<i class="el-icon-setting"></i>
|
<span>异常处理配置</span>
|
</div>
|
|
<el-form
|
:model="question.exceptionConfig"
|
:rules="configRules"
|
ref="configForm"
|
label-width="100px"
|
size="small"
|
class="config-form"
|
>
|
<div class="config-fields">
|
<!-- 责任科室 -->
|
<div class="config-field">
|
<el-form-item
|
label="责任科室"
|
prop="responsibilityDept"
|
class="config-item"
|
>
|
<el-select
|
v-model="question.exceptionConfig.responsibilityDept"
|
placeholder="请选择责任科室"
|
filterable
|
clearable
|
style="width: 100%"
|
@change="handleConfigChange(question)"
|
>
|
<el-option
|
v-for="dept in deptOptions"
|
:key="dept.id"
|
:label="dept.name"
|
:value="dept.id"
|
/>
|
</el-select>
|
<div class="config-tip">负责处理该题目反馈的科室</div>
|
</el-form-item>
|
</div>
|
|
<!-- 报备科室 -->
|
<div class="config-field">
|
<el-form-item
|
label="报备科室"
|
prop="reportDept"
|
class="config-item"
|
>
|
<el-select
|
v-model="question.exceptionConfig.reportDept"
|
placeholder="请选择报备科室"
|
filterable
|
clearable
|
multiple
|
collapse-tags
|
style="width: 100%"
|
@change="handleConfigChange(question)"
|
>
|
<el-option
|
v-for="dept in deptOptions"
|
:key="dept.id"
|
:label="dept.name"
|
:value="dept.id"
|
/>
|
</el-select>
|
<div class="config-tip">
|
需要接收异常反馈的科室,可多选
|
</div>
|
</el-form-item>
|
</div>
|
|
<!-- 通知方式 -->
|
<div class="config-field">
|
<el-form-item
|
label="通知方式"
|
prop="notifyTypes"
|
class="config-item"
|
>
|
<el-checkbox-group
|
v-model="question.exceptionConfig.notifyTypes"
|
@change="handleConfigChange(question)"
|
>
|
<el-checkbox label="system">系统消息</el-checkbox>
|
<el-checkbox label="sms">短信</el-checkbox>
|
<el-checkbox label="email">邮件</el-checkbox>
|
<el-checkbox label="wechat">企业微信</el-checkbox>
|
</el-checkbox-group>
|
</el-form-item>
|
</div>
|
</div>
|
|
<!-- 配置状态和操作按钮 -->
|
<div class="config-footer">
|
<div v-if="question.saveStatus" class="save-status">
|
<el-alert
|
:type="question.saveStatus.type"
|
:title="question.saveStatus.message"
|
:closable="false"
|
show-icon
|
:effect="
|
question.saveStatus.type === 'success'
|
? 'dark'
|
: 'light'
|
"
|
size="small"
|
/>
|
</div>
|
|
<div class="config-actions">
|
<el-button
|
type="primary"
|
:loading="question.saving"
|
:disabled="!question.hasChanges"
|
@click="saveSingleConfig(question)"
|
size="small"
|
icon="el-icon-check"
|
>
|
{{ question.saving ? "保存中..." : "保存配置" }}
|
</el-button>
|
<el-button
|
v-if="question.hasChanges"
|
type="text"
|
@click="resetSingleConfig(question)"
|
size="small"
|
>
|
重置
|
</el-button>
|
</div>
|
</div>
|
</el-form>
|
</div>
|
</el-card>
|
</div>
|
</div>
|
|
<!-- 分页 -->
|
<div v-if="questionList.length > 0" class="pagination-wrapper">
|
<pagination
|
v-show="total > 0"
|
:total="total"
|
:page.sync="queryParams.pageNum"
|
:limit.sync="queryParams.pageSize"
|
@pagination="getQuestionList"
|
/>
|
</div>
|
</div>
|
|
<!-- 题目预览对话框 -->
|
<el-dialog
|
title="题目预览"
|
:visible.sync="previewVisible"
|
width="600px"
|
center
|
>
|
<div v-if="currentPreview" class="preview-wrapper">
|
<div class="preview-header">
|
<h4>{{ currentPreview.scriptTopic || "无主题" }}</h4>
|
<div class="preview-tags">
|
<dict-tag
|
:options="askvaluetype"
|
:value="currentPreview.scriptType"
|
size="small"
|
/>
|
<el-tag
|
:type="currentPreview.isavailable === 1 ? 'success' : 'danger'"
|
size="small"
|
>
|
{{ currentPreview.isavailable === 1 ? "可用" : "不可用" }}
|
</el-tag>
|
<el-tag v-if="currentPreview.targetname" size="small" type="info">
|
{{ currentPreview.targetname }}
|
</el-tag>
|
</div>
|
</div>
|
|
<div class="preview-content">
|
<p class="preview-question">{{ currentPreview.scriptContent }}</p>
|
|
<div
|
v-if="
|
currentPreview.scriptType != 3 && currentPreview.scriptType != 4
|
"
|
class="preview-options"
|
>
|
<el-radio-group v-model="previewAnswer">
|
<el-radio
|
v-for="(option, idx) in currentPreview.svyLibScriptOptions ||
|
[]"
|
:key="idx"
|
:label="option.optioncontent"
|
class="option-item"
|
>
|
{{ option.optioncontent }}
|
</el-radio>
|
</el-radio-group>
|
</div>
|
|
<div v-else class="preview-textarea">
|
<el-input
|
type="textarea"
|
placeholder="请输入回答"
|
v-model="previewAnswer"
|
:rows="4"
|
/>
|
</div>
|
</div>
|
</div>
|
<span slot="footer" class="dialog-footer">
|
<el-button @click="previewVisible = false">关闭</el-button>
|
</span>
|
</el-dialog>
|
|
<!-- 保存成功提示 -->
|
<el-dialog
|
title="保存成功"
|
:visible.sync="saveSuccessVisible"
|
width="400px"
|
center
|
>
|
<div class="success-content">
|
<i class="el-icon-success success-icon"></i>
|
<p class="success-text">配置已成功保存!</p>
|
</div>
|
<span slot="footer" class="dialog-footer">
|
<el-button type="primary" @click="saveSuccessVisible = false"
|
>确定</el-button
|
>
|
</span>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
import {
|
getissuelist,
|
compileissue,
|
getissueclassify,
|
} from "@/api/AiCentre/index";
|
import store from "@/store";
|
import Pagination from "@/components/Pagination";
|
|
export default {
|
name: "SatisfactionExceptionConfig",
|
components: { Pagination },
|
data() {
|
return {
|
// 查询参数
|
queryParams: {
|
pageNum: 1,
|
pageSize: 10,
|
scriptTopic: "",
|
scriptContent: "",
|
targetname: "",
|
isavailable: "",
|
categoryids: "404,405,406", // 固定查询满意度类型
|
},
|
|
// 数据列表
|
questionList: [],
|
total: 0,
|
loading: false,
|
batchSaving: false,
|
|
// 字典数据
|
askvaluetype: store.getters.askvaluetype || [],
|
qyoptions: store.getters.usable || [],
|
mode: store.getters.mode || [],
|
languagelist: store.getters.languagelist || [],
|
|
// 科室选项
|
deptOptions: [],
|
|
// 预览相关
|
previewVisible: false,
|
currentPreview: null,
|
previewAnswer: "",
|
|
// 保存相关
|
saveSuccessVisible: false,
|
hasChanges: false,
|
changedCount: 0,
|
|
// 表单验证规则
|
configRules: {
|
responsibilityDept: [
|
{ required: true, message: "请选择责任科室", trigger: "change" },
|
],
|
reportDept: [
|
{
|
required: true,
|
message: "请选择至少一个报备科室",
|
trigger: "change",
|
},
|
{
|
validator: (rule, value, callback) => {
|
if (!value || value.length === 0) {
|
callback(new Error("请选择至少一个报备科室"));
|
} else {
|
callback();
|
}
|
},
|
trigger: "change",
|
},
|
],
|
notifyTypes: [
|
{
|
validator: (rule, value, callback) => {
|
if (!value || value.length === 0) {
|
callback(new Error("请至少选择一种通知方式"));
|
} else {
|
callback();
|
}
|
},
|
trigger: "change",
|
},
|
],
|
},
|
};
|
},
|
created() {
|
this.getDeptOptions();
|
this.getQuestionList();
|
},
|
methods: {
|
/** 查询科室列表 */
|
getDeptOptions() {
|
getissueclassify({})
|
.then((res) => {
|
if (res.code === 200) {
|
this.deptOptions = res.rows || [];
|
}
|
})
|
.catch((error) => {
|
console.error("获取科室列表失败:", error);
|
this.$message.error("获取科室列表失败");
|
});
|
},
|
|
/** 查询满意度题目列表 */
|
getQuestionList() {
|
this.loading = true;
|
this.questionList = [];
|
|
getissuelist(this.queryParams)
|
.then((res) => {
|
this.loading = false;
|
if (res.code === 200) {
|
this.questionList = (res.rows || []).map((item) => {
|
// 解析异常处理配置
|
let exceptionConfig = {
|
responsibilityDept: "",
|
reportDept: [],
|
notifyTypes: ["system"],
|
};
|
|
try {
|
if (item.otherdata) {
|
const otherData = JSON.parse(item.otherdata);
|
if (otherData.exceptionConfig) {
|
exceptionConfig = {
|
...exceptionConfig,
|
...otherData.exceptionConfig,
|
};
|
}
|
}
|
} catch (error) {
|
console.warn("解析异常配置失败:", error);
|
}
|
|
return {
|
...item,
|
originalConfig: JSON.parse(JSON.stringify(exceptionConfig)),
|
exceptionConfig: exceptionConfig,
|
hasChanges: false,
|
saving: false,
|
saveStatus: null,
|
};
|
});
|
|
this.total = res.total || 0;
|
this.updateChangedStatus();
|
} else {
|
this.$message.error(res.msg || "获取数据失败");
|
}
|
})
|
.catch((error) => {
|
this.loading = false;
|
console.error("查询失败:", error);
|
this.$message.error("获取数据失败");
|
});
|
},
|
|
/** 配置变更处理 */
|
handleConfigChange(question) {
|
this.$nextTick(() => {
|
const index = this.questionList.findIndex((q) => q.id === question.id);
|
if (index !== -1) {
|
const formRef = this.$refs.configForm && this.$refs.configForm[index];
|
if (formRef) {
|
formRef.validate((valid) => {
|
if (valid) {
|
question.hasChanges = !this.isConfigEqual(
|
question.exceptionConfig,
|
question.originalConfig
|
);
|
this.updateChangedStatus();
|
}
|
});
|
}
|
}
|
});
|
},
|
|
/** 比较配置是否改变 */
|
isConfigEqual(config1, config2) {
|
if (!config1 || !config2) return false;
|
|
const report1 = [...(config1.reportDept || [])].sort().join(",");
|
const report2 = [...(config2.reportDept || [])].sort().join(",");
|
const notify1 = [...(config1.notifyTypes || [])].sort().join(",");
|
const notify2 = [...(config2.notifyTypes || [])].sort().join(",");
|
|
return (
|
config1.responsibilityDept === config2.responsibilityDept &&
|
report1 === report2 &&
|
notify1 === notify2
|
);
|
},
|
|
/** 更新变更状态 */
|
updateChangedStatus() {
|
const changedItems = this.questionList.filter((q) => q.hasChanges);
|
this.changedCount = changedItems.length;
|
this.hasChanges = changedItems.length > 0;
|
},
|
|
/** 保存单个题目配置 */
|
async saveSingleConfig(question) {
|
if (!question.hasChanges) return;
|
|
const index = this.questionList.findIndex((q) => q.id === question.id);
|
if (index === -1) return;
|
|
const formRef = this.$refs.configForm && this.$refs.configForm[index];
|
if (!formRef) return;
|
|
const valid = await formRef.validate();
|
if (!valid) {
|
this.$message.warning("请先完成必填项");
|
return;
|
}
|
|
question.saving = true;
|
question.saveStatus = null;
|
|
try {
|
// 构建保存数据
|
const saveData = {
|
id: question.id,
|
isoperation: 2, // 修改操作
|
...question,
|
};
|
|
// 将异常配置保存到 otherdata
|
const otherData = JSON.parse(question.otherdata || "{}");
|
otherData.exceptionConfig = question.exceptionConfig;
|
saveData.otherdata = JSON.stringify(otherData);
|
|
// 移除不需要的字段
|
delete saveData.originalConfig;
|
delete saveData.hasChanges;
|
delete saveData.saving;
|
delete saveData.saveStatus;
|
delete saveData.exceptionConfig;
|
|
const response = await compileissue(saveData);
|
|
if (response.code === 200) {
|
// 更新原始配置
|
question.originalConfig = JSON.parse(
|
JSON.stringify(question.exceptionConfig)
|
);
|
question.hasChanges = false;
|
question.saveStatus = {
|
type: "success",
|
message: "配置保存成功",
|
};
|
|
this.updateChangedStatus();
|
this.$message.success("配置保存成功");
|
|
// 5秒后清除成功提示
|
setTimeout(() => {
|
question.saveStatus = null;
|
}, 5000);
|
} else {
|
question.saveStatus = {
|
type: "error",
|
message: response.msg || "保存失败",
|
};
|
this.$message.error(response.msg || "保存失败");
|
}
|
} catch (error) {
|
console.error("保存失败:", error);
|
question.saveStatus = {
|
type: "error",
|
message: "保存失败,请稍后重试",
|
};
|
this.$message.error("保存失败,请稍后重试");
|
} finally {
|
question.saving = false;
|
}
|
},
|
|
/** 重置单个题目配置 */
|
resetSingleConfig(question) {
|
this.$confirm("确定要重置当前题目的配置吗?", "提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(() => {
|
question.exceptionConfig = JSON.parse(
|
JSON.stringify(question.originalConfig)
|
);
|
question.hasChanges = false;
|
question.saveStatus = null;
|
this.updateChangedStatus();
|
this.$message.success("配置已重置");
|
})
|
.catch(() => {});
|
},
|
|
/** 批量保存配置 */
|
async handleBatchSave() {
|
if (!this.hasChanges || this.batchSaving) return;
|
|
this.$confirm("确定要保存所有修改过的配置吗?", "批量保存", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning",
|
})
|
.then(async () => {
|
this.batchSaving = true;
|
|
const changedQuestions = this.questionList.filter(
|
(q) => q.hasChanges
|
);
|
const results = [];
|
|
for (const question of changedQuestions) {
|
try {
|
await this.saveSingleConfig(question);
|
results.push({
|
id: question.id,
|
success:
|
!question.hasChanges &&
|
question.saveStatus?.type === "success",
|
});
|
} catch (error) {
|
results.push({
|
id: question.id,
|
success: false,
|
});
|
}
|
}
|
|
this.batchSaving = false;
|
|
const successCount = results.filter((r) => r.success).length;
|
const failCount = results.length - successCount;
|
|
if (failCount === 0) {
|
this.saveSuccessVisible = true;
|
this.$message.success(`成功保存 ${successCount} 个配置`);
|
} else {
|
this.$message.warning(
|
`成功保存 ${successCount} 个,失败 ${failCount} 个`
|
);
|
}
|
})
|
.catch(() => {
|
this.batchSaving = false;
|
});
|
},
|
|
/** 预览题目 */
|
previewQuestion(question) {
|
this.currentPreview = { ...question };
|
this.previewAnswer = "";
|
this.previewVisible = true;
|
},
|
|
/** 搜索 */
|
handleQuery() {
|
this.queryParams.pageNum = 1;
|
this.getQuestionList();
|
},
|
|
/** 重置搜索 */
|
resetQuery() {
|
this.queryParams = {
|
pageNum: 1,
|
pageSize: 10,
|
scriptTopic: "",
|
scriptContent: "",
|
targetname: "",
|
isavailable: "",
|
categoryids: "404,405,406",
|
};
|
this.getQuestionList();
|
},
|
},
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
.satisfaction-exception-config {
|
min-height: 100%;
|
background-color: #f5f7fa;
|
padding: 20px;
|
|
.page-header {
|
margin-bottom: 20px;
|
padding: 20px;
|
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
|
border-radius: 8px;
|
color: white;
|
|
.header-content {
|
.page-title {
|
margin: 0 0 8px 0;
|
font-size: 20px;
|
font-weight: 600;
|
}
|
|
.page-description {
|
margin: 0;
|
opacity: 0.9;
|
font-size: 14px;
|
}
|
}
|
}
|
|
.search-card {
|
margin-bottom: 20px;
|
|
.search-container {
|
border-radius: 8px;
|
|
.el-form {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 16px;
|
align-items: center;
|
}
|
}
|
}
|
|
.config-content {
|
.batch-actions-card {
|
margin-bottom: 20px;
|
|
.batch-actions {
|
display: flex;
|
align-items: center;
|
gap: 20px;
|
padding: 8px 0;
|
|
.change-count {
|
color: #e6a23c;
|
font-size: 14px;
|
font-weight: 500;
|
}
|
|
.total-count {
|
margin-left: auto;
|
color: #909399;
|
font-size: 14px;
|
}
|
}
|
}
|
|
.loading-wrapper {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
min-height: 400px;
|
|
.loading-spinner {
|
text-align: center;
|
color: #409eff;
|
|
i {
|
font-size: 24px;
|
margin-right: 8px;
|
}
|
|
span {
|
font-size: 16px;
|
}
|
}
|
}
|
|
.empty-wrapper {
|
min-height: 400px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
.question-list {
|
display: flex;
|
flex-direction: column;
|
gap: 16px;
|
}
|
|
.question-item {
|
.question-card {
|
border-radius: 8px;
|
border: 1px solid #ebeef5;
|
transition: all 0.3s ease;
|
|
&.has-changes {
|
border-color: #409eff;
|
box-shadow: 0 2px 12px 0 rgba(64, 158, 255, 0.1);
|
}
|
|
&:hover {
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
}
|
|
.card-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: flex-start;
|
margin-bottom: 20px;
|
padding-bottom: 20px;
|
border-bottom: 1px solid #f0f0f0;
|
|
.header-left {
|
display: flex;
|
gap: 20px;
|
flex: 1;
|
|
.question-index {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
min-width: 40px;
|
|
.index-number {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
width: 32px;
|
height: 32px;
|
background: #409eff;
|
color: white;
|
border-radius: 50%;
|
font-size: 14px;
|
font-weight: 600;
|
margin-bottom: 8px;
|
}
|
|
.index-line {
|
width: 2px;
|
height: 100%;
|
background: #e0e0e0;
|
border-radius: 1px;
|
}
|
}
|
|
.question-basic-info {
|
flex: 1;
|
|
.question-title-section {
|
margin-bottom: 12px;
|
|
.question-topic {
|
margin: 0 0 8px 0;
|
font-size: 16px;
|
font-weight: 600;
|
color: #303133;
|
line-height: 1.4;
|
}
|
|
.question-tags {
|
display: flex;
|
gap: 8px;
|
flex-wrap: wrap;
|
}
|
}
|
|
.question-content-section {
|
display: flex;
|
align-items: flex-start;
|
gap: 8px;
|
|
.content-label {
|
color: #606266;
|
font-size: 13px;
|
font-weight: 500;
|
min-width: 80px;
|
}
|
|
.content-text {
|
color: #303133;
|
font-size: 13px;
|
line-height: 1.6;
|
flex: 1;
|
}
|
}
|
}
|
}
|
|
.header-right {
|
flex-shrink: 0;
|
}
|
}
|
|
.config-section {
|
.config-title {
|
display: flex;
|
align-items: center;
|
gap: 8px;
|
margin-bottom: 20px;
|
padding: 8px 12px;
|
background: #f8f9fa;
|
border-radius: 4px;
|
|
i {
|
color: #409eff;
|
font-size: 16px;
|
}
|
|
span {
|
color: #303133;
|
font-weight: 600;
|
font-size: 14px;
|
}
|
}
|
|
.config-form {
|
.config-fields {
|
display: grid;
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
gap: 20px;
|
margin-bottom: 20px;
|
|
.config-field {
|
.config-item {
|
margin-bottom: 0;
|
|
:deep(.el-form-item__label) {
|
font-weight: 500;
|
color: #606266;
|
padding-right: 12px;
|
}
|
|
.config-tip {
|
font-size: 12px;
|
color: #909399;
|
margin-top: 4px;
|
line-height: 1.4;
|
}
|
}
|
}
|
}
|
|
.config-footer {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding-top: 20px;
|
border-top: 1px dashed #dcdfe6;
|
|
.save-status {
|
flex: 1;
|
margin-right: 20px;
|
|
.el-alert {
|
padding: 8px 16px;
|
border-radius: 4px;
|
}
|
}
|
|
.config-actions {
|
display: flex;
|
align-items: center;
|
gap: 12px;
|
flex-shrink: 0;
|
|
.el-button {
|
min-width: 100px;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
.pagination-wrapper {
|
margin-top: 20px;
|
padding: 20px;
|
background: white;
|
border-radius: 8px;
|
display: flex;
|
justify-content: center;
|
}
|
}
|
|
.preview-wrapper {
|
.preview-header {
|
margin-bottom: 20px;
|
|
h4 {
|
margin: 0 0 12px 0;
|
color: #303133;
|
font-size: 18px;
|
font-weight: 600;
|
}
|
|
.preview-tags {
|
display: flex;
|
gap: 8px;
|
flex-wrap: wrap;
|
}
|
}
|
|
.preview-content {
|
.preview-question {
|
margin-bottom: 20px;
|
padding: 16px;
|
background: #f8f9fa;
|
border-radius: 4px;
|
color: #606266;
|
line-height: 1.6;
|
}
|
|
.preview-options {
|
.option-item {
|
display: block;
|
margin-bottom: 12px;
|
padding: 12px;
|
border-radius: 4px;
|
border: 1px solid #ebeef5;
|
transition: all 0.3s;
|
|
&:hover {
|
background: #f5f7fa;
|
border-color: #409eff;
|
}
|
|
&:last-child {
|
margin-bottom: 0;
|
}
|
}
|
}
|
|
.preview-textarea {
|
.el-textarea__inner {
|
resize: none;
|
}
|
}
|
}
|
}
|
|
.success-content {
|
text-align: center;
|
padding: 20px 0;
|
|
.success-icon {
|
color: #67c23a;
|
font-size: 48px;
|
margin-bottom: 20px;
|
}
|
|
.success-text {
|
font-size: 16px;
|
color: #606266;
|
margin: 0;
|
}
|
}
|
}
|
|
@media (max-width: 768px) {
|
.satisfaction-exception-config {
|
padding: 12px;
|
|
.page-header {
|
padding: 16px;
|
margin-bottom: 16px;
|
}
|
|
.search-card {
|
margin-bottom: 16px;
|
}
|
|
.config-content {
|
.batch-actions-card {
|
margin-bottom: 16px;
|
}
|
|
.question-item {
|
.question-card {
|
.card-header {
|
flex-direction: column;
|
gap: 12px;
|
|
.header-left {
|
flex-direction: column;
|
gap: 12px;
|
|
.question-index {
|
flex-direction: row;
|
align-items: center;
|
min-width: auto;
|
|
.index-number {
|
margin-bottom: 0;
|
margin-right: 12px;
|
}
|
|
.index-line {
|
width: 100%;
|
height: 2px;
|
}
|
}
|
}
|
}
|
|
.config-section {
|
.config-form {
|
.config-fields {
|
grid-template-columns: 1fr;
|
gap: 16px;
|
}
|
|
.config-footer {
|
flex-direction: column;
|
align-items: stretch;
|
gap: 12px;
|
|
.save-status {
|
margin-right: 0;
|
margin-bottom: 8px;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|
|
<style lang="scss">
|
.config-form {
|
.el-checkbox-group {
|
display: flex;
|
flex-wrap: wrap;
|
gap: 12px;
|
}
|
|
.el-checkbox {
|
margin: 0;
|
}
|
}
|
|
.option-item {
|
.el-radio__label {
|
display: block;
|
padding-left: 8px;
|
}
|
}
|
</style>
|