|
@@ -0,0 +1,361 @@
|
|
|
+<template>
|
|
|
+ <div class="mcSubmit">
|
|
|
+ <van-form @submit="onSubmit" style="background: #fff">
|
|
|
+ <van-cell-group style="margin: none" inset>
|
|
|
+ <div class="myTitle required"><span class="number">01</span>{{ t('feedback.title1') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.problemDesc"
|
|
|
+ label-align="top"
|
|
|
+ name="故障描述"
|
|
|
+ label=""
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ rows="2"
|
|
|
+ autoSize
|
|
|
+ :max-count="5"
|
|
|
+ type="textarea"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ :rules="[{ required: true, message: t('feedback.settext') + t('feedback.title1') }]"
|
|
|
+ :placeholder="t('feedback.settext')"
|
|
|
+ />
|
|
|
+ <van-field name="uploader" label-align="top">
|
|
|
+ <template #input>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <van-uploader
|
|
|
+ :before-read="beforeRead"
|
|
|
+ :after-read="clzpAfterRead"
|
|
|
+ accept=".jpg,.png,.mp4"
|
|
|
+ :max-count="6"
|
|
|
+ v-model="formData.problemDescImgs"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="tips">{{ t('feedback.fileTips') }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ <div class="myTitle required"><span class="number">02</span>{{ t('feedback.title2') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.solution"
|
|
|
+ label-align="top"
|
|
|
+ name="故障描述"
|
|
|
+ label=""
|
|
|
+ rows="2"
|
|
|
+ autoSize
|
|
|
+ type="textarea"
|
|
|
+ maxlength="500"
|
|
|
+ show-word-limit
|
|
|
+ :rules="[{ required: true, message: t('feedback.settext') + t('feedback.title2') }]"
|
|
|
+ :placeholder="t('feedback.settext')"
|
|
|
+ />
|
|
|
+ <van-field name="uploader" label-align="top">
|
|
|
+ <template #input>
|
|
|
+ <div>
|
|
|
+ <div>
|
|
|
+ <van-uploader :before-read="beforeRead" :after-read="clzpAfterRead" :max-count="6" v-model="formData.solutionImgs" />
|
|
|
+ </div>
|
|
|
+ <div class="tips">{{ t('feedback.fileTips') }}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ <div class="myTitle required"><span class="number">03</span>{{ t('feedback.title3') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.industryOptionId"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="picker"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.setselcet')"
|
|
|
+ :rules="[{ required: true, message: t('feedback.setselcet') + t('feedback.title3') }]"
|
|
|
+ @click="showPicker.industryOptionId = true"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="showPicker.industryOptionId" position="bottom">
|
|
|
+ <van-picker
|
|
|
+ :columns="propsOptions.industryOptionId"
|
|
|
+ @confirm="(val) => onConfirm(val, 'industryOptionId')"
|
|
|
+ @cancel="showPicker.industryOptionId = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ <div class="myTitle required"><span class="number">04</span>{{ t('feedback.title4') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.hardwareOptionId"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="picker"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.setselcet')"
|
|
|
+ :rules="[{ required: true, message: t('feedback.setselcet') + t('feedback.title4') }]"
|
|
|
+ @click="showPicker.hardwareOptionId = true"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="showPicker.hardwareOptionId" position="bottom">
|
|
|
+ <van-picker
|
|
|
+ :columns="propsOptions.hardwareOptionId"
|
|
|
+ @confirm="(val) => onConfirm(val, 'hardwareOptionId')"
|
|
|
+ @cancel="showPicker.hardwareOptionId = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ <div class="myTitle required"><span class="number">05</span>{{ t('feedback.title5') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.softwareOptionId"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="picker"
|
|
|
+ label=""
|
|
|
+ maxlength="30"
|
|
|
+ :placeholder="t('feedback.setselcet')"
|
|
|
+ :rules="[{ required: true, message: t('feedback.setselcet') + t('feedback.title5') }]"
|
|
|
+ @click="showPicker.softwareOptionId = true"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="showPicker.softwareOptionId" position="bottom">
|
|
|
+ <van-picker
|
|
|
+ :columns="propsOptions.softwareOptionId"
|
|
|
+ @confirm="(val) => onConfirm(val, 'softwareOptionId')"
|
|
|
+ @cancel="showPicker.softwareOptionId = false"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ <div class="myTitle"><span class="number">06</span>{{ t('feedback.title6') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.nickName"
|
|
|
+ label-align="top"
|
|
|
+ name="联系电话"
|
|
|
+ maxlength="15"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.settext')"
|
|
|
+ />
|
|
|
+ <div class="myTitle"><span class="number">07</span>{{ t('feedback.title61') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.phone"
|
|
|
+ label-align="top"
|
|
|
+ name="联系电话"
|
|
|
+ maxlength="11"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.settext')"
|
|
|
+ />
|
|
|
+ <div class="myTitle"><span class="number">08</span>{{ t('feedback.title7') }}</div>
|
|
|
+ <van-field
|
|
|
+ v-model="formData.country"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="picker"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.setselcet')"
|
|
|
+ @click="showPicker.country = true"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="showPicker.country" position="bottom">
|
|
|
+ <van-picker :columns="columnsCountry" @confirm="(val) => onConfirm(val, 'country')" @cancel="showPicker.country = false" />
|
|
|
+ </van-popup>
|
|
|
+ <div class="myTitle" v-if="formData.country == '中国'"
|
|
|
+ ><span class="number">{{ formData.country == '中国' ? '09' : '08' }}</span
|
|
|
+ >{{ t('feedback.title71') }}</div
|
|
|
+ >
|
|
|
+ <van-field
|
|
|
+ v-if="formData.country == '中国'"
|
|
|
+ v-model="formData.city"
|
|
|
+ is-link
|
|
|
+ readonly
|
|
|
+ name="area"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.setselcet')"
|
|
|
+ @click="showPicker.city = true"
|
|
|
+ />
|
|
|
+ <van-popup v-model:show="showPicker.city" position="bottom">
|
|
|
+ <van-cascader
|
|
|
+ v-model="cascaderValue"
|
|
|
+ title="请选择所在地区"
|
|
|
+ :options="columnsCity"
|
|
|
+ @close="showPicker.city = false"
|
|
|
+ @finish="onFinish"
|
|
|
+ />
|
|
|
+ </van-popup>
|
|
|
+ <div class="myTitle"
|
|
|
+ ><span class="number">{{ formData.country == '中国' ? '10' : '09' }}</span
|
|
|
+ >{{ t('feedback.title8') }}</div
|
|
|
+ >
|
|
|
+ <van-field name="rate" label="">
|
|
|
+ <template #input>
|
|
|
+ <van-rate color="#FADB14" void-color="#D9D9D9" :allow-half="true" v-model="formData.score" />
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
+ <div class="myTitle"
|
|
|
+ ><span class="number">{{ formData.country == '中国' ? '11' : '10' }}</span
|
|
|
+ >{{ t('feedback.title9') }}</div
|
|
|
+ >
|
|
|
+ <van-field
|
|
|
+ v-model="formData.scoreReason"
|
|
|
+ label-align="top"
|
|
|
+ name="联系电话"
|
|
|
+ maxlength="30"
|
|
|
+ label=""
|
|
|
+ :placeholder="t('feedback.settext')"
|
|
|
+ />
|
|
|
+ <div style="margin: 16px; background-color: #f5f5f5">
|
|
|
+ <van-button style="height: 44px" block color="#00B3EC" type="primary" native-type="submit"> 提交 </van-button>
|
|
|
+ </div>
|
|
|
+ </van-cell-group>
|
|
|
+ </van-form>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+ import { ref } from 'vue';
|
|
|
+ import cityList from './area.json';
|
|
|
+ import countryList from './country.json';
|
|
|
+ import axios from 'axios';
|
|
|
+ const areaList = ref({});
|
|
|
+ const props = defineProps(['formData', 'columns']);
|
|
|
+ const emit = defineEmits(['submit']);
|
|
|
+ const propsOptions = props.columns;
|
|
|
+ const loading = ref(false);
|
|
|
+ const setObjId = ref({})
|
|
|
+ const formData = ref({
|
|
|
+ problemDesc: '',
|
|
|
+ problemDescImgs: [],
|
|
|
+ hardwareOptionId: null,
|
|
|
+ softwareOptionId: null,
|
|
|
+ industryOptionId: null,
|
|
|
+ solution: '',
|
|
|
+ solutionImgs: [],
|
|
|
+ nickName: '',
|
|
|
+ phone: '',
|
|
|
+ address: '',
|
|
|
+ score: 0,
|
|
|
+ scoreReason: '',
|
|
|
+ });
|
|
|
+ import { useI18n } from 'vue-i18n';
|
|
|
+ const { t } = useI18n();
|
|
|
+ const showPicker = ref({
|
|
|
+ country: false,
|
|
|
+ hardwareOptionId: false,
|
|
|
+ softwareOptionId: false,
|
|
|
+ city: false,
|
|
|
+ });
|
|
|
+ const columnsCountry = countryList.map((ele) => {
|
|
|
+ return { text: ele.chinese, value: ele.chinese };
|
|
|
+ });
|
|
|
+ const columnsCity = cityList.map((ele) => {
|
|
|
+ return {
|
|
|
+ text: ele.name,
|
|
|
+ value: ele.name,
|
|
|
+ children: ele.city.map((element) => {
|
|
|
+ return {
|
|
|
+ text: element.name,
|
|
|
+ value: element.name,
|
|
|
+ };
|
|
|
+ }),
|
|
|
+ };
|
|
|
+ });
|
|
|
+ // 全部选项选择完毕后,会触发 finish 事件
|
|
|
+ const onFinish = ({ selectedOptions }, b) => {
|
|
|
+ showPicker.value.city = false;
|
|
|
+ formData.value.city = selectedOptions.map((option) => option.text).join('/');
|
|
|
+ };
|
|
|
+ const onConfirm = ({ selectedOptions, selectedValues }, b) => {
|
|
|
+ formData.value[b] = selectedOptions[0].text;
|
|
|
+ setObjId.value[b] = selectedValues.join(',');
|
|
|
+ showPicker.value[b] = false;
|
|
|
+ };
|
|
|
+ const onSubmit = () => {
|
|
|
+ formData.value = {
|
|
|
+ ...formData.value,
|
|
|
+ ...setObjId.value,
|
|
|
+ }
|
|
|
+ emit('submit', formData.value);
|
|
|
+ };
|
|
|
+ const beforeUpload = (file) => {
|
|
|
+ console.log('beforeUpload', file);
|
|
|
+ const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
|
|
+ if (!isJpgOrPng) {
|
|
|
+ message.error('You can only upload JPG file!');
|
|
|
+ }
|
|
|
+ const isLt2M = file.size / 1024 / 1024 < 2;
|
|
|
+ if (!isLt2M) {
|
|
|
+ message.error('Image must smaller than 2MB!');
|
|
|
+ }
|
|
|
+ return isJpgOrPng && isLt2M;
|
|
|
+ }; //校验图片的格式
|
|
|
+ function beforeRead(file) {
|
|
|
+ if (!/(jpg|jpeg|png|JPG|PNG|mp4)/i.test(file.type)) {
|
|
|
+ showToast(t('feedback.upload'));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ //照片上传事件方法
|
|
|
+ function clzpAfterRead(file) {
|
|
|
+ // 上传状态提示开启
|
|
|
+ file.status = 'uploading';
|
|
|
+ file.message = '上传中...';
|
|
|
+ loading.value = true;
|
|
|
+ // 创建一个空对象实例
|
|
|
+ let formData = new FormData();
|
|
|
+ // 调用append()方法添加数据
|
|
|
+ formData.append('file', file.file);
|
|
|
+ axios({
|
|
|
+ url: '/service/sale/upload/file',
|
|
|
+ method: 'POST',
|
|
|
+ data: formData,
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'multipart/form-data',
|
|
|
+ },
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ loading.value = false;
|
|
|
+ let { data } = res;
|
|
|
+ if (data.code == 200) {
|
|
|
+ // 上传状态提示关闭
|
|
|
+ file.url = data.data;
|
|
|
+ file.file = '';
|
|
|
+ file.content = '';
|
|
|
+ file.status = 'done';
|
|
|
+ showToast('上传成功!');
|
|
|
+ }
|
|
|
+ console.log('formData.faultImg', formData, file);
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ loading.value = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+ .mcSubmit {
|
|
|
+ .tips {
|
|
|
+ font-size: 14px;
|
|
|
+ font-family: Source Han Sans CN, Source Han Sans CN;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #cccccc;
|
|
|
+ line-height: 16px;
|
|
|
+ margin-top: 15px;
|
|
|
+ }
|
|
|
+ .required {
|
|
|
+ &::before {
|
|
|
+ display: inline-block;
|
|
|
+ margin-inline-end: 4px;
|
|
|
+ color: #ff4d4f;
|
|
|
+ font-size: 14px;
|
|
|
+ font-family: SimSun, sans-serif;
|
|
|
+ line-height: 1;
|
|
|
+ content: '*';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .myTitle {
|
|
|
+ position: relative;
|
|
|
+ margin-top: 14px;
|
|
|
+ padding: 0 var(--van-cell-horizontal-padding);
|
|
|
+ .number {
|
|
|
+ font-size: 16px;
|
|
|
+ font-family: Microsoft YaHei, Microsoft YaHei;
|
|
|
+ font-weight: bold;
|
|
|
+ color: #00b3ec;
|
|
|
+ }
|
|
|
+ span {
|
|
|
+ font-size: 16px;
|
|
|
+ font-family: Microsoft YaHei, Microsoft YaHei;
|
|
|
+ font-weight: 400;
|
|
|
+ color: #333333;
|
|
|
+ line-height: 19px;
|
|
|
+ margin-right: 7px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|