pcSubmit.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <template>
  2. <div class="pcSubmit">
  3. <a-form layout="vertical" :model="formData" ref="formRef" :rules="rules">
  4. <a-form-item name="problemDesc">
  5. <div class="myTitle required" slot="label"><span class="number">01</span>{{ t('feedback.title1') }}</div>
  6. <a-textarea :autoSize="{ minRows: 3, maxRows: 6 }" v-model:value="formData.problemDesc" :placeholder="t('feedback.settext')" />
  7. </a-form-item>
  8. <a-form-item name="problemFile" style="margin-top: 32px">
  9. <a-upload
  10. v-model:file-list="formData.problemDescImgs"
  11. accept=".jpg,.png,.mp4"
  12. action="/service/sale/upload/file"
  13. list-type="picture-card"
  14. :before-upload="beforeUpload"
  15. >
  16. <div>
  17. <PlusOutlined />
  18. <div style="margin-top: 8px">{{ t('feedback.upload') }}</div>
  19. </div>
  20. </a-upload>
  21. <div class="tips">{{ t('feedback.fileTips') }}</div>
  22. </a-form-item>
  23. <a-form-item name="solution">
  24. <div class="myTitle required" slot="label"><span class="number">02</span>{{ t('feedback.title2') }}</div>
  25. <a-textarea :autoSize="{ minRows: 3, maxRows: 6 }" v-model:value="formData.solution" :placeholder="t('feedback.settext')" />
  26. </a-form-item>
  27. <a-form-item name="problemFile" style="margin-top: 32px">
  28. <a-upload v-model:file-list="formData.solutionImgs" action="/service/sale/upload/file" list-type="picture-card">
  29. <div>
  30. <PlusOutlined />
  31. <div style="margin-top: 8px">{{ t('feedback.upload') }}</div>
  32. </div>
  33. </a-upload>
  34. <div class="tips">{{ t('feedback.fileTips') }}</div>
  35. </a-form-item>
  36. <a-form-item name="industryOptionId">
  37. <div class="myTitle required" slot="label"><span class="number">03</span>{{ t('feedback.title3') }}</div>
  38. <a-select
  39. key="industryOptionId"
  40. v-model:value="formData.industryOptionId"
  41. :placeholder="t('feedback.setselcet')"
  42. :options="propsOptions.industryOptionId"
  43. />
  44. </a-form-item>
  45. <a-form-item name="hardwareOptionId">
  46. <div class="myTitle required" slot="label"><span class="number">04</span>{{ t('feedback.title4') }}</div>
  47. <a-select
  48. key="hardwareOptionId"
  49. v-model:value="formData.hardwareOptionId"
  50. :placeholder="t('feedback.setselcet')"
  51. :options="propsOptions.hardwareOptionId"
  52. />
  53. </a-form-item>
  54. <a-form-item name="softwareOptionId">
  55. <div class="myTitle required" slot="label"><span class="number">05</span>{{ t('feedback.title5') }}</div>
  56. <a-select
  57. key="softwareOptionId"
  58. v-model:value="formData.softwareOptionId"
  59. :placeholder="t('feedback.setselcet')"
  60. :options="propsOptions.softwareOptionId"
  61. />
  62. </a-form-item>
  63. <a-form-item>
  64. <div class="myTitle" slot="label"><span class="number">06</span>{{ t('feedback.title6') }}</div>
  65. <a-input v-model:value="formData.nickName" :placeholder="t('feedback.settext')" />
  66. </a-form-item>
  67. <a-form-item>
  68. <div class="myTitle" slot="label"><span class="number">07</span>{{ t('feedback.title61') }}</div>
  69. <a-input v-model:value="formData.phone" :placeholder="t('feedback.settext')" />
  70. </a-form-item>
  71. <a-form-item>
  72. <div class="myTitle" slot="label"><span class="number">08</span>{{ t('feedback.title7') }}</div>
  73. <a-select
  74. v-model:value="formData.country"
  75. :filterOption="filterOption"
  76. :options="countryOption"
  77. showSearch
  78. :placeholder="t('feedback.setselcet')"
  79. />
  80. <!-- <a-cascader v-model:value="formData.countries" :options="options" placeholder="Please select" /> -->
  81. </a-form-item>
  82. <a-form-item v-if="formData.country == '中国' || formData.country == 'China'">
  83. <div class="myTitle" slot="label"
  84. ><span class="number">{{ formData.country == '中国' || formData.country == 'China' ? '09' : '08' }}</span
  85. >{{ t('feedback.title71') }}</div
  86. >
  87. <a-cascader v-model:value="formData.countries" :options="options" :placeholder="t('feedback.setselcet')" />
  88. </a-form-item>
  89. <a-form-item>
  90. <div class="myTitle" slot="label"
  91. ><span class="number">{{ formData.country == '中国' || formData.country == 'China' ? '10' : '09' }}</span
  92. >{{ t('feedback.title8') }}</div
  93. >
  94. <van-rate color="#FADB14" size="30" void-color="#D9D9D9" :allow-half="true" v-model="formData.score" :placeholder="t('feedback.setselcet')" />
  95. </a-form-item>
  96. <a-form-item>
  97. <div class="myTitle" slot="label"
  98. ><span class="number">{{ formData.country == '中国' || formData.country == 'China' ? '11' : '10' }}</span
  99. >{{ t('feedback.title9') }}</div
  100. >
  101. <a-input v-model:value="formData.scoreReason" :placeholder="t('feedback.settext')" />
  102. </a-form-item>
  103. <a-form-item style="text-align: center">
  104. <a-button class="w-160px" style="background-color: #00b3ec" type="primary" size="large" @click="onSubmit">{{
  105. t('feedback.Submit')
  106. }}</a-button>
  107. </a-form-item>
  108. </a-form>
  109. </div>
  110. </template>
  111. <script setup>
  112. import { ref } from 'vue';
  113. import { PlusOutlined } from '@ant-design/icons-vue';
  114. import cityList from './area.json';
  115. import countryList from './country.json';
  116. const props = defineProps(['formData', 'columns']);
  117. import { message, Upload } from 'ant-design-vue';
  118. import { useI18n } from 'vue-i18n';
  119. const { t } = useI18n();
  120. const emit = defineEmits(['submit']);
  121. // eslint-disable-next-line vue/no-setup-props-destructure
  122. const formData = ref({
  123. problemDesc: '',
  124. problemDescImgs: [],
  125. hardwareOptionId: null,
  126. softwareOptionId: null,
  127. industryOptionId: null,
  128. solution: '',
  129. solutionImgs: [],
  130. nickName: '',
  131. phone: '',
  132. score: 0,
  133. scoreReason: '',
  134. country: '',
  135. address: '',
  136. countries: [],
  137. });
  138. console.log('formData', formData);
  139. // eslint-disable-next-line vue/no-setup-props-destructure
  140. const propsOptions = props.columns;
  141. const formRef = ref(null);
  142. const rules = {
  143. problemDesc: [{ required: true, message: t('feedback.settext') + t('feedback.title1'), trigger: 'change' }],
  144. solution: [{ required: true, message: t('feedback.settext') + t('feedback.title2'), trigger: 'change' }],
  145. softwareOptionId: [{ required: true, message: t('feedback.setselcet') + t('feedback.title5'), trigger: 'change' }],
  146. industryOptionId: [{ required: true, message: t('feedback.setselcet') + t('feedback.title3'), trigger: 'change' }],
  147. hardwareOptionId: [{ required: true, message: t('feedback.setselcet') + t('feedback.title4'), trigger: 'change' }],
  148. };
  149. const countryOption = countryList.map((ele) => {
  150. return { value: ele.chinese, label: ele.chinese, english: ele.english };
  151. });
  152. function filterOption(inputValue, option) {
  153. return (
  154. option.label.toLowerCase().indexOf(inputValue.toLowerCase()) >= 0 ||
  155. option.english.toLowerCase().indexOf(inputValue.toLowerCase()) >= 0
  156. );
  157. }
  158. const options = cityList.map((ele) => {
  159. return {
  160. value: ele.name,
  161. label: ele.name,
  162. children: ele.city.map((element) => {
  163. return {
  164. value: element.name,
  165. label: element.name,
  166. };
  167. }),
  168. };
  169. });
  170. const beforeUpload = (file) => {
  171. console.log('beforeUpload', file);
  172. const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'video/mp4';
  173. if (!isJpgOrPng) {
  174. message.error(t('feedback.fileTips'));
  175. return false;
  176. }
  177. const isLt2M = file.size / 1024 / 1024 < 2;
  178. const isLt50M = file.size / 1024 / 1024 < 50;
  179. if (!isLt2M && (file.type === 'image/jpeg' || file.type === 'image/png')) {
  180. message.error(t('feedback.fileTips'));
  181. return false;
  182. }
  183. if (!isLt50M && file.type === 'video/mp4') {
  184. message.error(t('feedback.fileTips'));
  185. return Upload.LIST_IGNORE;
  186. }
  187. return file.type === 'video/mp4' ? isLt50M && isJpgOrPng : isJpgOrPng && isLt2M;
  188. };
  189. const onSubmit = () => {
  190. console.log('values', formRef.value.validate());
  191. formRef.value
  192. .validate()
  193. .then(() => {
  194. emit('submit', formData.value);
  195. console.log('values', formData);
  196. })
  197. .catch((error) => {
  198. console.log('error', error);
  199. });
  200. };
  201. </script>
  202. <style lang="scss" scoped>
  203. .myTitle {
  204. position: relative;
  205. margin-bottom: 14px;
  206. margin-top: 32px;
  207. .number {
  208. font-size: 16px;
  209. font-family: Microsoft YaHei, Microsoft YaHei;
  210. font-weight: bold;
  211. color: #00b3ec;
  212. }
  213. span {
  214. font-size: 16px;
  215. font-family: Microsoft YaHei, Microsoft YaHei;
  216. font-weight: 400;
  217. color: #333333;
  218. line-height: 19px;
  219. margin-right: 7px;
  220. }
  221. }
  222. .tips {
  223. font-size: 14px;
  224. font-family: Microsoft YaHei, Microsoft YaHei;
  225. font-weight: 400;
  226. color: #cccccc;
  227. line-height: 16px;
  228. margin-top: 8px;
  229. }
  230. .required {
  231. &::before {
  232. display: inline-block;
  233. margin-inline-end: 4px;
  234. color: #ff4d4f;
  235. font-size: 14px;
  236. font-family: SimSun, sans-serif;
  237. line-height: 1;
  238. content: '*';
  239. }
  240. }
  241. </style>