This commit is contained in:
faiz 2024-08-09 15:06:54 +08:00
parent 9a51d08428
commit ea5813bea7
2 changed files with 329 additions and 242 deletions

View File

@ -3,9 +3,19 @@
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<div class="problem_form"> <div class="problem_form">
<el-form :inline="true" ref="form" :model="dataForm" label-width="60px"> <el-form
:inline="true"
ref="form"
:model="dataForm"
label-width="60px"
>
<el-form-item label="关键字:"> <el-form-item label="关键字:">
<el-input v-model="dataForm.keyword" placeholder="请输入搜索关键字" style="width: 400px;" class="filter-item" /> <el-input
v-model="dataForm.keyword"
placeholder="请输入搜索关键字"
style="width: 400px"
class="filter-item"
/>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="success" @click="onSubmit">查询</el-button> <el-button type="success" @click="onSubmit">查询</el-button>
@ -15,26 +25,58 @@
</el-col> </el-col>
</el-row> </el-row>
<div class="problem_container"> <div class="problem_container">
<div class="problem_left" v-infinite-scroll="load" :infinite-scroll-immediate="false" style="overflow:auto;padding: 10px;"> <div
<div @click="handleQacityl(item.city_id)" class="btn" v-for="item in getQaCityList">{{ item.city_name }}</div> class="problem_left"
v-infinite-scroll="load"
:infinite-scroll-immediate="false"
style="overflow: auto; padding: 10px"
>
<div
@click="handleQacityl(item.city_id)"
class="btn"
v-for="item in getQaCityList"
>
{{ item.city_name }}
</div>
</div> </div>
<div class="problem_right"> <div class="problem_right">
<ul class="infinite-list" v-infinite-scroll="load" :infinite-scroll-immediate="false" style="overflow:auto"> <ul
class="infinite-list"
v-infinite-scroll="load"
:infinite-scroll-immediate="false"
style="overflow: auto"
>
<li class="problem_right_container" v-for="item in getQaLists"> <li class="problem_right_container" v-for="item in getQaLists">
<div class="title"> <div class="title">
<span v-html="handleprant(item.title)"></span> <span v-html="handleprant(item.title)"></span>
<!-- <el-button @click="handleZip(item.img_zip)" type="primary">下载图片</el-button> <!-- <el-button @click="handleZip(item.img_zip)" type="primary">下载图片</el-button>
<el-button @click="handleZip(item.trip_zip)" type="primary">下载行程</el-button> --> <el-button @click="handleZip(item.trip_zip)" type="primary">下载行程</el-button> -->
<el-button @click="showImgDialog(item.img_zip)" type="primary">下载图片</el-button> <el-button @click="showImgDialog(item.img_zip)" type="primary"
<el-button @click="showFileList(item.trip_zip)" type="primary" style="margin-left: 10px;">下载行程</el-button> >下载图片</el-button
>
<el-button
@click="showFileList(item.trip_zip)"
type="primary"
style="margin-left: 10px"
>下载行程</el-button
>
</div> </div>
<div class="desc_container" v-for="list in item.qaQuestions"> <div class="desc_container" v-for="list in item.qaQuestions">
<span style="font-weight: 700;color: #46a6ff;" class="desc" v-html="handleprant(list.title)"> <span
style="font-weight: 700; color: #46a6ff"
class="desc"
v-html="handleprant(list.title)"
>
</span> </span>
<el-button @click="copyToClipboard(list.content)" type="primary" size="mini" style="margin-left: 10px;">复制</el-button> <el-button
@click="copyToClipboard(list.content)"
type="primary"
size="mini"
style="margin-left: 10px"
>复制</el-button
>
<div class="desc" v-html="handleprantHtml(list.content)"> <div class="desc" v-html="handleprantHtml(list.content)"></div>
</div>
</div> </div>
</li> </li>
</ul> </ul>
@ -50,10 +92,18 @@
class="image-card" class="image-card"
:body-style="{ padding: '10px' }" :body-style="{ padding: '10px' }"
> >
<img :src="image.url" class="image-preview" /> <div style="text-align: center">{{ image.desc }}</div>
<img :src="image.file" class="image-preview" />
<div class="image-footer"> <div class="image-footer">
<el-button @click="handlePreview(image.url)" size="mini">查看</el-button> <el-button @click="handlePreview(image.file)" size="mini"
<el-button @click="handleDownload(image.url)" type="success" size="mini">下载</el-button> >查看</el-button
>
<el-button
@click="handleDownload(image.file)"
type="success"
size="mini"
>下载</el-button
>
</div> </div>
</el-card> </el-card>
</div> </div>
@ -74,12 +124,17 @@
> >
<div class="file-info"> <div class="file-info">
<el-icon class="file-icon"> <el-icon class="file-icon">
<i :class="getFileIcon(file.url)"></i> <i :class="getFileIcon(file.file)"></i>
</el-icon> </el-icon>
<span class="file-name">{{ file.name }}</span> <span class="file-name">{{ file.desc }}</span>
</div> </div>
<div class="file-footer"> <div class="file-footer">
<el-button @click="handleDownload(file.url)" type="success" size="mini">下载</el-button> <el-button
@click="handleDownload(file.file)"
type="success"
size="mini"
>下载</el-button
>
</div> </div>
</el-card> </el-card>
</div> </div>
@ -99,7 +154,7 @@
</template> </template>
<script> <script>
import { getQaCityList, getQaList } from '@/api/qa' import { getQaCityList, getQaList } from "@/api/qa";
export default { export default {
data() { data() {
@ -107,110 +162,115 @@ export default {
getQaCityList: [], getQaCityList: [],
getQaLists: [], getQaLists: [],
dataForm: { dataForm: {
keyword: '', keyword: "",
city_id: '' city_id: "",
}, },
dialogImage: false, // dialogImage: false, //
previewVisible: false, // previewVisible: false, //
previewImageUrl: '', // URL previewImageUrl: "", // URL
previewTitle: '', // previewTitle: "", //
imageList: [ // imageList: [
//
], ],
fileList: [ // fileList: [
//
], ],
dialogFile: false, dialogFile: false,
} };
}, },
created() { created() {
getQaCityList().then(res => { getQaCityList().then((res) => {
this.getQaCityList = res.data this.getQaCityList = res.data;
}) });
}, },
watch: { watch: {
'dataForm.keyword': function (newVal) { "dataForm.keyword": function (newVal) {
if (newVal) { if (newVal) {
this.onSubmit(); this.onSubmit();
} }
} },
}, },
methods: { methods: {
// //
showFileList(fileUrl) { showFileList(fileUrl) {
this.fileList = []; if (fileUrl.length) {
if (fileUrl) { this.fileList = fileUrl;
this.fileList = fileUrl.split(',').map(url => ({ url, name: url.split('/').pop() }));
} }
this.dialogFile = true; this.dialogFile = true;
}, },
// URL // URL
getFileIcon(url) { getFileIcon(url) {
const ext = url.split('.').pop().toLowerCase(); const ext = url.split(".").pop().toLowerCase();
console.log(ext);
switch (ext) { switch (ext) {
case 'pdf': case "pdf":
return 'el-icon-file-pdf'; return "el-icon-file-pdf";
case 'docx': case "docx":
return 'el-icon-file-word'; return "el-icon-file-word";
case 'pptx': case "pptx":
return 'el-icon-file-ppt'; return "el-icon-file-ppt";
case 'xlsx': case "xlsx":
return 'el-icon-file-excel'; return "el-icon-file-excel";
default: default:
return 'el-icon-file'; return "el-icon-file";
} }
}, },
handleQacityl(val) { handleQacityl(val) {
getQaList({ city_id: val }).then(res => { getQaList({ city_id: val }).then((res) => {
this.getQaLists = res.data.data this.getQaLists = res.data.data;
}) });
}, },
handleZip(url) { handleZip(url) {
if (url) { if (url) {
// window.open(url) // window.open(url)
fetch(url) fetch(url)
.then(response => response.blob()) .then((response) => response.blob())
.then(blob => { .then((blob) => {
const link = document.createElement('a'); const link = document.createElement("a");
const objectUrl = URL.createObjectURL(blob); const objectUrl = URL.createObjectURL(blob);
link.href = objectUrl; link.href = objectUrl;
link.download = url.split('/').pop(); // Extract filename from URL link.download = url.split("/").pop(); // Extract filename from URL
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
URL.revokeObjectURL(objectUrl); URL.revokeObjectURL(objectUrl);
}) })
.catch(error => { .catch((error) => {
this.$message({ this.$message({
showClose: true, showClose: true,
message: '下载失败', message: "下载失败",
type: 'error' type: "error",
}); });
console.error('Download error:', error); console.error("Download error:", error);
}); });
} else { } else {
this.$message({ this.$message({
showClose: true, showClose: true,
message: '暂无下载链接', message: "暂无下载链接",
type: 'warning' type: "warning",
}); });
} }
}, },
load() { load() {
console.log('load') console.log("load");
}, },
handleprant(val) { handleprant(val) {
if (!val) return ''; // undefined if (!val) return ""; // undefined
let replaceReg = new RegExp(this.dataForm.keyword, "ig"); let replaceReg = new RegExp(this.dataForm.keyword, "ig");
let replaceString = `<span style="color: #fff;background-color: #FC0421FF;">${this.dataForm.keyword}</span>`; let replaceString = `<span style="color: #fff;background-color: #FC0421FF;">${this.dataForm.keyword}</span>`;
return val.replace(replaceReg, replaceString); return val.replace(replaceReg, replaceString);
}, },
handleprantHtml(val) { handleprantHtml(val) {
if (!val) return ''; if (!val) return "";
let p = this.dataForm.keyword; let p = this.dataForm.keyword;
let regexp = new RegExp(p, "g"); let regexp = new RegExp(p, "g");
let replacedHtml = val.replace(/(?<=>)[^>]+(?=<[/]?\w+.*>)/g, (v) => { let replacedHtml = val.replace(/(?<=>)[^>]+(?=<[/]?\w+.*>)/g, (v) => {
return v.replace(regexp, `<span style='color: #fff;background-color: #FC0421FF;'>${p}</span>`); return v.replace(
regexp,
`<span style='color: #fff;background-color: #FC0421FF;'>${p}</span>`
);
}); });
// //
if (replacedHtml === val) { if (replacedHtml === val) {
@ -220,32 +280,31 @@ export default {
return replacedHtml; return replacedHtml;
}, },
onSubmit() { onSubmit() {
getQaList(this.dataForm).then(res => { getQaList(this.dataForm).then((res) => {
this.getQaLists = res.data.data this.getQaLists = res.data.data;
}) });
}, },
copyToClipboard(html) { copyToClipboard(html) {
const text = this.stripHtml(html); const text = this.stripHtml(html);
const input = document.createElement('textarea'); const input = document.createElement("textarea");
input.value = text; input.value = text;
document.body.appendChild(input); document.body.appendChild(input);
input.select(); input.select();
document.execCommand('copy'); document.execCommand("copy");
document.body.removeChild(input); document.body.removeChild(input);
this.$message({ this.$message({
showClose: true, showClose: true,
message: '内容已复制' message: "内容已复制",
}); });
}, },
stripHtml(html) { stripHtml(html) {
const div = document.createElement('div'); const div = document.createElement("div");
div.innerHTML = html; div.innerHTML = html;
return div.textContent || div.innerText || ''; return div.textContent || div.innerText || "";
}, },
showImgDialog(imagesUrls) { showImgDialog(imagesUrls) {
this.imageList = [] if (imagesUrls.length) {
if (imagesUrls) { this.imageList = imagesUrls;
this.imageList = imagesUrls.split(',').map(url => ({ url }));
} }
this.dialogImage = true; this.dialogImage = true;
@ -253,7 +312,7 @@ export default {
// //
handlePreview(url) { handlePreview(url) {
this.previewImageUrl = url; this.previewImageUrl = url;
this.previewTitle = '图片预览'; this.previewTitle = "图片预览";
this.previewVisible = true; this.previewVisible = true;
}, },
// //
@ -265,35 +324,35 @@ export default {
if (url) { if (url) {
// window.open(url) // window.open(url)
fetch(url) fetch(url)
.then(response => response.blob()) .then((response) => response.blob())
.then(blob => { .then((blob) => {
const link = document.createElement('a'); const link = document.createElement("a");
const objectUrl = URL.createObjectURL(blob); const objectUrl = URL.createObjectURL(blob);
link.href = objectUrl; link.href = objectUrl;
link.download = url.split('/').pop(); // Extract filename from URL link.download = url.split("/").pop(); // Extract filename from URL
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
document.body.removeChild(link); document.body.removeChild(link);
URL.revokeObjectURL(objectUrl); URL.revokeObjectURL(objectUrl);
}) })
.catch(error => { .catch((error) => {
this.$message({ this.$message({
showClose: true, showClose: true,
message: '下载失败', message: "下载失败",
type: 'error' type: "error",
}); });
console.error('Download error:', error); console.error("Download error:", error);
}); });
} else { } else {
this.$message({ this.$message({
showClose: true, showClose: true,
message: '暂无下载链接', message: "暂无下载链接",
type: 'warning' type: "warning",
}); });
} }
} },
} },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -365,7 +424,7 @@ body {
font-weight: 600; font-weight: 600;
margin-bottom: 10px; margin-bottom: 10px;
color: #46a6ff; color: #46a6ff;
&>:nth-child(1) { & > :nth-child(1) {
margin-right: 40px; margin-right: 40px;
} }
} }

View File

@ -96,169 +96,185 @@
@pagination="getList" @pagination="getList"
/> />
<el-dialog :title="title" :visible.sync="dialogCreate"> <el-dialog
<el-button v-if="dialogCreate"
class="filter-items" ref="dialog"
v-loading="loading" :title="title"
type="primary" :visible.sync="dialogCreate"
@click="onSave" >
> </el-button <div
style="display: flex; justify-content: flex-end; margin-bottom: 10px"
> >
<el-form ref="addForm" label-width="120px" :model="anchors"> <el-button v-loading="loading" type="primary" @click="onSave"
<el-form-item label="城市" prop="city_id"> > </el-button
<el-select v-model="anchors.city_id" placeholder="请选择"> >
<el-form-item </div>
style="display: inline-flex; text-align: left; width: 770px" <el-scrollbar ref="scrollbar" class="scrollable-container">
<el-form ref="addForm" label-width="120px" :model="anchors">
<el-form-item label="城市" prop="city_id">
<el-select v-model="anchors.city_id" placeholder="请选择">
<el-form-item
style="display: inline-flex; text-align: left; width: 770px"
>
<el-option
v-for="item in getQaCitys"
:key="item.city_id"
style="display: inline-flex; word-break: break-all"
:label="item.city_name"
:value="item.city_id"
/>
</el-form-item>
</el-select>
</el-form-item>
<el-form-item label="旅游路线" prop="title">
<el-input
v-model="anchors.title"
type="text"
placeholder="请输入旅游路线"
/>
</el-form-item>
<el-form-item label="QA内容">
<div
class="mistake-content"
v-for="(item, index) in anchors.qaQuestions"
> >
<el-option <div class="mistake-left">
v-for="item in getQaCitys" <div>副标题</div>
:key="item.city_id" <div class="qa-desc">
style="display: inline-flex; word-break: break-all" <el-input
:label="item.city_name" style="width: 100px; margin-right: 10px"
:value="item.city_id" v-model="item.sort"
/> type="text"
</el-form-item> placeholder="序号"
</el-select> />
</el-form-item> <el-input
<el-form-item label="旅游路线" prop="title"> v-model="item.title"
<el-input type="text"
v-model="anchors.title" placeholder="请输入副标题"
type="text" />
placeholder="请输入旅游路线" </div>
/> <div>内容</div>
</el-form-item> <div style="border: 1px solid #ccc">
<el-form-item label="QA内容"> <myEditor v-model="item.content" />
</div>
</div>
<div class="mistake-right">
<el-button @click="handleDel(index)" type="danger"
>删除</el-button
>
</div>
</div>
<div class="mistake-btn">
<el-button type="primary" @click="handleAdd">添加</el-button>
</div>
</el-form-item>
<el-form-item label="状态">
<el-switch
v-model="anchors.status"
:active-value="1"
:inactive-value="0"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<div <div
class="mistake-content" style="
v-for="(item, index) in anchors.qaQuestions" display: flex;
justify-content: flex-end;
margin-bottom: 10px;
"
> >
<div class="mistake-left"> <el-button type="primary" @click="onAddImg()">添加图片</el-button>
<div>副标题</div> </div>
<div class="qa-desc"> <el-form-item label="上传图片">
<el-input <div class="upload-list">
style="width: 100px; margin-right: 10px" <div class="wu-yu" v-for="(item, index) in anchors.img_zip">
v-model="item.sort" <i
type="text" @click.stop="handleClose('img_zip', index)"
placeholder="序号" class="close el-icon-close"
/> />
<el-input <el-upload
v-model="item.title" class="avatar-uploader"
type="text" action=""
placeholder="请输入副标题" :show-file-list="false"
/> :http-request="handlesAvatarSuccess"
</div> :on-success="
<div>内容</div> (response, file, fileList) =>
<div style="border: 1px solid #ccc"> handleAvatarSuccess(response, file, fileList, index)
<myEditor v-model="item.content" /> "
>
<div v-if="!!item.file" class="img-box">
<i
v-if="!checkIfUrlContainsImage(item.file)"
class="el-icon-folder"
/>
<img
v-else
style="width: 100px; height: 100px"
:src="item.file"
class="avatar"
alt=""
/>
<div class="desc">{{ handleRegex(item.file) }}</div>
</div>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-input v-model="item.desc" placeholder="图片说明"></el-input>
</div> </div>
</div> </div>
<div class="mistake-right"> <div style="color: red">(请上传.jpg, png的图片)</div>
<el-button @click="handleDel(index)" type="danger" </el-form-item>
>删除</el-button <div
> style="
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
"
>
<el-button type="primary" @click="onAddtrip()">添加行程</el-button>
</div>
<el-form-item label="上传行程">
<div class="upload-list">
<div class="wu-yu" v-for="(item, index) in anchors.trip_zip">
<i
@click.stop="handleClose('trip_zip', index)"
class="close el-icon-close"
/>
<el-upload
class="avatar-uploader"
action=""
:http-request="handlesAvatarSuccess"
:show-file-list="false"
:on-success="
(response, file, fileList) =>
handleSuccess(response, file, fileList, index)
"
>
<div v-if="!!item.file" class="img-box">
<i
v-if="!checkIfUrlContainsImage(item.file)"
class="el-icon-folder"
/>
<img
v-else
style="width: 100px; height: 100px"
:src="item.file"
class="avatar"
alt=""
/>
<div class="desc">{{ handleRegex(item.file) }}</div>
</div>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
<el-input v-model="item.desc" placeholder="行程说明"></el-input>
</div>
</div> </div>
</div> <span style="color: red"
<div class="mistake-btn"> >(本行程请上传,ppt,word,pdf格式的文件)</span
<el-button type="primary" @click="handleAdd">添加</el-button> >
</div> </el-form-item>
</el-form-item> </el-form>
<el-form-item label="状态"> </el-scrollbar>
<el-switch
v-model="anchors.status"
:active-value="1"
:inactive-value="0"
active-color="#13ce66"
inactive-color="#ff4949"
/>
</el-form-item>
<div
style="display: flex; justify-content: flex-end; margin-bottom: 10px"
>
<el-button type="primary" @click="onAddImg()">添加图片</el-button>
</div>
<el-form-item label="上传图片">
<div class="upload-list">
<div class="wu-yu" v-for="(item, index) in anchors.img_zip">
<i
@click.stop="handleClose('img_zip', index)"
class="close el-icon-close"
/>
<el-input v-model="item.desc" placeholder="图片说明"></el-input>
<el-upload
class="avatar-uploader"
action=""
:show-file-list="false"
:http-request="handlesAvatarSuccess"
:on-success="
(response, file, fileList) =>
handleAvatarSuccess(response, file, fileList, index)
"
>
<div v-if="!!item.file" class="img-box">
<i
v-if="!checkIfUrlContainsImage(item.file)"
class="el-icon-folder"
/>
<img
v-else
style="width: 100px; height: 100px"
:src="item.file"
class="avatar"
alt=""
/>
<div class="desc">{{ handleRegex(item.file) }}</div>
</div>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
</div>
</div>
<div style="color: red">(请上传.jpg, png的图片)</div>
</el-form-item>
<div
style="display: flex; justify-content: flex-end; margin-bottom: 10px"
>
<el-button type="primary" @click="onAddtrip()">添加行程</el-button>
</div>
<el-form-item label="上传行程">
<div class="upload-list">
<div class="wu-yu" v-for="(item, index) in anchors.trip_zip">
<i
@click.stop="handleClose('trip_zip', index)"
class="close el-icon-close"
/>
<el-input v-model="item.desc" placeholder="行程说明"></el-input>
<el-upload
class="avatar-uploader"
action=""
:http-request="handlesAvatarSuccess"
:show-file-list="false"
:on-success="
(response, file, fileList) =>
handleSuccess(response, file, fileList, index)
"
>
<div v-if="!!item.file" class="img-box">
<i
v-if="!checkIfUrlContainsImage(item.file)"
class="el-icon-folder"
/>
<img
v-else
style="width: 100px; height: 100px"
:src="item.file"
class="avatar"
alt=""
/>
<div class="desc">{{ handleRegex(item.file) }}</div>
</div>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
</div>
</div>
<span style="color: red">(本行程请上传,ppt,word,pdf格式的文件)</span>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer"></div>
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
@ -524,18 +540,30 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.scrollable-container {
// position: relative;
height: 500px; /* 可以根据实际情况调整高度 */
// overflow-y: auto;
}
::v-deep.el-scrollbar .el-scrollbar__wrap {
overflow-x: hidden;
}
.upload-list { .upload-list {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.wu-yu { .wu-yu {
margin-bottom: 10px; margin-bottom: 10px;
position: relative; position: relative;
display: flex;
width: 110px;
flex-wrap: wrap;
align-content: space-between;
& + .wu-yu { & + .wu-yu {
margin-left: 5px; margin-left: 5px;
} }
::v-deep.el-input { ::v-deep.el-input {
width: 100px; width: 100px;
margin: 0 0 10px 10px; margin: 10px 0 10px 10px;
} }
} }
} }