You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

630 lines
17 KiB

3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
3 months ago
  1. <script setup>
  2. import { ref, computed, onMounted, watch, nextTick, onUnmounted } from "vue";
  3. import { useDataStore } from '@/store/dataList.js'
  4. import { addFeedbackAPI, getFeedbackAPI } from "../api/AIxiaocaishen"
  5. import feedback from "../assets/img/Feedback/feedback.png";
  6. import feedbackImg from "../assets/img/Feedback/feedbackImg.png";
  7. import feedbackSuccess from "../assets/img/Feedback/feedbackSuccess.png";
  8. import noFeedback from "../assets/img/Feedback/noFeedback.png";
  9. import border from "../assets/img/Feedback/border.png";
  10. import success from "../assets/img/Feedback/success.png";
  11. import failure from "../assets/img/Feedback/failure.png";
  12. import save from "../assets/img/Feedback/save.png";
  13. import back from "../assets/img/Feedback/back.png";
  14. import purpleDot from "../assets/img/Feedback/purpleDot.png";
  15. import moment from 'moment';
  16. const dataStore = useDataStore()
  17. const feedbackContent = ref("");
  18. const uploadUrl = import.meta.env.VITE_APP_IMG_API_BASE_URL;
  19. const feedbackFileList = ref([]);
  20. const isHistoryFeedback = ref(false);
  21. const submitSuccessDialogVisible = ref(false)
  22. const submitFailureDialogVisible = ref(false)
  23. const submitFailureContent = ref('')
  24. const feedbackSubmit = async () => {
  25. console.log(feedbackContent.value)
  26. console.log(feedbackFileList.value)
  27. if (feedbackContent.value == '' && feedbackFileList.value.length == 0) {
  28. submitFailureDialogVisible.value = true;
  29. submitFailureContent.value = '请输入反馈内容或上传图片';
  30. } else {
  31. try {
  32. let img1 = ''
  33. let img2 = ''
  34. let img3 = '';
  35. if (feedbackFileList.value[0]) {
  36. img1 = feedbackFileList.value[0].url;
  37. }
  38. if (feedbackFileList.value[1]) {
  39. img2 = feedbackFileList.value[1].url;
  40. }
  41. if (feedbackFileList.value[2]) {
  42. img3 = feedbackFileList.value[2].url;
  43. }
  44. console.log(img1, img2, img3);
  45. const result = await addFeedbackAPI({
  46. token: localStorage.getItem('localToken'),
  47. content: feedbackContent.value,
  48. image1: img1,
  49. image2: img2,
  50. image3: img3,
  51. })
  52. console.log(result)
  53. feedbackHistory();
  54. submitSuccessDialogVisible.value = true;
  55. } catch (error) {
  56. submitFailureDialogVisible.value = true;
  57. submitFailureContent.value = '反馈提交异常(错误代码:' + error.response.status + '),建议尝试更换网络环境后重新提交。';
  58. }
  59. }
  60. }
  61. const feedbackHistoryList = ref([])
  62. const feedbackHistory = async () => {
  63. try {
  64. const result = await getFeedbackAPI({
  65. token: localStorage.getItem('localToken'),
  66. })
  67. console.log(result)
  68. if (result.data.length > 0) {
  69. isHistoryFeedback.value = true;
  70. feedbackHistoryList.value = result.data;
  71. } else {
  72. isHistoryFeedback.value = false;
  73. }
  74. } catch (error) {
  75. console.log(error)
  76. }
  77. }
  78. const submitSuccessConfirm = () => {
  79. feedbackContent.value = '';
  80. feedbackFileList.value = [];
  81. if (localStorage.getItem('feedbackContent')) {
  82. localStorage.removeItem('feedbackContent');
  83. }
  84. if (localStorage.getItem('feedbackFileList')) {
  85. localStorage.removeItem('feedbackFileList');
  86. }
  87. submitSuccessDialogVisible.value = false;
  88. }
  89. const submitFailureConfirm = () => {
  90. submitFailureDialogVisible.value = false;
  91. }
  92. // 字数限制提示弹窗
  93. const feedbackContentOverLengthDialogVisible = ref(false)
  94. const feedbackContentLengthJudge = () => {
  95. console.log('字数判断');
  96. console.log(feedbackContent.value.length)
  97. if (feedbackContent.value.length >= 2000) {
  98. feedbackContentOverLengthDialogVisible.value = true;
  99. }
  100. }
  101. const feedbackContentOverLengthConfirm = () => {
  102. feedbackContentOverLengthDialogVisible.value = false;
  103. }
  104. const feedbackContentChange = () => {
  105. console.log('内容改变');
  106. console.log(feedbackContent.value)
  107. localStorage.setItem('feedbackContent', feedbackContent.value);
  108. }
  109. const check = function (file, fileList) {
  110. console.log('调用check方法');
  111. console.log(fileList);
  112. console.log(fileList.length);
  113. }
  114. const successChange = function (file, fileList) {
  115. console.log('调用successChange方法');
  116. console.log(fileList);
  117. console.log(fileList.response);
  118. if (fileList.response.code == 200) {
  119. feedbackFileList.value.push(fileList.response.data)
  120. }
  121. console.log(feedbackFileList.value);
  122. localStorage.setItem('feedbackFileList', JSON.stringify(feedbackFileList.value));
  123. }
  124. const dialogImageUrl = ref('')
  125. const dialogVisible = ref(false)
  126. const handleRemove = (uploadFile, uploadFiles) => {
  127. console.log(uploadFile, uploadFiles)
  128. feedbackFileList.value = uploadFiles;
  129. console.log('调用handleRemove方法');
  130. console.log(feedbackFileList.value);
  131. console.log(feedbackFileList.value.length);
  132. localStorage.setItem('feedbackFileList', JSON.stringify(feedbackFileList.value));
  133. }
  134. const handlePictureCardPreview = (uploadFile) => {
  135. dialogImageUrl.value = uploadFile.url
  136. dialogVisible.value = true
  137. }
  138. // 返回弹窗
  139. const feedbackBackDialogVisible = ref(false)
  140. const feedbackBack = () => {
  141. if(feedbackContent.value == '' && feedbackFileList.value.length == 0) {
  142. dataStore.isFeedback = false;
  143. return;
  144. }
  145. feedbackBackDialogVisible.value = true;
  146. }
  147. // 确人保存
  148. const feedbackBackConfirm = () => {
  149. feedbackBackDialogVisible.value = false;
  150. dataStore.isFeedback = false;
  151. }
  152. // 取消保存
  153. const feedbackBackCancel = () => {
  154. if (localStorage.getItem('feedbackContent')) {
  155. localStorage.removeItem('feedbackContent');
  156. }
  157. if (localStorage.getItem('feedbackFileList')) {
  158. localStorage.removeItem('feedbackFileList');
  159. }
  160. feedbackBackDialogVisible.value = false;
  161. dataStore.isFeedback = false;
  162. }
  163. onMounted(() => {
  164. feedbackHistory()
  165. if (localStorage.getItem('feedbackContent')) {
  166. feedbackContent.value = localStorage.getItem('feedbackContent')
  167. } else {
  168. feedbackContent.value = '';
  169. }
  170. if (localStorage.getItem('feedbackFileList')) {
  171. feedbackFileList.value = JSON.parse(localStorage.getItem('feedbackFileList'));
  172. } else {
  173. feedbackFileList.value = [];
  174. }
  175. console.log(uploadUrl)
  176. })
  177. </script>
  178. <template>
  179. <el-container>
  180. <div>
  181. <div @click="feedbackBack">
  182. <img :src="back" alt="返回按钮" class="backImg">
  183. </div>
  184. </div>
  185. <el-scrollbar>
  186. <el-header>
  187. <div class="feedbackImgClass">
  188. <img :src="feedback" alt="用户反馈" class="img">
  189. <img :src="feedbackImg" alt="用户反馈" class="img">
  190. </div>
  191. </el-header>
  192. <el-main>
  193. <div class="card">
  194. <div class="feedbackTitle header-item">
  195. 填写反馈内容
  196. </div>
  197. <div class="header-item">
  198. <el-input class="feedbackContent" v-model="feedbackContent" :rows="5" type="textarea"
  199. maxlength="2000" show-word-limit placeholder="请描写您想反馈的内容..." @change="feedbackContentChange"
  200. @input="feedbackContentLengthJudge" />
  201. </div>
  202. <div class="feedbackTitle header-item">
  203. 照片上传
  204. </div>
  205. <div class="header-item">
  206. <el-upload class="uploadImg" :action="uploadUrl" list-type="picture-card" :auto-upload="true"
  207. :on-success="successChange" accept=".png, .jpg, .jpeg, .ico," :on-change="check"
  208. :file-list="feedbackFileList" :on-preview="handlePictureCardPreview"
  209. :on-remove="handleRemove" :limit="3">
  210. <el-icon>
  211. <Plus />
  212. </el-icon>
  213. <template #tip>
  214. <div class="el-upload__tip">
  215. 最多上传三张
  216. </div>
  217. </template>
  218. </el-upload>
  219. </div>
  220. <div>
  221. <div class="feedbackSubmitBtn" @click="feedbackSubmit"> </div>
  222. </div>
  223. </div>
  224. <div class="card">
  225. <div class="feedbackTitle">
  226. 历史反馈内容
  227. </div>
  228. <div v-if="isHistoryFeedback">
  229. <div v-for="(item, index) in feedbackHistoryList" :key="index" class="feedbackHistory">
  230. <div class="feedbackHistoryItem">
  231. <div class="feedbackHistoryTitle">
  232. <img :src="purpleDot" alt="紫点" class="purpleDot">
  233. {{ moment(item.created_at).format('YYYY-MM-DD HH:mm') }}
  234. <div class="feedbackSuccess">
  235. <div class="feedbackSuccessWord">
  236. 反馈成功
  237. </div>
  238. <img class="feedbackSuccessImg" :src="feedbackSuccess" alt="成功">
  239. </div>
  240. </div>
  241. <div class="feedbackHistoryContent">
  242. {{ item.content }}
  243. </div>
  244. <div class="feedbackHistoryImg">
  245. <el-image v-if="item.image1" :src="item.image1" alt="图片错误"
  246. class="feedbackHistoryImgItem" :preview-src-list="[item.image1]" />
  247. <el-image v-if="item.image2" :src="item.image2" alt="图片错误"
  248. class="feedbackHistoryImgItem" :preview-src-list="[item.image2]" />
  249. <el-image v-if="item.image3" :src="item.image3" alt="图片错误"
  250. class="feedbackHistoryImgItem" :preview-src-list="[item.image3]" />
  251. </div>
  252. </div>
  253. </div>
  254. </div>
  255. <div v-else>
  256. <div class="noFeedback">
  257. <img class="noFeedbackImg" :src="noFeedback" alt="暂无历史提交">
  258. 暂无记录
  259. </div>
  260. </div>
  261. </div>
  262. </el-main>
  263. </el-scrollbar>
  264. </el-container>
  265. <el-dialog v-model="dialogVisible">
  266. <img w-full :src="dialogImageUrl" alt="Preview Image" />
  267. </el-dialog>
  268. <el-dialog v-model="feedbackBackDialogVisible" class="save-dialog">
  269. <div class="imgLine">
  270. <img class="dialogImg" :src="save" alt="保存">
  271. </div>
  272. <div class="feedbackBackTitle">
  273. 系统提示
  274. </div>
  275. <div class="feedbackBackAttention">
  276. 检测到为保存内容离开将丢失修改请选择是否保留此次编辑
  277. </div>
  278. <div class="feedbackBackBtnGroup">
  279. <el-button class="feedbackBackBtn nosave" plain @click="feedbackBackCancel" type="primary">不保留</el-button>
  280. <el-button class="feedbackBackBtn save" @click="feedbackBackConfirm" type="primary">保留</el-button>
  281. </div>
  282. </el-dialog>
  283. <el-dialog v-model="feedbackContentOverLengthDialogVisible" class="save-dialog">
  284. <div class="feedbackContentOverLengthTitle">
  285. 温馨提示
  286. </div>
  287. <div class="feedbackContentOverLengthContent">
  288. 当前输入字数已达上限
  289. </div>
  290. <div class="feedbackBackBtnGroup">
  291. <el-button class="feedbackContentOverLengthBtn confirm" type="primary"
  292. @click="feedbackContentOverLengthConfirm">确认</el-button>
  293. </div>
  294. </el-dialog>
  295. <el-dialog v-model="submitSuccessDialogVisible" class="save-dialog">
  296. <div class="imgLine">
  297. <img class="dialogImg" :src="success" alt="成功">
  298. </div>
  299. <div class="feedbackSuccessTitle">
  300. 提交成功
  301. </div>
  302. <div class="feedbackBackAttention">
  303. 感谢您的反馈
  304. </div>
  305. <div class="feedbackBackBtnGroup">
  306. <el-button class="feedbackBackBtn confirm" @click="submitSuccessConfirm" type="primary">确定</el-button>
  307. </div>
  308. </el-dialog>
  309. <el-dialog v-model="submitFailureDialogVisible" class="save-dialog">
  310. <div class="imgLine">
  311. <img class="dialogImg" :src="failure" alt="失败">
  312. </div>
  313. <div class="feedbackFailureTitle">
  314. 提交失败
  315. </div>
  316. <div class="feedbackBackAttention">
  317. {{ submitFailureContent }}
  318. </div>
  319. <div class="feedbackBackBtnGroup">
  320. <el-button class="feedbackBackBtn confirm" @click="submitFailureConfirm" type="primary">确定</el-button>
  321. </div>
  322. </el-dialog>
  323. </template>
  324. <style scoped>
  325. .backImg{
  326. width: 40px;
  327. height: 40px;
  328. margin-left: 10px;
  329. }
  330. .el-container {
  331. display: flex;
  332. flex-direction: column;
  333. overflow: auto;
  334. }
  335. .el-header {
  336. height: auto;
  337. padding: 0;
  338. }
  339. .el-main {
  340. height: auto;
  341. padding: 0;
  342. display: flex;
  343. flex-direction: column;
  344. gap: 20px;
  345. overflow: hidden;
  346. }
  347. .card {
  348. background-color: white;
  349. padding: 20px;
  350. height: auto;
  351. border-radius: 15px;
  352. }
  353. .header-item {
  354. margin: 10px 0;
  355. }
  356. .feedbackImgClass {
  357. display: flex;
  358. justify-content: space-between;
  359. align-items: center;
  360. margin: 0 20px;
  361. }
  362. .img {
  363. max-width: 50%;
  364. height: auto;
  365. object-fit: contain;
  366. }
  367. .feedbackSubmitBtn {
  368. width: 60%;
  369. height: 50px;
  370. text-align: center;
  371. display: flex;
  372. align-items: center;
  373. justify-content: center;
  374. margin: 0 auto;
  375. background: linear-gradient(90deg, #cac4fe, #b9d0fc, #a7dbfc);
  376. border-radius: 60px;
  377. color: #4423FF;
  378. font-weight: bold;
  379. font-size: 25px;
  380. cursor: pointer;
  381. }
  382. .feedbackTitle {
  383. font-size: 25px;
  384. font-weight: bold;
  385. }
  386. .feedbackContent {
  387. font-size: 20px;
  388. }
  389. @media (max-width: 768px) {
  390. .feedbackTitle {
  391. font-size: 20px;
  392. }
  393. .feedbackContent {
  394. font-size: 15px;
  395. }
  396. }
  397. .noFeedback {
  398. margin: 20px 0;
  399. display: flex;
  400. flex-direction: column;
  401. align-items: center;
  402. justify-content: center;
  403. }
  404. .noFeedbackImg {
  405. width: 200px;
  406. height: 200px;
  407. }
  408. .feedbackBackTitle {
  409. width: 100%;
  410. text-align: center;
  411. font-size: 25px;
  412. font-weight: bold;
  413. color: #2961FF
  414. }
  415. .feedbackBackAttention {
  416. font-size: 15px;
  417. font-weight: bold;
  418. margin: 10px 5px;
  419. text-align: center;
  420. }
  421. .feedbackBackBtnGroup {
  422. display: flex;
  423. align-items: center;
  424. justify-content: center;
  425. margin: 20px auto;
  426. width: 75%;
  427. }
  428. .feedbackBackBtn {
  429. margin: 0 auto;
  430. font-weight: bold;
  431. border-radius: 20px;
  432. }
  433. .save {
  434. background: #816CF6;
  435. border: none;
  436. }
  437. .nosave {
  438. color: #816CF6;
  439. background: white;
  440. border: none;
  441. }
  442. .confirm {
  443. background: #816CF6;
  444. border: none;
  445. }
  446. .feedbackContentOverLengthTitle {
  447. font-size: 25px;
  448. font-weight: bold;
  449. width: 100%;
  450. text-align: center;
  451. margin: 20px 0;
  452. color: #2961FF;
  453. }
  454. .feedbackContentOverLengthContent {
  455. font-size: 15px;
  456. font-weight: bold;
  457. width: 100%;
  458. text-align: center;
  459. margin: 20px 0;
  460. }
  461. .imgLine {
  462. width: 100%;
  463. display: flex;
  464. }
  465. .dialogImg {
  466. max-width: 300px;
  467. width: 50%;
  468. height: 50%;
  469. margin: 0 auto;
  470. }
  471. .feedbackSuccessTitle {
  472. width: 100%;
  473. text-align: center;
  474. font-size: 25px;
  475. font-weight: bold;
  476. color: #2961FF
  477. }
  478. .feedbackFailureTitle {
  479. width: 100%;
  480. text-align: center;
  481. font-size: 25px;
  482. font-weight: bold;
  483. color: #ff4646
  484. }
  485. .purpleDot {
  486. margin: 0px 5px 0px 0px;
  487. width: 20px;
  488. height: 20px;
  489. }
  490. .feedbackHistoryTitle {
  491. display: flex;
  492. }
  493. .feedbackSuccess {
  494. margin-left: auto;
  495. display: flex;
  496. }
  497. .feedbackSuccessWord {
  498. padding: 3px 0 0 0;
  499. color: #4221FF;
  500. font-weight: bold;
  501. }
  502. .feedbackSuccessImg {
  503. width: 30px;
  504. height: auto;
  505. margin: 0 5px;
  506. }
  507. .feedbackHistoryContent {
  508. min-height: 50px;
  509. margin: 0 0 0 25px;
  510. font-weight: bold;
  511. }
  512. .feedbackHistoryImg {
  513. display: flex;
  514. margin: 0px 0px 0px 20px;
  515. }
  516. .feedbackHistoryImgItem {
  517. width: 100px;
  518. height: auto;
  519. margin: 5px 10px;
  520. }
  521. </style>
  522. <style>
  523. .uploadImg .el-upload {
  524. width: 150px;
  525. height: 150px;
  526. }
  527. @media (max-width: 768px) {
  528. .uploadImg .el-upload {
  529. width: 100px;
  530. height: 100px;
  531. }
  532. }
  533. .feedbackContentOverLengthBtn {
  534. margin: 0 auto;
  535. color: white;
  536. &:hover,
  537. &:active,
  538. &:focus {
  539. color: white !important;
  540. }
  541. }
  542. .save-dialog {
  543. background: linear-gradient(90deg, #cac4fe, #b9d0fc, #a7dbfc);
  544. border-radius: 20px;
  545. }
  546. </style>