feedback.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. <template>
  2. <view>
  3. <view class="container" v-if="formInfo&&formInfo.length>0">
  4. <view class="list-item title">投诉原因:{{ text }}</view>
  5. </view>
  6. <view class="formbox" v-if="formInfo&&formInfo.length>0">
  7. <u-form labelPosition="left" labelWidth='80' :model="formdata" :rules="rules" ref="uForm" errorType="toast">
  8. <u-form-item :required="item.isRequire == 1" :label="item.name" :prop="item.desc"
  9. v-for="(item,i) in formInfo" :key="i">
  10. <template v-if="item.type=='文本框'">
  11. <u-input v-model="formdata[item.desc]" border="none" :clearable="true"
  12. :placeholder="'请填写'+item.name"></u-input>
  13. </template>
  14. <template v-if="item.type=='图片'">
  15. <view class="imgitem">
  16. <u-upload :key="imgdata[item.desc].key" :fileList="imgdata[item.desc]" @afterRead="afterRead" @delete="deletePic" :name="item.desc" multiple :maxCount="9">
  17. </u-upload>
  18. </view>
  19. </template>
  20. </u-form-item>
  21. </u-form>
  22. <view class="footer-btn">
  23. <button class="submit-btn" @click="submit">提交</button>
  24. <button class="submit-btn back-btn" @click="goBack">返回</button>
  25. </view>
  26. </view>
  27. <view class="container" v-else>
  28. <view class="list-item title">请选择投诉原因</view>
  29. <view class="list-item" v-for="(item, index) in feedbackItems" :key="index"
  30. @click="handleClick(item,index)">
  31. <view>{{ item.name }}</view>
  32. <uni-icons type="right" size="20" color="rgba(0,0,0,.3)" v-if="formInfo.length==0"></uni-icons>
  33. </view>
  34. <view class="list-item" v-if="pageIndex!=0&&formInfo.length==0" @click="goBack">
  35. 返回上一层
  36. </view>
  37. </view>
  38. </view>
  39. </template>
  40. <script>
  41. import { templateList, complaint } from "@/api/user.js"
  42. import { addReportTalent, addReportVideo } from "@/api/expert.js"
  43. export default {
  44. data() {
  45. return {
  46. statusBarHeight: uni.getSystemInfoSync().statusBarHeight,
  47. menuButtonH: 45,
  48. pageIndex: 0,
  49. list: [],
  50. feedbackItems: [],
  51. userId: '',
  52. courseId: '',
  53. videoId: '',
  54. formInfo: [],
  55. formdata: {},
  56. imgdata: {},
  57. rules: {},
  58. text: '',
  59. templateId: 0,
  60. user: {},
  61. isLastChild: 0,
  62. type:null,
  63. talentId:null,
  64. videoId:null,
  65. };
  66. },
  67. onLoad(options) {
  68. if(!this.$isLogin()){
  69. uni.navigateTo({
  70. url: '/pages/auth/loginIndex'
  71. })
  72. return;
  73. }
  74. this.user = this.$getUserInfo()
  75. this.getList();
  76. if(!!options.type){
  77. this.type=options.type;
  78. }
  79. if(!!options.talentId){
  80. this.talentId=options.talentId;
  81. }
  82. if(!!options.videoId){
  83. this.videoId=options.videoId;
  84. }
  85. },
  86. onReady() {
  87. //onReady 为uni-app支持的生命周期之一
  88. // this.$refs.uForm.setRules(this.rules)
  89. },
  90. methods: {
  91. goBack() {
  92. // 返回上一层逻辑
  93. if (this.pageIndex == 0) {
  94. uni.navigateBack();
  95. } else {
  96. this.pageIndex--;
  97. this.formInfo = []
  98. this.rules = {}
  99. this.formdata = {}
  100. this.imgdata = {}
  101. if (this.isLastChild == 1) {
  102. this.isLastChild = 0
  103. } else {
  104. if (this.pageIndex == 0) {
  105. this.feedbackItems = this.list
  106. this.templateId = 0
  107. } else {
  108. const list = this.findGrandparentOrAllData(this.list, this.templateId)
  109. this.feedbackItems = list.children
  110. this.templateId = list.id
  111. }
  112. }
  113. }
  114. },
  115. findGrandparentOrAllData(data, targetId) {
  116. // 递归函数,用于查找目标节点的父级节点
  117. function findParent(node, targetId) {
  118. if (!node || !node.children) return null;
  119. for (let child of node.children) {
  120. if (child.id === targetId) {
  121. return node; // 找到目标节点的父级节点
  122. }
  123. const result = findParent(child, targetId); // 递归查找子节点
  124. if (result) return result;
  125. }
  126. return null;
  127. }
  128. // 遍历顶层节点,查找目标节点的父级和祖父级节点
  129. for (let root of data) {
  130. if (root.id === targetId) {
  131. return data; // 如果目标节点是顶层节点,返回所有数据
  132. }
  133. const parent = findParent(root, targetId); // 查找目标节点的父级节点
  134. if (parent) {
  135. const grandparent = findParent(root, parent.id); // 查找父级节点的父级节点
  136. return grandparent || data; // 如果找到祖父节点返回祖父节点,否则返回所有数据
  137. }
  138. }
  139. return data; // 如果没有找到目标节点,返回所有数据
  140. },
  141. handleClick(item, index) {
  142. if (this.isLastChild == 1) return
  143. if (this.pageIndex >= 0) {
  144. this.pageIndex++
  145. let children = this.feedbackItems[index].children || [];
  146. this.templateId = this.feedbackItems[index].id
  147. this.formInfo = []
  148. this.rules = {}
  149. this.formdata = {}
  150. this.imgdata = {}
  151. this.text = this.feedbackItems[index].name
  152. if (children.length > 0) {
  153. this.isLastChild = 0
  154. this.feedbackItems = children
  155. this.templateId = this.feedbackItems[0].id
  156. }
  157. else {
  158. this.isLastChild = 1
  159. if (this.feedbackItems[index].description) {
  160. this.formInfo = JSON.parse(this.feedbackItems[index].description);
  161. const rules = {};
  162. const formdata = {};
  163. // 遍历description中的每个对象
  164. this.formInfo.forEach(descObj => {
  165. const {
  166. isRequire,
  167. desc,
  168. name,
  169. type
  170. } = descObj;
  171. formdata[desc] = ""
  172. if (type == '图片') {
  173. this.imgdata[desc] = []
  174. this.imgdata[desc].key = 1
  175. this.$forceUpdate()
  176. }
  177. // 如果isRequire为"1",则添加到rules中
  178. if (isRequire == 1) {
  179. rules[desc] = [{
  180. required: true,
  181. message: name + '不能为空',
  182. trigger: ["change", "blur"]
  183. }];
  184. }
  185. });
  186. this.rules = rules
  187. this.formdata = formdata;
  188. console.log("qxj formdata",this.formdata);
  189. setTimeout(() => {
  190. this.$refs.uForm.setRules(this.rules);
  191. }, 200)
  192. } else {
  193. this.formInfo = []
  194. this.rules = {}
  195. this.formdata = {}
  196. this.imgdata = {}
  197. this.$forceUpdate()
  198. }
  199. }
  200. }
  201. },
  202. getList() {
  203. templateList().then(res => {
  204. if (res.code == 200) {
  205. this.list = res.data
  206. this.pageIndex = 0
  207. this.feedbackItems = this.list
  208. } else {
  209. this.list = []
  210. }
  211. })
  212. },
  213. submit() {
  214. const imgs = this.convertArrayToString(this.imgdata)
  215. this.formdata = {
  216. ...this.formdata,
  217. ...imgs
  218. };
  219. this.$refs.uForm.validate().then(res => {
  220. if (res) {
  221. if(!this.type){
  222. this.doComplaint();
  223. }
  224. else{
  225. if(this.talentId!=null){
  226. this.doReportTalent();
  227. }
  228. if(this.videoId!=null){
  229. this.doReportVideo();
  230. }
  231. }
  232. }
  233. })
  234. },
  235. doReportTalent(){ //举报达人
  236. if(!!this.formdata.content){
  237. this.formdata.reportDesc=this.formdata.content;
  238. }
  239. const param = {
  240. talentId: this.talentId,
  241. type: 2,
  242. templateId: this.templateId,
  243. ...this.formdata
  244. }
  245. uni.showLoading({
  246. title:""
  247. });
  248. addReportTalent(param).then(res => {
  249. uni.hideLoading();
  250. if (res.code == 200) {
  251. uni.showModal({
  252. title: '',
  253. content: '我们已收到您的反馈,谢谢',
  254. showCancel: false,
  255. success: (res) => {
  256. this.formInfo = []
  257. this.rules = {}
  258. this.formdata = {}
  259. this.imgdata = {}
  260. this.text = ''
  261. this.templateId = 0
  262. this.isLastChild = 0
  263. this.pageIndex = 0
  264. this.feedbackItems = this.list
  265. }
  266. });
  267. } else {
  268. uni.showToast({
  269. title: res.msg,
  270. icon: 'none'
  271. })
  272. }
  273. },
  274. rej => {
  275. uni.hideLoading();
  276. });
  277. },
  278. doReportVideo(){ //举报短视频
  279. if(!!this.formdata.content){
  280. this.formdata.reportDesc=this.formdata.content;
  281. }
  282. const param = {
  283. videoId: this.videoId,
  284. type: 2,
  285. templateId: this.templateId,
  286. ...this.formdata
  287. }
  288. addReportVideo(param).then(res => {
  289. if (res.code == 200) {
  290. uni.showModal({
  291. title: '',
  292. content: '我们已收到您的反馈,谢谢',
  293. showCancel: false,
  294. success: (res) => {
  295. this.formInfo = []
  296. this.rules = {}
  297. this.formdata = {}
  298. this.imgdata = {}
  299. this.text = ''
  300. this.templateId = 0
  301. this.isLastChild = 0
  302. this.pageIndex = 0
  303. this.feedbackItems = this.list
  304. }
  305. });
  306. } else {
  307. uni.showToast({
  308. title: res.msg,
  309. icon: 'none'
  310. })
  311. }
  312. })
  313. },
  314. doComplaint(){
  315. const param = {
  316. userId: this.user.userId,
  317. userName: this.user.nickName,
  318. templateId: this.templateId,
  319. ...this.formdata
  320. }
  321. complaint(param).then(res => {
  322. if (res.code == 200) {
  323. uni.showModal({
  324. title: '',
  325. content: '我们已收到您的反馈,谢谢',
  326. showCancel: false,
  327. success: (res) => {
  328. this.formInfo = []
  329. this.rules = {}
  330. this.formdata = {}
  331. this.imgdata = {}
  332. this.text = ''
  333. this.templateId = 0
  334. this.isLastChild = 0
  335. this.pageIndex = 0
  336. this.feedbackItems = this.list
  337. }
  338. });
  339. } else {
  340. uni.showToast({
  341. title: res.msg,
  342. icon: 'none'
  343. })
  344. }
  345. })
  346. },
  347. convertArrayToString(obj) {
  348. const result = {};
  349. for (const key in obj) {
  350. if (obj.hasOwnProperty(key)) {
  351. const value = obj[key];
  352. // 如果值是数组,则将其转换为逗号分隔的字符串
  353. if (Array.isArray(value)) {
  354. result[key] = value.filter(item => item.status == 'success').map(it => it.url).join(
  355. ","); // 使用逗号分隔数组元素
  356. } else {
  357. result[key] = value; // 保持原样
  358. }
  359. }
  360. }
  361. return result;
  362. },
  363. deletePic(event) {
  364. const fieldName = event.name;
  365. const index = event.index;
  366. if (this.imgdata[fieldName] && Array.isArray(this.imgdata[fieldName])) {
  367. this.imgdata[fieldName].splice(index, 1);
  368. }
  369. this.$forceUpdate()
  370. this.imgdata[fieldName].key --
  371. },
  372. async afterRead(event) {
  373. const fieldName = event.name;
  374. if (!this.imgdata[fieldName]) {
  375. this.imgdata[fieldName] = [];
  376. this.imgdata[fieldName].key = 1
  377. }
  378. let lists = Array.isArray(event.file) ? event.file : [event.file];
  379. for (let i = 0; i < lists.length; i++) {
  380. this.imgdata[fieldName].push({
  381. ...lists[i],
  382. status: 'uploading',
  383. message: '上传中...'
  384. });
  385. this.$forceUpdate()
  386. this.imgdata[fieldName].key ++
  387. // 调用上传方法
  388. const result = await this.uploadFilePromise(lists[i].url);
  389. if (result.code == 200) {
  390. this.imgdata[fieldName][this.imgdata[fieldName].length - 1] = {
  391. ...this.imgdata[fieldName][this.imgdata[fieldName].length - 1],
  392. url: result.url,
  393. status: 'success',
  394. message: ''
  395. };
  396. this.$forceUpdate()
  397. this.imgdata[fieldName].key ++
  398. } else {
  399. this.imgdata[fieldName][this.imgdata[fieldName].length - 1] = {
  400. ...this.imgdata[fieldName][this.imgdata[fieldName].length - 1],
  401. status: 'fail',
  402. message: '上传失败'
  403. };
  404. this.$forceUpdate()
  405. this.imgdata[fieldName].key ++
  406. uni.showToast({
  407. title: '上传失败',
  408. icon: 'error'
  409. });
  410. }
  411. }
  412. },
  413. uploadFilePromise(url) {
  414. return new Promise((resolve, reject) => {
  415. let a = uni.uploadFile({
  416. url: uni.getStorageSync('requestPath') + '/app/common/uploadOSS', // 仅为示例,非真实的接口地址
  417. filePath: url,
  418. name: 'file',
  419. formData: {
  420. user: 'test'
  421. },
  422. success: (res) => {
  423. resolve(JSON.parse(res.data))
  424. },
  425. fail: (err) => {
  426. uni.showToast({
  427. title: '上传失败',
  428. icon: 'error'
  429. })
  430. }
  431. });
  432. })
  433. }
  434. }
  435. };
  436. </script>
  437. <style scoped lang="scss">
  438. .formbox {
  439. background-color: #fff;
  440. padding: 0 30rpx;
  441. }
  442. .footer-btn {
  443. width: 100%;
  444. box-sizing: border-box;
  445. padding: 32rpx;
  446. display: flex;
  447. flex-direction: column;
  448. align-items: center;
  449. }
  450. .back-btn {
  451. margin-top: 40rpx;
  452. color: #FF5C03 !important;
  453. background: #fff !important;
  454. border: 1rpx solid #FF5C03;
  455. }
  456. .submit-btn {
  457. width: 100%;
  458. height: 88rpx;
  459. line-height: 88rpx;
  460. text-align: center;
  461. font-size: 30rpx;
  462. font-family: PingFang SC;
  463. font-weight: bold;
  464. color: #FFFFFF;
  465. background: #FF5C03;
  466. border-radius: 44rpx;
  467. border: 1rpx solid #FF5C03;
  468. &::after {
  469. border: none;
  470. }
  471. }
  472. .arrow-left {
  473. position: absolute;
  474. left: 24rpx;
  475. height: 88rpx;
  476. display: flex;
  477. align-items: center;
  478. justify-content: center;
  479. overflow: hidden;
  480. }
  481. .list-item {
  482. background-color: #fff;
  483. padding: 24rpx;
  484. border-bottom: 1rpx solid #f4f4f4;
  485. font-size: 15px;
  486. color: #333;
  487. display: flex;
  488. align-items: center;
  489. justify-content: space-between;
  490. }
  491. .title {
  492. color: rgba(0, 0, 0, .5);
  493. background-color: transparent;
  494. border-top: 1rpx solid #f4f4f4;
  495. }
  496. .imgitem {
  497. display: flex;
  498. align-items: center;
  499. justify-content: flex-start;
  500. .icon {
  501. min-width: 30rpx;
  502. margin-right: 15rpx;
  503. width: 30rpx;
  504. height: 30rpx;
  505. }
  506. }
  507. </style>