report.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. <template>
  2. <div class="w-full h-[100vh]">
  3. <!-- @open="openReportDropdownMenuRef" -->
  4. <van-dropdown-menu
  5. id="reportDropdownMenuRef"
  6. fixed
  7. ref="reportDropdownMenuRef"
  8. active-color="#FF9300"
  9. >
  10. <van-dropdown-item
  11. ref="reportItemRef"
  12. v-model="reportIndex"
  13. @change="onreportFilterClose"
  14. :options="
  15. reportList.map((item) => ({
  16. text: item?.typeName,
  17. value: item?.id
  18. }))
  19. "
  20. >
  21. <template #title class="relative" active-color="#FF9300">
  22. <div class="font-semibold text-2xl">
  23. <div @click.stop="goBack" class="absolute top-0 -left-135">
  24. <van-icon name="arrow-left" size="24" color="#000000" />
  25. </div>
  26. {{ title }}
  27. </div>
  28. </template>
  29. </van-dropdown-item>
  30. </van-dropdown-menu>
  31. <van-form @submit="onSubmit">
  32. <van-cell-group>
  33. <van-field
  34. :rules="[{ required: true, message: '请输入内容' }]"
  35. size="large"
  36. rows="2"
  37. readonly
  38. autosize
  39. type="textarea"
  40. v-model="form.elseTypeReason"
  41. :placeholder="
  42. form.elseTypeReason
  43. ? form.elseTypeReason
  44. : '对话中可能含有血腥、恐怖等内容,或者其他未提及的违规类型。'
  45. "
  46. label-align="top"
  47. >
  48. <template #label>
  49. <div>举报描述:{{ title }}</div>
  50. </template>
  51. </van-field>
  52. <van-field
  53. :rules="[{ required: true, message: '请输入违规描述' }]"
  54. required
  55. size="large"
  56. rows="6"
  57. autosize
  58. type="textarea"
  59. v-model="form.description"
  60. label="举报描述"
  61. maxlength="200"
  62. placeholder="请尽可能的描述存在的问题,如:让您感到不适的画面、或其他未提及的违规内容。"
  63. label-align="top"
  64. />
  65. <van-field
  66. id="image"
  67. class="image"
  68. style="background-color: white"
  69. required
  70. size="large"
  71. name="uploader"
  72. label="图片证据"
  73. label-align="top"
  74. :rules="[{ required: true, message: '请至少上传一张图片' }]"
  75. >
  76. <template #input>
  77. <div class="w-full flex justify-start items-start flex-wrap">
  78. <template v-if="form.image.length">
  79. <div
  80. v-for="(item, index) in form.image"
  81. :key="`img${index}`"
  82. class="shrink-0 relative w-80 h-80 mr-7 rounded-xl overflow-hidden"
  83. >
  84. <img class="w-full h-full object-cover" :src="item" alt="" />
  85. <div
  86. @click="deleteImage(index)"
  87. class="absolute z-10 top-0 right-0 w-20 rounded-bl-md h-20 bg-black/[0.4] flex justify-center items-center"
  88. >
  89. <span class="icon iconfont text-white" style="font-size: 16px">&#xe7fc;</span>
  90. </div>
  91. </div>
  92. </template>
  93. <div
  94. @click="handleChangeAvatar"
  95. class="border shrink-0 w-80 h-80 rounded-xl bg-[#F3F3F3] flex justify-center flex-wrap items-center"
  96. >
  97. <div>
  98. <span class="iconfont icon-plus text-black/[0.4]" style="font-size: 18px"></span>
  99. <p class="leading-3xl py-0 w-full text-sm text-center text-black/[0.4]">
  100. {{ form.image?.length }}/3
  101. </p>
  102. </div>
  103. </div>
  104. </div>
  105. <!-- <div
  106. class="border w-80 h-80 rounded-xl bg-[#F3F3F3] flex justify-center flex-wrap items-center"
  107. >
  108. <div @click="handleChangeAvatar">
  109. <span class="iconfont icon-plus text-black/[0.4]" style="font-size: 18px"></span>
  110. <p class="leading-3xl py-0 w-full text-sm text-center text-black/[0.4]">0/3</p>
  111. </div>
  112. </div> -->
  113. </template>
  114. </van-field>
  115. </van-cell-group>
  116. <div class="w-full fixed bottom-0 left-0 mt-90 px-16 pt-16 pb-40 box-border">
  117. <van-button
  118. size="large"
  119. round
  120. :color="isBtnDisabled ? '#A6A6A6' : '#FF9300'"
  121. class="font-semibold"
  122. block
  123. @click="handleReport"
  124. :loading="isSubmiting"
  125. >
  126. <!-- @click="isBtnDisabled ? handleReport : () => {}" -->
  127. 提交
  128. </van-button>
  129. </div>
  130. </van-form>
  131. </div>
  132. </template>
  133. <script setup>
  134. const route = useRoute()
  135. const router = useRouter()
  136. const goBack = () => router.back()
  137. definePageMeta({
  138. layout: false
  139. })
  140. const TEXT = '举报类型'
  141. // 刷新次数
  142. const reportIndex = ref('')
  143. const loading = ref(false)
  144. const title = ref(TEXT)
  145. const reportDropdownMenuRef = ref(null)
  146. const reportItemRef = ref(null)
  147. const form = reactive({
  148. typeId: null,
  149. objectType: computed(() => (route?.query?.objectType == 2 ? 2 : 1)),
  150. elseTypeReason: null,
  151. description: null,
  152. image: []
  153. })
  154. const { open, onChange } = useFileDialog({
  155. accept: '.png,.png,.jpeg,.JPG,Png '
  156. })
  157. function handleChangeAvatar() {
  158. open()
  159. }
  160. onChange(async (files) => {
  161. if (!files.length) return
  162. const formData = new FormData()
  163. formData.append('uploadFile', files[0])
  164. formData.append('asImage', true)
  165. formData.append('fieldName', 'image')
  166. const maxSize = 5 * 1024 * 1024 // 10 MB
  167. if (form.image.length <= 3) {
  168. if (files[0].size > maxSize) {
  169. showToast('上传图片过大,请重新上传')
  170. return
  171. } else {
  172. try {
  173. showLoadingToast({
  174. message: '图片上传中...',
  175. duration: 1000000
  176. })
  177. const { data } = await request('/website/tourComplait/upload', {
  178. method: 'post',
  179. body: formData
  180. })
  181. form.image.push(data.fileUrl)
  182. closeToast()
  183. showToast('图片上传成功')
  184. } catch (error) {
  185. form.image.push({
  186. url: files[0].name,
  187. status: 'failed',
  188. isImage: true,
  189. message: '上传失败',
  190. imageFit: 'contain'
  191. })
  192. closeToast()
  193. showToast('图片上传失败')
  194. console.log('图片上传失败')
  195. }
  196. }
  197. } else {
  198. showToast('最多上传图片数量3张')
  199. }
  200. })
  201. // 删除图片
  202. const deleteImage = (index) => {
  203. form.image = form.image.filter((it, filterIndex) => filterIndex != index)
  204. }
  205. const reportList = ref([])
  206. // 下拉菜单的方法
  207. function onreportFilterClose(value) {
  208. form.elseTypeReason = '55555'
  209. console.log(value, '12')
  210. reportIndex.value = value
  211. let el = reportList.find((item) => item?.id == value)
  212. console.log(el, 'el')
  213. title.value = el.typeName
  214. form.elseTypeReason = el.description
  215. }
  216. function openReportDropdownMenuRef() {
  217. nextTick(() => {
  218. reportItemRef.value?.toggle(true)
  219. })
  220. }
  221. // 获取举报类型
  222. const getreportType = async () => {
  223. try {
  224. let { data } = await request('/website/tourComplaintType/getTypeList')
  225. if (Array.isArray(data) && data?.length) {
  226. reportIndex.value = data[0]?.id
  227. form.typeId = data[0]?.id
  228. title.value = data[0]?.typeName
  229. form.elseTypeReason = '5555'
  230. reportList.value = data
  231. } else {
  232. reportList.value = []
  233. }
  234. } catch (err) {}
  235. }
  236. const isBtnDisabled = computed(() => {
  237. return !form.elseTypeReason || !form.description || !form.image.length != 0
  238. })
  239. const isSubmiting = ref(false)
  240. const handleReport = async () => {
  241. try {
  242. isSubmiting.value = true
  243. if (form.objectType == 2) {
  244. // form.groupId = route.query.groupId
  245. form.groupId = '1876571259412688897'
  246. } else {
  247. form.userId = route.query.userId
  248. }
  249. let { data } = await request('/website/tourComplait/add', {
  250. method: 'post',
  251. body: form
  252. })
  253. if (data) {
  254. showSuccessToast('操作成功')
  255. }
  256. isSubmiting.value = false
  257. } catch (err) {
  258. } finally {
  259. isSubmiting.value = false
  260. }
  261. }
  262. onMounted(() => {
  263. getreportType()
  264. })
  265. useSeoMeta({
  266. title: TEXT
  267. })
  268. </script>
  269. <style lang="scss" scoped>
  270. ::v-deep .van-field__body {
  271. background-color: #f3f3f3;
  272. border-radius: 8px;
  273. padding: 12px;
  274. padding-bottom: 20px;
  275. }
  276. ::v-deep .image .van-field__value .van-field__body {
  277. background-color: #fff !important;
  278. padding: 0;
  279. }
  280. ::v-deep .van-field__label {
  281. font-weight: 600;
  282. }
  283. ::v-deep .van-field__label--required::after {
  284. margin-left: 2px;
  285. color: var(--van-field-required-mark-color);
  286. content: '*';
  287. }
  288. ::v-deep .van-field__label--required::before {
  289. content: '';
  290. }
  291. </style>