index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <template>
  2. <view class="content">
  3. <view class="top">
  4. <img src="../../static/首页海报图.jpg" class="topImg"/>
  5. <br />
  6. <h2 style="color: white; margin-top: 2%;">膳食管理科意见征集</h2>
  7. <text style="color: white">{{title}}</text>
  8. </view>
  9. <br />
  10. <view style="padding-left: 1rem;">
  11. <text style="color: white;">所属园区:</text>
  12. <a-dropdown-button @click="handleButtonClick">
  13. 总公司园区
  14. <template #overlay>
  15. <a-menu @click="handleMenuClick">
  16. <a-menu-item key="1">
  17. <UserOutlined />
  18. 总公司园区
  19. </a-menu-item>
  20. </a-menu>
  21. </template>
  22. <template #icon><down-outlined /></template>
  23. </a-dropdown-button>
  24. </view>
  25. <view class="formStyle">
  26. <a-form
  27. :model="formState"
  28. name="basic"
  29. :label-col="{ span: 8 }"
  30. :wrapper-col="{ span: 16 }"
  31. autocomplete="off"
  32. width="95%"
  33. >
  34. <a-form-item
  35. label="问题描述(必填)"
  36. name="advice"
  37. :rules="[{ required: true, message: '意见不能为空' }]">
  38. <a-textarea
  39. placeholder="请写下您的建议或意见, 我们会努力改进"
  40. v-model:value="formState.advice"
  41. :rows="4"
  42. class="textAreaStyle"
  43. @input="onAdviceChange"/>
  44. </a-form-item>
  45. <a-form-item
  46. label="上传图片(最多三张)"
  47. name="password"
  48. >
  49. <div class="clearfix">
  50. <a-upload
  51. multiple=true
  52. maxCount="3"
  53. v-model:file-list="myfileList"
  54. @change="handleChange"
  55. list-type="picture-card"
  56. @preview="handlePreview"
  57. @remove="handleRemove">
  58. <div v-if="myfileList.length < 3">
  59. <plus-outlined />
  60. </div>
  61. </a-upload>
  62. <a-modal :open="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
  63. <img alt="example" style="width: 100%" :src="previewImage" />
  64. </a-modal>
  65. </div>
  66. </a-form-item>
  67. </a-form>
  68. <div class=test>
  69. <a-button
  70. shape="round"
  71. type="primary"
  72. @click="formSubmit"
  73. style="font-size: 40rpx;"
  74. class="subButton"
  75. :disabled="canSubmit" >提 交</a-button>
  76. </div>
  77. </view>
  78. </view>
  79. </template>
  80. <script lang="ts" setup>
  81. import { ref, reactive} from 'vue';
  82. import { PlusOutlined } from '@ant-design/icons-vue';
  83. import type { UploadProps, MenuProps} from 'ant-design-vue';
  84. import {message, reject} from 'ant-design-vue'
  85. import axios from 'axios';
  86. import { DownOutlined } from '@ant-design/icons-vue';
  87. import {baseUrl} from '@/config.js'
  88. interface FormState {
  89. advice: string;
  90. }
  91. const formState = reactive<FormState>({
  92. advice: ''
  93. });
  94. const title = '为了完善餐厅管理,持续提高服务质量,尽心竭力让员工更加精神饱满的投入生产工作,值此,我们诚恳向广大员工征集意见及建议,敬请员工们给予热心指导批评。';
  95. let filelist = []; // 图片链接集合(提交后台的)
  96. // 图片预览相关的
  97. const previewVisible = ref(false);
  98. const previewImage = ref('');
  99. const previewTitle = ref('');
  100. let myfileList = ref<UploadProps['fileList']>([]); // 页面显示的图片集合
  101. const canSubmit = ref(true) // 提交按钮可点击状态
  102. // 图片移除
  103. const handleRemove = (file: UploadProps['fileList'][number]) => {
  104. // 删除图片信息,防止提交冗余信息
  105. filelist = filelist.filter(item => item.uid !== file.uid);
  106. myfileList.value = myfileList.value.filter(f => f.uid !== file.uid);
  107. previewVisible.value = false;
  108. previewTitle.value = '';
  109. };
  110. function handleChange(info:any) {
  111. const file = info.file
  112. const isJPGorPNG = file.type === 'image/jpeg' || info.file.type === 'image/png' || file.type === 'image/jpg';
  113. const maxSize = 10 * 1024 * 1024;
  114. if(file.size>maxSize){
  115. message.error('单张图片需小于10MB');
  116. filelist = filelist.filter(item => item.uid !== file.uid);
  117. myfileList.value = myfileList.value.filter((file) => file.uid !== info.file.uid);
  118. }
  119. if (!isJPGorPNG) {
  120. message.error('只能上传 JPG 或 PNG 格式的图片!');
  121. filelist = filelist.filter(item => item.uid !== file.uid);
  122. myfileList.value = myfileList.value.filter((file) => file.uid !== info.file.uid);
  123. }else{
  124. filelist = info.fileList;
  125. }
  126. }
  127. // 监听意见框输入
  128. function onAdviceChange(event:any) {
  129. formState.advice = event.target.value;
  130. canSubmit.value = !(formState.advice.trim().length > 0);
  131. }
  132. // 点击提交
  133. function formSubmit(){
  134. console.log("点击提交")
  135. const formData = new FormData();
  136. filelist.forEach((file) => {
  137. formData.append('images', file.originFileObj);
  138. });
  139. formData.append('advice', formState.advice);
  140. // uni.request({
  141. // url:'/api'+'/review',
  142. // data:formData,
  143. // method:'POST'
  144. // })
  145. axios.post(baseUrl+'/review', formData).then(response => {
  146. formState.advice = ''
  147. filelist = []
  148. uni.reLaunch({
  149. url: './success'
  150. });
  151. })
  152. .catch(error => {
  153. console.error('提交失败:', error);
  154. });
  155. }
  156. function getBase64(file: File) {
  157. return new Promise((resolve, reject) => {
  158. const reader = new FileReader();
  159. reader.readAsDataURL(file);
  160. reader.onload = () => resolve(reader.result);
  161. reader.onerror = error => reject(error);
  162. });
  163. }
  164. const handlePreview = async (file: UploadProps['fileList'][number]) => {
  165. if (!file.url && !file.preview) {
  166. file.preview = (await getBase64(file.originFileObj)) as string;
  167. }
  168. previewImage.value = file.url || file.preview;
  169. previewVisible.value = true;
  170. previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
  171. };
  172. const handleCancel = () => {
  173. previewVisible.value = false;
  174. previewTitle.value = '';
  175. };
  176. const handleButtonClick = (e: Event) => {
  177. console.log('click left button', e);
  178. };
  179. const handleMenuClick: MenuProps['onClick'] = e => {
  180. console.log('click', e);
  181. };
  182. </script>
  183. <style scope>
  184. .content {
  185. display: flex;
  186. flex-direction: column;
  187. gap: 2%;
  188. background-color: rgb(85, 135, 158);
  189. height: 95vh;
  190. }
  191. .top{
  192. font-size: 25rpx;
  193. width: 94%;
  194. height: 35vh;
  195. margin-top: 5%;
  196. margin-left: 3%;
  197. padding: 2%;
  198. text-align: center;
  199. }
  200. .formStyle{
  201. display: flex;
  202. flex-direction: column;
  203. height: 80vh;
  204. background-color: white;
  205. }
  206. .textAreaStyle {
  207. border-bottom: none !important;
  208. border-radius: 0%;
  209. width: 95%;
  210. height: 30vh;
  211. margin-left: 2.5%;
  212. background-color: #F8F8F8;
  213. }
  214. .subButton{
  215. width: 80%;
  216. border-radius: 0%;
  217. height: auto;
  218. margin-left: 10%;
  219. }
  220. .ant-upload-select-picture-card i {
  221. width: 50rpx !important;
  222. color: yellow;
  223. }
  224. .ant-upload-select-picture-card{
  225. width: 100rpx !important;
  226. height: 100rpx !important;
  227. margin-left: 2%;
  228. }
  229. .topImg{
  230. width: 50%;
  231. height: 70%;
  232. }
  233. </style>