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.

656 lines
13 KiB

4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
4 weeks ago
  1. <template>
  2. <view class="main">
  3. <view class="top" :style="{height:iSMT+'px'}"></view>
  4. <!-- 头部导航 -->
  5. <view class="header">
  6. <view class="back-icon">
  7. <image @click="onBack" src="/static/customer-service-platform/cs-platform-back.png" class="header-icon-image"></image>
  8. </view>
  9. <view class="title">{{headerTitle}}</view>
  10. <view class="notification-icon">
  11. <image src="/static/customer-service-platform/message.png" class="header-icon-image"></image>
  12. </view>
  13. </view>
  14. <!-- 内容区域 - 使用滚动视图 -->
  15. <scroll-view scroll-y class="content-container">
  16. <view class="content-header">
  17. <view class="content-header-area">
  18. <view class="logo">
  19. <image mode="aspectFit" src="/static/customer-service-platform/ellipse-dc-img.png"></image>
  20. </view>
  21. <view class="greeting">
  22. <text class="greet-title">我能为你做点什么</text>
  23. <text class="greet-sub">DeepChart随时为您提供服务</text>
  24. </view>
  25. </view>
  26. </view>
  27. <!--猜你想问卡片部分-->
  28. <view class="card">
  29. <view class="suggest-header">
  30. <text class="suggest-title">猜你想问</text>
  31. <view class="swap" @click="shuffleQuestions">
  32. <image class="swap-icon" src="/static/customer-service-platform/refresh-icon.png"></image>
  33. <text class="swap-title">换一换</text>
  34. </view>
  35. </view>
  36. <view class="card-line"></view>
  37. <view class="suggest-list">
  38. <view class="suggest-item" v-for="(q, idx) in showQuestions" :key="q.id"
  39. @click="onQuestionClick(q)">
  40. <view class="left">
  41. <view :class="['num', 'num-' + ((idx % 5) + 1)]">{{ idx + 1 }}</view>
  42. </view>
  43. <view class="mid">
  44. <text class="q-text">{{ q.text }}</text>
  45. </view>
  46. <view class="right">
  47. <text class="arrow"></text>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. <!--反馈卡片部分-->
  53. <text class="feedback-card-title">反馈中心</text>
  54. <view class="card">
  55. <view class="suggest-header">
  56. <text class="feedback-title">填写反馈内容</text>
  57. </view>
  58. <view class="card-line"></view>
  59. <textarea class="feedback-input" placeholder="请描述您想反馈的内容 最多可输入200字" maxlength="200"
  60. v-model="feedbackText" />
  61. <view class="meta-row">
  62. <text class="char-count">{{ feedbackText.length }}/200</text>
  63. </view>
  64. <view class="suggest-header">
  65. <text class="upload-img-tip">上传图片</text>
  66. </view>
  67. <view class="upload-row">
  68. <view class="img-slot" v-for="(img, index) in images" :key="index">
  69. <image :src="img" mode="scaleToFill" class="slot-img" />
  70. <button v-if="img" class="remove" @click="removeImage(index)">×</button>
  71. </view>
  72. <view class="img-slot" v-if="images.length < 9">
  73. <view class="slot-empty" @click="chooseImage()">
  74. <image src="/static/customer-service-platform/camera.png" class="camera-icon" />
  75. </view>
  76. </view>
  77. <text class="tip-text" v-if="images.length === 0">最多添加9张图片</text>
  78. </view>
  79. <button class="feedback-btn" @click="onSumbitFeedback()">提交</button>
  80. <feedback-modal ref="feedback" @confirm="onConfirm" />
  81. </view>
  82. <!--历史反馈卡片部分-->
  83. <view class="card">
  84. <text class="feedback-title">历史反馈内容</text>
  85. <view class="card-line"></view>
  86. <button class="feedback-btn" @click="viewHistory">查看</button>
  87. </view>
  88. </scroll-view>
  89. </view>
  90. </template>
  91. <script>
  92. import FeedbackModal from '@/components/FeedbackModal.vue'
  93. export default {
  94. components: { FeedbackModal },
  95. data() {
  96. return {
  97. headerTitle: '智能客服中台',
  98. iSMT: 0,
  99. questions: [{
  100. id: 1,
  101. text: '如何注册账号?'
  102. },
  103. {
  104. id: 2,
  105. text: '为什么无法注册账户?'
  106. },
  107. {
  108. id: 3,
  109. text: 'DeepChart的主要功能有哪些?'
  110. },
  111. {
  112. id: 4,
  113. text: '什么是机构行为?'
  114. },
  115. {
  116. id: 5,
  117. text: '为什么机构行为很重要?'
  118. },
  119. {
  120. id: 6,
  121. text: '如何绑定银行卡?'
  122. },
  123. {
  124. id: 7,
  125. text: '忘记密码怎么办?'
  126. }
  127. ],
  128. showQuestions: [],
  129. feedbackText: '',
  130. images: [],
  131. capacity: 2
  132. }
  133. },
  134. mounted() {
  135. // 状态栏高度
  136. this.iSMT = uni.getSystemInfoSync().statusBarHeight;
  137. },
  138. created() {
  139. this.shuffleQuestions();
  140. },
  141. methods: {
  142. onSumbitFeedback(){
  143. this.onSuccess();
  144. },
  145. onSuccess() {
  146. this.$refs.feedback.show({
  147. status: 'success',
  148. title: '提交成功',
  149. subtitle: '— 感谢您的反馈 —',
  150. buttonText: '确定',
  151. width:'80%',
  152. });
  153. },
  154. onFail() {
  155. this.$refs.feedback.show({
  156. status: 'fail',
  157. title: '提交失败',
  158. subtitle: '— 请重新提交 —',
  159. buttonText: '确定',
  160. width:'80%',
  161. });
  162. },
  163. onBack() {
  164. if (typeof uni !== 'undefined') uni.navigateBack();
  165. },
  166. shuffleQuestions() {
  167. // 随机取前4条或展示5条
  168. const arr = this.questions.slice();
  169. for (let i = arr.length - 1; i > 0; i--) {
  170. const j = Math.floor(Math.random() * (i + 1));
  171. [arr[i], arr[j]] = [arr[j], arr[i]];
  172. }
  173. this.showQuestions = arr.slice(0, 5);
  174. },
  175. onQuestionClick(q) {
  176. // 可跳转到问答页或直接填入反馈
  177. this.feedbackText = q.text;
  178. },
  179. chooseImage() {
  180. const that = this;
  181. if (typeof uni === 'undefined' || !uni.chooseImage) return;
  182. const remain = 9 - (that.images ? that.images.length : 0);
  183. if (remain <= 0) {
  184. if (typeof uni !== 'undefined') uni.showToast({
  185. title: '最多只能上传9张',
  186. icon: 'none'
  187. });
  188. return;
  189. }
  190. uni.chooseImage({
  191. count: remain, // 最多选取剩余可上传数量
  192. sizeType: ['original', 'compressed'],
  193. sourceType: ['album', 'camera'],
  194. success(res) {
  195. // res.tempFilePaths 是数组(小程序/APP)
  196. const paths = res.tempFilePaths || (res.tempFiles && res.tempFiles.map(f => f.path)) || [];
  197. // 追加到 images(Vue2 下 push 是响应式的)
  198. for (let p of paths) {
  199. if (that.images.length < 9) {
  200. that.images.push(p);
  201. }
  202. }
  203. // 可选:若要立即上传到服务器,可在这里调用 uni.uploadFile
  204. },
  205. fail(err) {
  206. // 处理取消或失败(不需要提示太多)
  207. // console.log('chooseImage fail', err)
  208. }
  209. });
  210. },
  211. removeImage(index) {
  212. // 删除并保持响应
  213. this.images.splice(index, 1);
  214. },
  215. submit() {
  216. if (!this.feedbackText.trim()) {
  217. if (typeof uni !== 'undefined') uni.showToast({
  218. title: '请填写反馈内容',
  219. icon: 'none'
  220. });
  221. return;
  222. }
  223. // 模拟上传
  224. if (typeof uni !== 'undefined') uni.showLoading({
  225. title: '提交中...'
  226. });
  227. setTimeout(() => {
  228. if (typeof uni !== 'undefined') {
  229. uni.hideLoading();
  230. uni.showToast({
  231. title: '提交成功',
  232. icon: 'success'
  233. });
  234. } else {
  235. console.log('提交数据', {
  236. text: this.feedbackText,
  237. images: this.images
  238. });
  239. }
  240. // 清空
  241. this.feedbackText = '';
  242. this.images = [null, null];
  243. }, 1000);
  244. },
  245. viewHistory() {
  246. // 跳转到历史页
  247. if (typeof uni !== 'undefined') uni.navigateTo({
  248. url: '/pages/customerServicePlatform/historyRecord'
  249. });
  250. }
  251. }
  252. }
  253. </script>
  254. <style scoped>
  255. .main {
  256. display: flex;
  257. flex-direction: column;
  258. height: 100vh;
  259. background-color: #ffffff;
  260. }
  261. .header {
  262. display: flex;
  263. justify-content: space-between;
  264. align-items: center;
  265. padding: 20rpx 30rpx;
  266. background-color: #ffffff;
  267. }
  268. .title {
  269. color: #000000;
  270. text-align: center;
  271. font-size: 32rpx;
  272. font-style: normal;
  273. font-weight: 400;
  274. }
  275. .back-icon,
  276. .notification-icon {
  277. width: 40rpx;
  278. display: flex;
  279. align-items: center;
  280. justify-content: center;
  281. }
  282. .header-icon-image {
  283. width: 40rpx;
  284. height: 40rpx;
  285. object-fit: contain;
  286. }
  287. .content-container {
  288. padding: 20rpx;
  289. width: 100%;
  290. box-sizing: border-box;
  291. overflow-x: hidden;
  292. }
  293. .content-header {
  294. display: flex;
  295. align-items: center;
  296. justify-content: center;
  297. gap: 24rpx;
  298. padding: 0 60rpx;
  299. width: 100%;
  300. box-sizing: border-box;
  301. height: 188rpx;
  302. }
  303. .content-header-area {
  304. display: flex;
  305. gap: 20rpx;
  306. }
  307. .logo {
  308. width: 120rpx;
  309. height: 120rpx;
  310. display: flex;
  311. align-items: center;
  312. justify-content: center;
  313. flex: 0 0 112rpx;
  314. }
  315. .greeting {
  316. display: flex;
  317. flex-direction: column;
  318. justify-content: center;
  319. flex: 1 1 auto;
  320. }
  321. .greet-title {
  322. color: #000;
  323. font-size: 40rpx;
  324. font-style: normal;
  325. font-weight: 500;
  326. line-height: normal;
  327. margin: 0;
  328. overflow: hidden;
  329. text-overflow: ellipsis;
  330. white-space: nowrap;
  331. }
  332. .greet-sub {
  333. color: #838383;
  334. font-size: 28rpx;
  335. font-style: normal;
  336. font-weight: 400;
  337. line-height: normal;
  338. margin-top: 12rpx;
  339. overflow: hidden;
  340. text-overflow: ellipsis;
  341. white-space: nowrap;
  342. }
  343. .card {
  344. width: 90%;
  345. margin: 0 auto;
  346. border-radius: 16rpx;
  347. padding: 20rpx 40rpx;
  348. box-sizing: border-box;
  349. border-radius: 12rpx;
  350. border: 4rpx solid #FCC8D4;
  351. background: linear-gradient(180deg, #FCC8D3 0%, #FEF0F3 30%, #FFF 100%);
  352. margin-bottom: 20rpx;
  353. }
  354. .suggest-header {
  355. width: 100%;
  356. display: flex;
  357. align-items: center;
  358. justify-content: space-between;
  359. }
  360. .suggest-title {
  361. color: #000000;
  362. font-size: 32rpx;
  363. font-style: normal;
  364. font-weight: 400;
  365. line-height: normal;
  366. }
  367. .swap {
  368. display: flex;
  369. align-items: center;
  370. transition: transform 0.1s ease, background-color 0.1s ease;
  371. }
  372. .swap:active {
  373. transform: scale(0.95);
  374. }
  375. .swap-icon {
  376. width: 30rpx;
  377. height: 30rpx;
  378. }
  379. .swap-title {
  380. padding-left: 8rpx;
  381. color: #000000;
  382. font-size: 24rpx;
  383. font-style: normal;
  384. font-weight: 400;
  385. line-height: normal;
  386. }
  387. .suggest-list {
  388. margin-top: 20rpx;
  389. }
  390. .card-line {
  391. margin-top: 20rpx;
  392. width: 100%;
  393. height: 2rpx;
  394. border-radius: 2rpx;
  395. background: #FFF;
  396. }
  397. .suggest-item {
  398. display: flex;
  399. justify-content: space-between;
  400. align-items: center;
  401. padding-top: 10rpx;
  402. border-radius: 12rpx;
  403. margin-bottom: 20rpx;
  404. width: 100%;
  405. box-sizing: border-box;
  406. }
  407. .left {
  408. width: 72rpx;
  409. display: flex;
  410. justify-content: center;
  411. align-items: center;
  412. padding-right: 12rpx;
  413. }
  414. .num {
  415. font-size: 40rpx;
  416. font-style: normal;
  417. font-weight: 700;
  418. line-height: normal;
  419. }
  420. .num-1 {
  421. color: #df5662;
  422. }
  423. .num-2 {
  424. color: #ec6d4f;
  425. }
  426. .num-3 {
  427. color: #f3ba40;
  428. }
  429. .num-4 {
  430. color: #9296a0;
  431. }
  432. .num-5 {
  433. color: #9296a0;
  434. }
  435. .mid {
  436. flex: 1 1 auto;
  437. min-width: 0;
  438. }
  439. .q-text {
  440. display: block;
  441. color: #333;
  442. font-size: 28rpx;
  443. white-space: nowrap;
  444. overflow: hidden;
  445. text-overflow: ellipsis;
  446. }
  447. .right {
  448. width: 48rpx;
  449. display: flex;
  450. align-items: center;
  451. justify-content: flex-end;
  452. }
  453. .arrow {
  454. color: #cfcfcf;
  455. font-size: 36rpx;
  456. }
  457. .suggest-item:active {
  458. background: rgba(255, 77, 128, 0.06);
  459. }
  460. .feedback-card-title {
  461. display: flex;
  462. justify-content: center;
  463. color: #000000;
  464. font-size: 32rpx;
  465. font-weight: 700;
  466. line-height: 40rpx;
  467. width: 100%;
  468. margin-bottom: 20rpx;
  469. }
  470. .feedback-title {
  471. color: #000000;
  472. font-size: 32rpx;
  473. font-style: normal;
  474. font-weight: 400;
  475. line-height: normal;
  476. }
  477. .feedback-input {
  478. width: 100%;
  479. display: flex;
  480. padding: 20rpx;
  481. flex-direction: column;
  482. box-sizing: border-box;
  483. align-items: flex-start;
  484. gap: 12rpx;
  485. align-self: stretch;
  486. border-radius: 12rpx;
  487. border: 2rpx solid #F0F1F1;
  488. margin-top: 20rpx;
  489. display: flex;
  490. background: #FFF;
  491. color: #8a8a8a;
  492. font-size: 24rpx;
  493. font-weight: 700;
  494. line-height: normal;
  495. }
  496. .meta-row {
  497. display: flex;
  498. justify-content: flex-end;
  499. margin-top: 12rpx;
  500. }
  501. .char-count {
  502. color: #999
  503. }
  504. .upload-img-tip {
  505. color: #000000;
  506. font-size: 24rpx;
  507. font-style: normal;
  508. font-weight: 400;
  509. line-height: normal;
  510. }
  511. .upload-row {
  512. display: flex;
  513. justify-content: flex-start;
  514. align-items: flex-start;
  515. align-content: flex-start;
  516. flex-wrap: wrap;
  517. gap: 20rpx;
  518. margin-top: 20rpx;
  519. width: 100%;
  520. }
  521. .img-slot {
  522. width: calc((100% - 2 * 30rpx) / 3);
  523. aspect-ratio: 1 / 1;
  524. border-radius: 6px;
  525. border: 1px solid #F0F1F1;
  526. background: #FFF;
  527. position: relative;
  528. display: flex;
  529. align-items: center;
  530. justify-content: center;
  531. overflow: hidden;
  532. transition: transform 0.2s ease;
  533. }
  534. .slot-empty {
  535. width: 100%;
  536. height: 100%;
  537. display: flex;
  538. align-items: center;
  539. justify-content: center;
  540. }
  541. .camera-icon {
  542. width: 34rpx;
  543. height: 34rpx;
  544. }
  545. .slot-img {
  546. width: 100%;
  547. height: 100%;
  548. border-radius: 16rpx;
  549. }
  550. .remove {
  551. position: absolute;
  552. right: 6rpx;
  553. top: 6rpx;
  554. border-radius: 50%;
  555. background: #fd5c58;
  556. padding: 0;
  557. color: #fff;
  558. width: 36rpx;
  559. height: 36rpx;
  560. font-size: 28rpx;
  561. line-height: 36rpx;
  562. text-align: center;
  563. border: none;
  564. outline: none;
  565. cursor: pointer;
  566. }
  567. .remove:active {
  568. background: rgba(0, 0, 0, 0.75);
  569. }
  570. .image-upload-tip {
  571. display: flex;
  572. align-items: center;
  573. }
  574. .tip-text {
  575. color: #999999;
  576. font-size: 24rpx;
  577. font-style: normal;
  578. font-weight: 400;
  579. line-height: 40rpx;
  580. padding-top: 64rpx;
  581. }
  582. .feedback-btn {
  583. margin-top: 24rpx;
  584. width: 180rpx;
  585. height: 60rpx;
  586. aspect-ratio: 89/30;
  587. border-radius: 30rpx;
  588. background: #090A08;
  589. color: #ffffff;
  590. display: flex;
  591. justify-content: center;
  592. align-items: center;
  593. font-size: 16px;
  594. font-style: normal;
  595. font-weight: 700;
  596. line-height: normal;
  597. }
  598. </style>