<template>
|
<view class="client-visit-detail">
|
<PageHeader :title="detailType === 1 ? '新增知识' : (detailType === 2 ? '编辑知识' : '知识详情')"
|
@back="goBack" />
|
<view class="form-container">
|
<u-form ref="formRef"
|
:model="form"
|
label-width="90">
|
<u-cell-group title="基本信息">
|
<u-form-item label="知识标题"
|
prop="title"
|
required
|
border-bottom>
|
<u-input v-model="form.title"
|
:readonly="readonly"
|
placeholder="请输入知识标题" />
|
</u-form-item>
|
<u-form-item label="知识类型"
|
prop="type"
|
required
|
border-bottom>
|
<u-input v-model="typeName"
|
readonly
|
placeholder="请选择知识类型"
|
@click="!readonly && (showTypeSheet = true)" />
|
<template v-if="!readonly"
|
#right>
|
<up-icon name="arrow-right"
|
@click="showTypeSheet = true"></up-icon>
|
</template>
|
</u-form-item>
|
<u-form-item label="适用场景"
|
prop="scenario"
|
border-bottom>
|
<u-input v-model="form.scenario"
|
:readonly="readonly"
|
placeholder="请输入适用场景" />
|
</u-form-item>
|
<u-form-item label="解决效率"
|
prop="efficiency"
|
border-bottom>
|
<u-input v-model="efficiencyName"
|
readonly
|
placeholder="请选择解决效率"
|
@click="!readonly && (showEfficiencySheet = true)" />
|
<template v-if="!readonly"
|
#right>
|
<up-icon name="arrow-right"
|
@click="showEfficiencySheet = true"></up-icon>
|
</template>
|
</u-form-item>
|
</u-cell-group>
|
|
<u-cell-group title="详细内容">
|
<u-form-item label="问题描述"
|
required
|
prop="problem"
|
border-bottom>
|
<u-textarea v-model="form.problem"
|
rows="4"
|
:disabled="readonly"
|
placeholder="请输入问题描述" />
|
</u-form-item>
|
<u-form-item label="解决方案"
|
prop="solution"
|
required
|
border-bottom>
|
<u-textarea v-model="form.solution"
|
rows="4"
|
:disabled="readonly"
|
placeholder="请输入解决方案" />
|
</u-form-item>
|
<u-form-item label="关键要点"
|
prop="keyPoints"
|
border-bottom>
|
<u-textarea v-model="form.keyPoints"
|
rows="4"
|
:disabled="readonly"
|
placeholder="请输入关键要点,用逗号分隔" />
|
</u-form-item>
|
</u-cell-group>
|
|
<u-cell-group title="其他信息">
|
<u-form-item label="创建人"
|
prop="creator"
|
border-bottom>
|
<u-input v-model="form.creator"
|
readonly
|
placeholder="请选择创建人"
|
@click="!readonly && (showCreatorSheet = true)" />
|
<template v-if="!readonly"
|
#right>
|
<up-icon name="arrow-right"
|
@click="showCreatorSheet = true"></up-icon>
|
</template>
|
</u-form-item>
|
<u-form-item label="使用次数"
|
prop="usageCount"
|
border-bottom>
|
<uni-number-box v-model="form.usageCount"
|
:min="0"
|
:disabled="readonly" />
|
</u-form-item>
|
</u-cell-group>
|
|
<u-cell-group title="附件材料">
|
<view class="upload-section">
|
<view class="upload-tip" v-if="!readonly">
|
支持文档(doc, docx, xls, xlsx, pdf, txt)和图片(jpg, jpeg, png, gif)格式
|
</view>
|
<view class="file-list" v-if="form.commonFileList && form.commonFileList.length > 0">
|
<view v-for="(file, index) in form.commonFileList" :key="index" class="file-item">
|
<up-icon name="file-text" size="20" color="#667eea"></up-icon>
|
<text class="file-name" @click="previewFile(file)">{{ file.name || file.fileName }}</text>
|
<up-icon v-if="!readonly" name="close-circle-fill" size="18" color="#ff4d4f" @click="handleRemoveFile(index)"></up-icon>
|
</view>
|
</view>
|
<view v-if="!readonly" class="upload-btn-container">
|
<up-upload :fileList="fileList"
|
@afterRead="afterRead"
|
@delete="deleteFile"
|
multiple
|
:maxCount="10"
|
:previewImage="true">
|
<view class="custom-upload-btn">
|
<up-icon name="plus" size="24" color="#999"></up-icon>
|
<text>添加附件</text>
|
</view>
|
</up-upload>
|
</view>
|
</view>
|
</u-cell-group>
|
</u-form>
|
|
<!-- 提交按钮 -->
|
<view v-if="!readonly"
|
class="footer-btns">
|
<u-button class="cancel-btn"
|
@click="goBack">取消</u-button>
|
<u-button class="sign-btn"
|
type="primary"
|
@click="handleSubmit"
|
:loading="loading">保存</u-button>
|
</view>
|
</view>
|
|
<!-- 选择器 -->
|
<up-action-sheet :show="showTypeSheet"
|
:actions="typeOptions"
|
title="请选择知识类型"
|
@select="onTypeSelect"
|
@close="showTypeSheet = false" />
|
<up-action-sheet :show="showEfficiencySheet"
|
:actions="efficiencyOptions"
|
title="请选择解决效率"
|
@select="onEfficiencySelect"
|
@close="showEfficiencySheet = false" />
|
<up-action-sheet :show="showCreatorSheet"
|
:actions="creatorOptions"
|
title="请选择创建人"
|
@select="onCreatorSelect"
|
@close="showCreatorSheet = false" />
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, onMounted, computed } from "vue";
|
import { onLoad } from "@dcloudio/uni-app";
|
import PageHeader from "@/components/PageHeader.vue";
|
import useUserStore from "@/store/modules/user";
|
import { useDict } from "@/utils/dict";
|
import {
|
addKnowledgeBase,
|
updateKnowledgeBase,
|
} from "@/api/managementMeetings/knowledgeBase";
|
import { userListNoPageByTenantId } from "@/api/system/user";
|
import upload from "@/utils/upload";
|
|
defineOptions({ name: "knowledge-base-detail" });
|
|
const showToast = message => {
|
uni.showToast({
|
title: message,
|
icon: "none",
|
});
|
};
|
|
const userStore = useUserStore();
|
|
// 页面状态
|
const detailType = ref(1); // 1-新增, 2-编辑, 3-详情
|
const knowledgeId = ref("");
|
const readonly = ref(false);
|
const loading = ref(false);
|
const formRef = ref(null);
|
|
// 表单数据
|
const form = ref({
|
title: "",
|
type: "",
|
scenario: "",
|
efficiency: "",
|
problem: "",
|
solution: "",
|
keyPoints: "",
|
creator: userStore.nickName || "",
|
usageCount: 0,
|
tempFileIds: [],
|
commonFileList: []
|
});
|
|
// 选择器状态
|
const showTypeSheet = ref(false);
|
const showEfficiencySheet = ref(false);
|
const showCreatorSheet = ref(false);
|
|
// 数据字典
|
const { knowledge_type } = useDict("knowledge_type");
|
const typeOptions = computed(() => {
|
return (knowledge_type?.value || []).map(item => ({
|
name: item.label,
|
value: item.value
|
}));
|
});
|
|
const typeName = computed(() => {
|
const item = typeOptions.value.find(i => String(i.value) === String(form.value.type));
|
return item ? item.name : (form.value.type || "");
|
});
|
|
const efficiencyOptions = [
|
{ name: "显著提升", value: "high" },
|
{ name: "一般提升", value: "medium" },
|
{ name: "轻微提升", value: "low" }
|
];
|
|
const efficiencyName = computed(() => {
|
const item = efficiencyOptions.find(i => i.value === form.value.efficiency);
|
return item ? item.name : (form.value.efficiency || "");
|
});
|
|
const creatorOptions = ref([]);
|
|
// 文件上传相关
|
const fileList = ref([]);
|
|
// 返回上一页
|
const goBack = () => {
|
uni.navigateBack();
|
};
|
|
// 选择处理
|
const onTypeSelect = (action) => {
|
form.value.type = action.value;
|
showTypeSheet.value = false;
|
};
|
|
const onEfficiencySelect = (action) => {
|
form.value.efficiency = action.value;
|
showEfficiencySheet.value = false;
|
};
|
|
const onCreatorSelect = (action) => {
|
form.value.creator = action.name;
|
showCreatorSheet.value = false;
|
};
|
|
// 获取创建人列表
|
const getCreatorOptions = async () => {
|
try {
|
const res = await userListNoPageByTenantId();
|
if (res.code === 200) {
|
creatorOptions.value = (res.data || []).map(item => ({
|
name: item.nickName,
|
value: item.userId
|
}));
|
}
|
} catch (e) {
|
console.error("获取创建人列表失败:", e);
|
}
|
};
|
|
// 文件处理
|
const afterRead = async (event) => {
|
const { file } = event;
|
const lists = [].concat(file);
|
|
for (let i = 0; i < lists.length; i++) {
|
const item = lists[i];
|
try {
|
uni.showLoading({ title: '上传中...' });
|
const res = await upload({
|
url: '/file/upload',
|
filePath: item.url,
|
name: 'file'
|
});
|
uni.hideLoading();
|
|
if (res.code === 200) {
|
if (!form.value.tempFileIds) form.value.tempFileIds = [];
|
form.value.tempFileIds.push(res.data.tempId);
|
|
if (!form.value.commonFileList) form.value.commonFileList = [];
|
form.value.commonFileList.push({
|
id: res.data.tempId,
|
name: item.name || '未命名文件',
|
url: res.data.url
|
});
|
|
showToast('上传成功');
|
} else {
|
showToast(res.msg || '上传失败');
|
}
|
} catch (e) {
|
uni.hideLoading();
|
console.error('上传失败:', e);
|
showToast('上传失败');
|
}
|
}
|
};
|
|
const deleteFile = (event) => {
|
const { index } = event;
|
form.value.commonFileList.splice(index, 1);
|
if (form.value.tempFileIds) {
|
form.value.tempFileIds.splice(index, 1);
|
}
|
};
|
|
const handleRemoveFile = (index) => {
|
form.value.commonFileList.splice(index, 1);
|
if (form.value.tempFileIds) {
|
form.value.tempFileIds.splice(index, 1);
|
}
|
};
|
|
const previewFile = (file) => {
|
if (file.url) {
|
// 如果是图片,预览图片
|
const isImage = /\.(jpg|jpeg|png|gif)$/i.test(file.name || file.fileName || file.url);
|
if (isImage) {
|
uni.previewImage({
|
urls: [file.url]
|
});
|
} else {
|
// 其他文件尝试打开
|
uni.downloadFile({
|
url: file.url,
|
success: (res) => {
|
if (res.statusCode === 200) {
|
uni.openDocument({
|
filePath: res.tempFilePath,
|
success: () => console.log('打开文档成功')
|
});
|
}
|
}
|
});
|
}
|
}
|
};
|
|
// 提交表单
|
const handleSubmit = async () => {
|
if (!form.value.title) return showToast("请输入知识标题");
|
if (!form.value.type) return showToast("请选择知识类型");
|
if (!form.value.problem) return showToast("请输入问题描述");
|
if (!form.value.solution) return showToast("请输入解决方案");
|
|
try {
|
loading.value = true;
|
const apiCall = detailType.value === 1 ? addKnowledgeBase : updateKnowledgeBase;
|
const res = await apiCall(form.value);
|
loading.value = false;
|
|
if (res.code === 200) {
|
showToast("保存成功");
|
setTimeout(() => goBack(), 500);
|
} else {
|
showToast(res.msg || "保存失败");
|
}
|
} catch (e) {
|
loading.value = false;
|
console.error("保存失败:", e);
|
showToast("系统异常,保存失败");
|
}
|
};
|
|
onLoad(options => {
|
detailType.value = Number(options.detailType || 1);
|
knowledgeId.value = options.id || "";
|
readonly.value = detailType.value === 3;
|
|
if (detailType.value !== 1) {
|
try {
|
const cached = uni.getStorageSync("knowledgeBase");
|
if (cached) {
|
// 确保数据是对象类型
|
const data = typeof cached === 'string' ? JSON.parse(cached) : cached;
|
|
// 如果传入了 id,则校验 id 是否一致
|
if (!knowledgeId.value || String(data.id) === String(knowledgeId.value)) {
|
form.value = JSON.parse(JSON.stringify(data));
|
// 兼容处理文件列表
|
if (form.value.commonFileList) {
|
form.value.tempFileIds = form.value.commonFileList.map(f => f.id || f.tempId);
|
}
|
}
|
}
|
} catch (e) {
|
console.error("解析缓存数据失败:", e);
|
}
|
}
|
});
|
|
onMounted(() => {
|
getCreatorOptions();
|
});
|
</script>
|
|
<style scoped lang="scss">
|
@import "@/static/scss/form-common.scss";
|
|
.client-visit-detail {
|
min-height: 100vh;
|
background: #f8f9fa;
|
padding-bottom: 80px;
|
}
|
|
.form-container {
|
padding: 10px;
|
background: #fff;
|
}
|
|
.upload-section {
|
padding: 15px 0;
|
|
.section-title {
|
font-size: 14px;
|
color: #333;
|
font-weight: bold;
|
margin-bottom: 10px;
|
}
|
|
.upload-tip {
|
font-size: 12px;
|
color: #999;
|
margin-bottom: 10px;
|
}
|
|
.file-list {
|
margin-bottom: 15px;
|
|
.file-item {
|
display: flex;
|
align-items: center;
|
background: #f5f7fa;
|
padding: 8px 12px;
|
border-radius: 4px;
|
margin-bottom: 8px;
|
|
.file-name {
|
flex: 1;
|
margin: 0 10px;
|
font-size: 14px;
|
color: #667eea;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
}
|
}
|
}
|
}
|
|
.custom-upload-btn {
|
width: 80px;
|
height: 80px;
|
border: 1px dashed #d9d9d9;
|
border-radius: 4px;
|
display: flex;
|
flex-direction: column;
|
justify-content: center;
|
align-items: center;
|
background: #fafafa;
|
|
text {
|
font-size: 12px;
|
color: #999;
|
margin-top: 5px;
|
}
|
}
|
|
.footer-btns {
|
position: fixed;
|
left: 0;
|
right: 0;
|
bottom: 0;
|
background: #fff;
|
display: flex;
|
justify-content: space-around;
|
align-items: center;
|
padding: 15px 0;
|
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
z-index: 100;
|
|
.u-button {
|
width: 45%;
|
border-radius: 25px;
|
}
|
|
.sign-btn {
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
border: none;
|
}
|
}
|
</style>
|