Procházet zdrojové kódy

修改意见反馈

zs před 1 rokem
rodič
revize
801f50b075

+ 1 - 0
pagesMy/account/index.vue

@@ -265,6 +265,7 @@
 	.content {
 		display: flex;
 		flex-direction: column;
+		min-height: 100vh;
 		background-color: var(--f1Color);
 	}
 </style>

+ 199 - 24
pagesMy/opinion/index.vue

@@ -1,52 +1,227 @@
 <template>
 	<view class="content">
-		意见反馈
-		<up-overlay :show="show">
-			<login @showChange='showChange'></login>
-		</up-overlay>
+		<form @submit="formSubmit">
+			<view class="value other">
+				<view class="title">问题类型</view>
+				<view class="label">
+					<picker @change="typeChange" :range="typeList" range-key='label'>
+						<view class="picker">{{form.type_name||'请选择 >'}}</view>
+					</picker>
+					<span v-if="errors.type" class="error-message">{{ errors.type }}</span>
+				</view>
+			</view>
+			<view class="brief other margin">
+				<view class="title">问题描述</view>
+				<view class="label">
+					<textarea name='brief' :value="form.brief" placeholder="请写下您的建议,如功能需求、产品吐槽等,我们会努力改进" auto-height />
+					<span v-if="errors.brief" class="error-message">{{ errors.brief }}</span>
+				</view>
+			</view>
+			<view class="brief other margin">
+				<view class="title">图片(可上传三张)</view>
+				<view class="label">
+					<up-upload :fileList="form.file" @afterRead="afterRead" @delete="deletePic" name="icon" multiple
+						:maxCount="3"></up-upload>
+				</view>
+			</view>
+			<view class="button">
+				<button type="warn" size="mini" form-type="submit">保存</button>
+			</view>
+		</form>
+		<view class="view">查看历史反馈</view>
 	</view>
 </template>
 
 <script setup lang="ts">
-	import login from "@/components/login.vue"
+	import moment from 'moment';
 	import { inject, computed, ref } from 'vue';
 	//该依赖已内置不需要单独安装
 	import { onShow, onPullDownRefresh } from "@dcloudio/uni-app";
 	// 请求接口
 	const $api = inject('$api');
-	const $config = inject('$config');
-	// 基本信息
-	const config = ref({ logo: [], file: [] });
-	const list = ref([]);
-	const total = ref(0);
-	// 遮罩层
-	const show = ref(false);
+	const $apifile = inject('$apifile');
+	// 表单
+	const form = ref({ file: [] });
+	// 字典表
+	const typeList = ref([]);
+	const errors = ref({});
 	// user
 	const user = computed(() => {
 		return uni.getStorageSync('user');
 	})
 	onShow(async () => {
-		await searchConfig();
 		await searchOther();
-		await search();
-		if (!user.value) show.value = true
 	})
-	// config信息
-	const searchConfig = async () => {
-		config.value = uni.getStorageSync('config');
-	};
 	// 其他查询信息
