鸿宇研学生前端代码
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.

321 lines
7.4 KiB

  1. <template>
  2. <view>
  3. <uv-popup ref="popup" mode="bottom" bgColor="none" @change="onPopupChange">
  4. <view class="popup__view" v-if="isShow">
  5. <view class="flex header">
  6. <view class="title">评价</view>
  7. <button class="btn" @click="close">关闭</button>
  8. </view>
  9. <view class="form">
  10. <uv-form
  11. ref="form"
  12. :model="form"
  13. :rules="rules"
  14. errorType="toast"
  15. >
  16. <view class="section">
  17. <productCard :data="detail"></productCard>
  18. </view>
  19. <view class="section">
  20. <view class="form-item">
  21. <uv-form-item prop="processScore" :customStyle="formItemStyle">
  22. <view class="flex row">
  23. <view class="form-item-label">行程</view>
  24. <view class="form-item-content">
  25. <formRate v-model="form.processScore"></formRate>
  26. </view>
  27. </view>
  28. </uv-form-item>
  29. </view>
  30. <view class="form-item">
  31. <uv-form-item prop="spotScore" :customStyle="formItemStyle">
  32. <view class="flex row">
  33. <view class="form-item-label">景点</view>
  34. <view class="form-item-content">
  35. <formRate v-model="form.spotScore"></formRate>
  36. </view>
  37. </view>
  38. </uv-form-item>
  39. </view>
  40. <view class="form-item">
  41. <uv-form-item prop="teacherScore" :customStyle="formItemStyle">
  42. <view class="flex row">
  43. <view class="form-item-label">导师</view>
  44. <view class="form-item-content">
  45. <formRate v-model="form.teacherScore"></formRate>
  46. </view>
  47. </view>
  48. </uv-form-item>
  49. </view>
  50. </view>
  51. <view class="form-item">
  52. <uv-form-item prop="content" :customStyle="formItemStyle">
  53. <view class="form-item-content">
  54. <view class="tags">
  55. <view
  56. v-for="(item, oIdx) in options" :key="oIdx"
  57. :class="['tag', item === form.content ? 'is-active' : '']"
  58. @click="onSelectContent(item)"
  59. >
  60. {{ item }}
  61. </view>
  62. </view>
  63. </view>
  64. </uv-form-item>
  65. </view>
  66. </uv-form>
  67. </view>
  68. <view class="footer">
  69. <button class="flex btn" @click="onPublish">发布</button>
  70. </view>
  71. </view>
  72. </uv-popup>
  73. </view>
  74. </template>
  75. <script>
  76. import productCard from '@/pages_order/order/components/productCard.vue'
  77. import formRate from '@/pages_order/components/formRate.vue'
  78. export default {
  79. components: {
  80. productCard,
  81. formRate,
  82. },
  83. data() {
  84. return {
  85. isShow: false,
  86. id: null,
  87. // todo: fetch
  88. detail: {},
  89. form: {
  90. processScore: null,
  91. spotScore: null,
  92. teacherScore: null,
  93. content: null,
  94. },
  95. rules: {
  96. 'processScore': {
  97. type: 'number',
  98. required: true,
  99. message: '请为行程打分',
  100. },
  101. 'spotScore': {
  102. type: 'number',
  103. required: true,
  104. message: '请为景点打分',
  105. },
  106. 'teacherScore': {
  107. type: 'number',
  108. required: true,
  109. message: '请为导师打分',
  110. },
  111. 'content': {
  112. type: 'string',
  113. required: true,
  114. message: '请选择评语',
  115. },
  116. },
  117. // todo: fetch
  118. options: [],
  119. }
  120. },
  121. methods: {
  122. async getData() {
  123. // todo: fetch order product
  124. },
  125. async open(id, detail) {
  126. this.id = id
  127. this.detail = detail
  128. // todo: fetch order product
  129. // await this.getData()
  130. this.form = {
  131. processScore: null,
  132. spotScore: null,
  133. teacherScore: null,
  134. content: null,
  135. }
  136. this.$refs.popup.open()
  137. },
  138. close() {
  139. this.$refs.popup.close()
  140. },
  141. onPopupChange(e) {
  142. this.isShow = e.show
  143. },
  144. onSelectContent(content) {
  145. this.form.content = content
  146. },
  147. async onPublish() {
  148. try {
  149. await this.$refs.form.validate()
  150. const {
  151. processScore,
  152. spotScore,
  153. teacherScore,
  154. content,
  155. } = this.form
  156. const params = {
  157. orderId: this.id,
  158. processScore,
  159. spotScore,
  160. teacherScore,
  161. content,
  162. }
  163. await this.$fetch('addComment', params)
  164. uni.showToast({
  165. icon: 'success',
  166. title: '发布成功',
  167. });
  168. this.$emit('submitted')
  169. this.close()
  170. } catch (err) {
  171. console.log('onSave err', err)
  172. }
  173. },
  174. },
  175. }
  176. </script>
  177. <style lang="scss" scoped>
  178. .popup__view {
  179. width: 100vw;
  180. display: flex;
  181. flex-direction: column;
  182. box-sizing: border-box;
  183. background: #FFFFFF;
  184. border-top-left-radius: 32rpx;
  185. border-top-right-radius: 32rpx;
  186. }
  187. .header {
  188. position: relative;
  189. width: 100%;
  190. padding: 24rpx 0;
  191. box-sizing: border-box;
  192. border-bottom: 2rpx solid #EEEEEE;
  193. .title {
  194. font-family: PingFang SC;
  195. font-weight: 500;
  196. font-size: 34rpx;
  197. line-height: 1.4;
  198. color: #181818;
  199. }
  200. .btn {
  201. font-family: PingFang SC;
  202. font-weight: 500;
  203. font-size: 32rpx;
  204. line-height: 1.4;
  205. color: #8B8B8B;
  206. position: absolute;
  207. top: 26rpx;
  208. left: 40rpx;
  209. }
  210. }
  211. .section {
  212. & + & {
  213. margin-top: 24rpx;
  214. }
  215. }
  216. .form {
  217. max-height: 75vh;
  218. padding: 32rpx 40rpx;
  219. box-sizing: border-box;
  220. overflow-y: auto;
  221. &-item {
  222. &-label {
  223. margin-bottom: 14rpx;
  224. display: flex;
  225. align-items: center;
  226. font-family: PingFang SC;
  227. font-weight: 400;
  228. font-size: 26rpx;
  229. line-height: 1.4;
  230. color: #181818;
  231. .icon {
  232. margin-right: 8rpx;
  233. width: 16rpx;
  234. height: auto;
  235. }
  236. }
  237. &-content {
  238. }
  239. }
  240. }
  241. .row {
  242. justify-content: space-between;
  243. padding: 4rpx 0;
  244. & + & {
  245. margin-top: 4rpx;
  246. }
  247. .form-label {
  248. margin: 0;
  249. }
  250. }
  251. .tags {
  252. display: grid;
  253. grid-template-columns: repeat(2, 1fr);
  254. gap: 24rpx;
  255. }
  256. .tag {
  257. min-width: 0;
  258. padding: 16rpx;
  259. font-size: 26rpx;
  260. line-height: 1.4;
  261. color: #252545;
  262. background: #F5F8FF;
  263. border-radius: 24rpx;
  264. &.is-active {
  265. color: #FFFFFF;
  266. background: #00A9FF;
  267. }
  268. }
  269. .footer {
  270. width: 100%;
  271. padding: 32rpx 40rpx;
  272. box-sizing: border-box;
  273. border-top: 2rpx solid #F1F1F1;
  274. .btn {
  275. width: 100%;
  276. padding: 14rpx 0;
  277. box-sizing: border-box;
  278. font-family: PingFang SC;
  279. font-weight: 500;
  280. font-size: 36rpx;
  281. line-height: 1.4;
  282. color: #FFFFFF;
  283. background-image: linear-gradient(to right, #21FEEC, #019AF9);
  284. border: 2rpx solid #00A9FF;
  285. border-radius: 41rpx;
  286. }
  287. }
  288. </style>