-	const searchOther = async () => { };
-	// 查询
-	const search = async () => { };
-	const showChange = () => {
-		show.value = false
+	const searchOther = async () => {
+		let res;
+		// 问题类型
+		res = await $api(`dictData`, 'GET', { code: 'opinionType', is_use: '0' });
+		if (res.errcode === 0) typeList.value = res.data;
+	};
+	// 学历类型选择
+	const typeChange = (e) => {
+		const data = typeList.value[e.detail.value]
+		if (data) {
+			form.value.type = data.value
+			form.value.type_name = data.label
+		}
+	};
+	// 删除图片
+	const deletePic = (event) => {
+		const file = form.value.file.filter(i => i.url !== event.file.url)
+		form.value.file = file
+	};
+	// 新增图片
+	const afterRead = async (event) => {
+		const url = event.file[0].url
+		const result = await $apifile(`/web/learn_opinion/upload`, 'file', url, 'file');
+		if (result.errcode === 0) form.value.file = [...form.value.file, ...[result]]
+	};
+	// 自定义的验证函数
+	const validateObject = (obj : any) => {
+		const errors : any = {};
+		if (!obj.type || obj.type.trim() === '') {
+			errors.type = '请填写问题类型!';
+		}
+		if (!obj.brief || obj.brief.trim() === '') {
+			errors.brief = '请填写问题描述!';
+		}
+		// 如果有错误,返回错误对象
+		if (Object.keys(errors).length > 0) {
+			return errors;
+		}
+		// 如果没有错误,返回null或undefined
+		return null;
 	}
+	// 处理两个对象合并
+	const mergeObjectsWithoutDuplicates = async (obj1, obj2) => {
+		return Object.keys({ ...obj1, ...obj2 }).reduce((acc, key) => {
+			if (!acc.hasOwnProperty(key)) {
+				if (key == 'type_name') {
+					delete acc[key]
+				} else {
+					// 如果累加器对象(acc)中不存在该键,则添加它
+					acc[key] = obj1.hasOwnProperty(key) ? obj1[key] : obj2[key];
+				}
+			}
+			return acc;
+		}, {});
+	}
+	// 保存
+	const formSubmit = async (e) => {
+		// 调用验证函数
+		const data : any = await mergeObjectsWithoutDuplicates(e.detail.value, form.value);
+		const errorsInfo = await validateObject(data);
+		// 检查是否有错误
+		if (errorsInfo) {
+			errors.value = errorsInfo
+			// 遍历错误对象并显示错误信息
+			for (const key in errorsInfo) {
+				if (errorsInfo.hasOwnProperty(key)) {
+					console.error(`${key} 错误: ${errorsInfo[key]}`);
+				}
+			}
+		} else {
+			errors.value = {}
+			data.user = user.value._id
+			if (user.value.role_type == 'Student') data.userType = '1'
+			else data.userType = '0'
+			data.time = moment().format('YYYY-MM-DD HH:mm:ss')
+			const res = await $api(`opinion`, 'POST', data);
+			if (res.errcode == '0') {
+				uni.showToast({
+					title: '反馈成功!',
+					icon: 'success'
+				});
+				uni.navigateBack({
+					delta: 1
+				})
+			}
+		}
+	};
 </script>
 <style lang="scss" scoped>
 	.content {
 		display: flex;
 		flex-direction: column;
+		min-height: 100vh;
 		background-color: var(--f1Color);
+
+		.margin {
+			margin: 3vw 0 0 0;
+		}
+
+		.other {
+			padding: 3vw 2vw;
+			border-bottom: 1px solid var(--footColor);
+		}
+
+		.value {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			background-color: var(--mainColor);
+
+			.label {
+				text-align: right;
+
+				.input {
+					text-align: right;
+				}
+
+				.image {
+					width: 15vw;
+					height: 15vw;
+					border-radius: 20vw;
+				}
+
+				.error-message {
+					margin: 5px 0 0 0;
+					color: var(--ff0Color);
+					font-size: var(--font12Size);
+				}
+			}
+		}
+
+		.brief {
+			background-color: var(--mainColor);
+
+			.title {
+				margin: 0 0 2vw 0;
+			}
+
+			.label {
+				.error-message {
+					margin: 5px 0 0 0;
+					color: var(--ff0Color);
+					font-size: var(--font12Size);
+				}
+			}
+		}
+
+		.button {
+			text-align: center;
+			margin: 2vw 0 0 0;
+
+			button {
+				width: 80%;
+				font-size: var(--font16Size);
+				color: var(--mainColor);
+				background-color: var(--3c9Color);
+				border-radius: 10vw;
+				margin: 0 2vw;
+			}
+		}
+
+		.view {
+			width: 100%;
+			position: fixed;
+			bottom: 2vw;
+			left: 0;
+			text-align: center;
+			color: var(--3c9Color);
+			font-size: var(--font12Size);
+		}
 	}
 </style>

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 2567 - 2567
unpackage/dist/dev/mp-weixin/common/vendor.js


+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-badge/u-badge.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-badge",
-  mixins: [common_vendor.mpMixin, common_vendor.props$13, common_vendor.mixin],
+  mixins: [common_vendor.mpMixin, common_vendor.props$14, common_vendor.mixin],
   computed: {
     // 是否将badge中心与父组件右上角重合
     boxStyle() {

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-column-notice/u-column-notice.js

@@ -1,7 +1,7 @@
 "use strict";
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$11],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$12],
   watch: {
     text: {
       immediate: true,

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-line/u-line.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-line",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$15],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$16],
   computed: {
     lineStyle() {
       const style = {};

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-loading-icon/u-loading-icon.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-loading-icon",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$9],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$10],
   data() {
     return {
       // Array.form可以通过一个伪数组对象创建指定长度的数组

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-row-notice/u-row-notice.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-row-notice",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$12],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$13],
   data() {
     return {
       animationDuration: "0",

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-swiper-indicator/u-swiper-indicator.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-swiper-indicator",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$10],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.props$11],
   data() {
     return {
       lineWidth: 22

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-text/u-text.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u--text",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.value, common_vendor.button, common_vendor.openType, common_vendor.props$14],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.value, common_vendor.button, common_vendor.openType, common_vendor.props$15],
   emits: ["click"],
   computed: {
     valueStyle() {

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-transition/u-transition.js

@@ -33,7 +33,7 @@ const _sfc_main = {
     }
   },
   // 将mixin挂在到组件中,实际上为一个vue格式对象。
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.transition, common_vendor.props$16],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.transition, common_vendor.props$17],
   watch: {
     show: {
       handler(newVal) {

+ 1 - 1
unpackage/dist/dev/mp-weixin/node-modules/uview-plus/components/u-upload/u-upload.js

@@ -2,7 +2,7 @@
 const common_vendor = require("../../../../common/vendor.js");
 const _sfc_main = {
   name: "u-upload",
-  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.mixinUp, common_vendor.props$17],
+  mixins: [common_vendor.mpMixin, common_vendor.mixin, common_vendor.mixinUp, common_vendor.props$9],
   data() {
     return {
       lists: [],

+ 1 - 0
unpackage/dist/dev/mp-weixin/pagesMy/account/index.wxss

@@ -3,5 +3,6 @@
 .content.data-v-e33b06dd {
   display: flex;
   flex-direction: column;
+  min-height: 100vh;
   background-color: var(--f1Color);
 }

+ 106 - 27
unpackage/dist/dev/mp-weixin/pagesMy/opinion/index.js

@@ -1,50 +1,129 @@
 "use strict";
 const common_vendor = require("../../common/vendor.js");
 if (!Array) {
-  const _easycom_up_overlay2 = common_vendor.resolveComponent("up-overlay");
-  _easycom_up_overlay2();
+  const _easycom_up_upload2 = common_vendor.resolveComponent("up-upload");
+  _easycom_up_upload2();
 }
-const _easycom_up_overlay = () => "../../node-modules/uview-plus/components/u-overlay/u-overlay.js";
+const _easycom_up_upload = () => "../../node-modules/uview-plus/components/u-upload/u-upload.js";
 if (!Math) {
-  (login + _easycom_up_overlay)();
+  _easycom_up_upload();
 }
-const login = () => "../../components/login.js";
 const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
   __name: "index",
   setup(__props) {
-    common_vendor.inject("$api");
-    common_vendor.inject("$config");
-    const config = common_vendor.ref({ logo: [], file: [] });
-    common_vendor.ref([]);
-    common_vendor.ref(0);
-    const show = common_vendor.ref(false);
+    const $api = common_vendor.inject("$api");
+    const $apifile = common_vendor.inject("$apifile");
+    const form = common_vendor.ref({ file: [] });
+    const typeList = common_vendor.ref([]);
+    const errors = common_vendor.ref({});
     const user = common_vendor.computed(() => {
       return common_vendor.index.getStorageSync("user");
     });
     common_vendor.onShow(async () => {
-      await searchConfig();
       await searchOther();
-      await search();
-      if (!user.value)
-        show.value = true;
     });
-    const searchConfig = async () => {
-      config.value = common_vendor.index.getStorageSync("config");
-    };
     const searchOther = async () => {
+      let res;
+      res = await $api(`dictData`, "GET", { code: "opinionType", is_use: "0" });
+      if (res.errcode === 0)
+        typeList.value = res.data;
+    };
+    const typeChange = (e) => {
+      const data = typeList.value[e.detail.value];
+      if (data) {
+        form.value.type = data.value;
+        form.value.type_name = data.label;
+      }
+    };
+    const deletePic = (event) => {
+      const file = form.value.file.filter((i) => i.url !== event.file.url);
+      form.value.file = file;
+    };
+    const afterRead = async (event) => {
+      const url = event.file[0].url;
+      const result = await $apifile(`/web/learn_opinion/upload`, "file", url, "file");
+      if (result.errcode === 0)
+        form.value.file = [...form.value.file, ...[result]];
+    };
+    const validateObject = (obj) => {
+      const errors2 = {};
+      if (!obj.type || obj.type.trim() === "") {
+        errors2.type = "请填写问题类型!";
+      }
+      if (!obj.brief || obj.brief.trim() === "") {
+        errors2.brief = "请填写问题描述!";
+      }
+      if (Object.keys(errors2).length > 0) {
+        return errors2;
+      }
+      return null;
     };
-    const search = async () => {
+    const mergeObjectsWithoutDuplicates = async (obj1, obj2) => {
+      return Object.keys({ ...obj1, ...obj2 }).reduce((acc, key) => {
+        if (!acc.hasOwnProperty(key)) {
+          if (key == "type_name") {
+            delete acc[key];
+          } else {
+            acc[key] = obj1.hasOwnProperty(key) ? obj1[key] : obj2[key];
+          }
+        }
+        return acc;
+      }, {});
     };
-    const showChange = () => {
-      show.value = false;
+    const formSubmit = async (e) => {
+      const data = await mergeObjectsWithoutDuplicates(e.detail.value, form.value);
+      const errorsInfo = await validateObject(data);
+      if (errorsInfo) {
+        errors.value = errorsInfo;
+        for (const key in errorsInfo) {
+          if (errorsInfo.hasOwnProperty(key)) {
+            console.error(`${key} 错误: ${errorsInfo[key]}`);
+          }
+        }
+      } else {
+        errors.value = {};
+        data.user = user.value._id;
+        if (user.value.role_type == "Student")
+          data.userType = "1";
+        else
+          data.userType = "0";
+        data.time = common_vendor.hooks().format("YYYY-MM-DD HH:mm:ss");
+        const res = await $api(`opinion`, "POST", data);
+        if (res.errcode == "0") {
+          common_vendor.index.showToast({
+            title: "反馈成功!",
+            icon: "success"
+          });
+          common_vendor.index.navigateBack({
+            delta: 1
+          });
+        }
+      }
     };
     return (_ctx, _cache) => {
-      return {
-        a: common_vendor.o(showChange),
-        b: common_vendor.p({
-          show: show.value
-        })
-      };
+      return common_vendor.e({
+        a: common_vendor.t(form.value.type_name || "请选择 >"),
+        b: common_vendor.o(typeChange),
+        c: typeList.value,
+        d: errors.value.type
+      }, errors.value.type ? {
+        e: common_vendor.t(errors.value.type)
+      } : {}, {
+        f: form.value.brief,
+        g: errors.value.brief
+      }, errors.value.brief ? {
+        h: common_vendor.t(errors.value.brief)
+      } : {}, {
+        i: common_vendor.o(afterRead),
+        j: common_vendor.o(deletePic),
+        k: common_vendor.p({
+          fileList: form.value.file,
+          name: "icon",
+          multiple: true,
+          maxCount: 3
+        }),
+        l: common_vendor.o(formSubmit)
+      });
     };
   }
 });

+ 1 - 2
unpackage/dist/dev/mp-weixin/pagesMy/opinion/index.json

@@ -1,7 +1,6 @@
 {
   "navigationBarTitleText": "意见反馈",
   "usingComponents": {
-    "up-overlay": "../../node-modules/uview-plus/components/u-overlay/u-overlay",
-    "login": "../../components/login"
+    "up-upload": "../../node-modules/uview-plus/components/u-upload/u-upload"
   }
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 1
unpackage/dist/dev/mp-weixin/pagesMy/opinion/index.wxml


+ 62 - 0
unpackage/dist/dev/mp-weixin/pagesMy/opinion/index.wxss

@@ -3,5 +3,67 @@
 .content.data-v-09ed81ef {
   display: flex;
   flex-direction: column;
+  min-height: 100vh;
   background-color: var(--f1Color);
+}
+.content .margin.data-v-09ed81ef {
+  margin: 3vw 0 0 0;
+}
+.content .other.data-v-09ed81ef {
+  padding: 3vw 2vw;
+  border-bottom: 1px solid var(--footColor);
+}
+.content .value.data-v-09ed81ef {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  background-color: var(--mainColor);
+}
+.content .value .label.data-v-09ed81ef {
+  text-align: right;
+}
+.content .value .label .input.data-v-09ed81ef {
+  text-align: right;
+}
+.content .value .label .image.data-v-09ed81ef {
+  width: 15vw;
+  height: 15vw;
+  border-radius: 20vw;
+}
+.content .value .label .error-message.data-v-09ed81ef {
+  margin: 5px 0 0 0;
+  color: var(--ff0Color);
+  font-size: var(--font12Size);
+}
+.content .brief.data-v-09ed81ef {
+  background-color: var(--mainColor);
+}
+.content .brief .title.data-v-09ed81ef {
+  margin: 0 0 2vw 0;
+}
+.content .brief .label .error-message.data-v-09ed81ef {
+  margin: 5px 0 0 0;
+  color: var(--ff0Color);
+  font-size: var(--font12Size);
+}
+.content .button.data-v-09ed81ef {
+  text-align: center;
+  margin: 2vw 0 0 0;
+}
+.content .button button.data-v-09ed81ef {
+  width: 80%;
+  font-size: var(--font16Size);
+  color: var(--mainColor);
+  background-color: var(--3c9Color);
+  border-radius: 10vw;
+  margin: 0 2vw;
+}
+.content .view.data-v-09ed81ef {
+  width: 100%;
+  position: fixed;
+  bottom: 2vw;
+  left: 0;
+  text-align: center;
+  color: var(--3c9Color);
+  font-size: var(--font12Size);
 }