addCommon.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <template>
  2. <view class="main">
  3. <view class="bg-white default_title">
  4. <u--form :model="inputForm" labelWidth="130px" class="u-form default_title" labelPosition="left"
  5. ref="inputForm">
  6. <u-form-item label="年度" borderBottom prop="yearNum">
  7. <u--input readonly v-model="inputForm.yearNum" placeholder="输入年度" border="none"></u--input>
  8. </u-form-item>
  9. <u-form-item label="卡号" borderBottom prop="cardNum">
  10. <u--input readonly v-model="inputForm.cardNum" placeholder="输入卡号" border="none"></u--input>
  11. </u-form-item>
  12. </u--form>
  13. </view>
  14. <view class="bg-white margin-top main_info">
  15. <u--form :model="inputForm" :rules="rules" labelWidth="130px" class="u-form default_title"
  16. labelPosition="left" ref="inputForm">
  17. <u-form-item required label="文件名称" borderBottom prop="name">
  18. <u--input v-model="inputForm.name" placeholder="请输入文件名称" border="none"></u--input>
  19. </u-form-item>
  20. <u-form-item label="拟稿人" borderBottom prop="authorPerson">
  21. <u--input readonly v-model="$auth.getUserInfo().name" border="none"></u--input>
  22. </u-form-item>
  23. <u-form-item required label="校对人" borderBottom prop="proofreader">
  24. <office-user-select v-model="inputForm.proofreader" placeholder="请选择校对人" title="校对人"
  25. myOffice types="3,6"></office-user-select>
  26. </u-form-item>
  27. <u-form-item label="印数" borderBottom prop="printNum">
  28. <u-number-box integer v-model="inputForm.printNum"></u-number-box>
  29. </u-form-item>
  30. <u-form-item label="是否公开" borderBottom prop="open">
  31. <u-radio-group v-model="inputForm.open">
  32. <u-radio style="margin-right: 20px;" label="是" name="1"></u-radio>
  33. <u-radio label="否" name="0"></u-radio>
  34. </u-radio-group>
  35. </u-form-item>
  36. <u-form-item label="备注" borderBottom prop="remark">
  37. <u--input v-model="inputForm.remark" placeholder="请输入备注" border="none"></u--input>
  38. </u-form-item>
  39. <u-form-item label="文件附件" prop="attachment" labelPosition="top">
  40. <lsj-upload ref="lsjUpload" childId="upload1" width="250rpx" height="200rpx" :option="option"
  41. :debug="false" :instantly="false" @uploadEnd="onuploadEnd" @change="afterRead">
  42. <view class="addfile flex">
  43. <u-icon size="20" bold name="plus"></u-icon>
  44. </view>
  45. </lsj-upload>
  46. <!-- #ifdef H5 -->
  47. <view class="takephoto addfile flex" @click="takePhoto"> <u-icon size="20" bold
  48. name="camera"></u-icon>
  49. </view>
  50. <!-- #endif -->
  51. </u-form-item>
  52. <view class="text-danger" style="font-size: 12px!important;">请确保上传图片内容清晰可见,所有涉密敏感信息不得上传</view>
  53. <view class="other_info">
  54. <view class="other_pdf">
  55. <u-cell-group>
  56. <u-cell v-for="item in fileList">
  57. <view slot="title">
  58. <u--text :lines="1" :text="item.name"></u--text>
  59. </view>
  60. <u-icon slot="value" size="28" name="trash-fill" @click="deleteFile(item)"></u-icon>
  61. </u-cell>
  62. </u-cell-group>
  63. </view>
  64. </view>
  65. <u-upload :fileList="imgList" @delete="deletePic" multiple :maxCount="imgList.length"
  66. :previewFullImage="true"></u-upload>
  67. <view class="submit_btn flex">
  68. <u-button v-if="!loading" type="primary" text="提交新增" @click="formSubmit"></u-button>
  69. <u-button v-if="loading" :loading="loading" type="primary" text="加载中"></u-button>
  70. </view>
  71. </u--form>
  72. </view>
  73. <u-toast ref="uToast"></u-toast>
  74. <u-overlay :show="loading">
  75. <view class="warp">
  76. <view class="rect"><u-button plain loading loadingText="加载中"></u-button></view>
  77. </view>
  78. </u-overlay>
  79. </view>
  80. </template>
  81. <script>
  82. import {
  83. isImageFormat
  84. } from "@/common/util.js"
  85. import BASE_URL from '@/config.js'
  86. import moment from "moment"
  87. import * as $auth from "@/common/auth.js"
  88. import userService from "@/api/sys/userService"
  89. import fileService from '@/api/file/fileService.js'
  90. import yzCirculationCardService from '@/api/commonseal/yzCirculationCardService.js'
  91. export default {
  92. mounted() {
  93. userService.list({
  94. current: 1,
  95. size: 10000
  96. }).then((res) => {
  97. this.userList = res.records
  98. }).catch((e) => {
  99. throw e
  100. })
  101. yzCirculationCardService.getCardNum().then(data => {
  102. this.inputForm.authorPerson = $auth.getUserInfo().id
  103. const currentYear = new Date().getFullYear();
  104. this.inputForm.yearNum = currentYear
  105. this.cardNum = data
  106. this.inputForm.cardNum = "[" + currentYear + "]" + data + "号"
  107. })
  108. },
  109. data() {
  110. return {
  111. imgsrc: {},
  112. loading: false,
  113. isreceive: false,
  114. iswrite: false,
  115. fileLists: [],
  116. fileList: [],
  117. files: [],
  118. imgList: [],
  119. userList: [],
  120. cardNum: "",
  121. inputForm: {
  122. id: '',
  123. name: '',
  124. authorPerson: '',
  125. proofreader: '',
  126. open: '1',
  127. printNum: '1',
  128. state: '1',
  129. cardNum: '',
  130. yearNum: '',
  131. attachment: '',
  132. remark: '',
  133. },
  134. rules: {
  135. name: [{
  136. required: true,
  137. message: '请输入文件名称',
  138. trigger: ['blur', 'change']
  139. }]
  140. },
  141. // 上传接口参数
  142. option: {
  143. url: BASE_URL + '/gwfile/upload?uploadPath=commonseal',
  144. name: 'file',
  145. header: {
  146. "token": $auth.getUserToken()
  147. },
  148. },
  149. }
  150. },
  151. methods: {
  152. showToast(params) {
  153. this.loading = false
  154. this.$refs.uToast.show({
  155. ...params,
  156. complete() {
  157. params.url && uni.redirectTo({
  158. url: params.url
  159. })
  160. }
  161. })
  162. },
  163. // 删除文件
  164. deleteFile(item) {
  165. let that = this
  166. that.fileList = that.fileList.filter(i => !(i.url == item.url))
  167. that.fileLists = that.fileLists.filter(i => !(i.url == item.url))
  168. },
  169. // 删除图片
  170. deletePic(event) {
  171. let that = this
  172. this.imgList = this.imgList.filter(item => item.name != event.file.name)
  173. that.fileLists = that.fileLists.filter(i => !(i.name == event.file.name))
  174. },
  175. // 图片压缩
  176. compressH5(urlData, targetSizeKB, initialQuality = 1.0) {
  177. const maxQuality = 1.0;
  178. const minQuality = 0.0;
  179. const tolerance = 0.01; // 根据需要调整公差
  180. if (!urlData.url) {
  181. this.$set(urlData, "url", urlData.path)
  182. }
  183. let that = this
  184. return new Promise((resolve, reject) => {
  185. let binarySearch = (min, max) => {
  186. const midQuality = (min + max) / 2;
  187. uni.getImageInfo({
  188. src: urlData.url,
  189. success(res) {
  190. const reader = new FileReader();
  191. let img = new Image()
  192. img.src = res.path
  193. img.onload = function() {
  194. const canvas = document.createElement('canvas');
  195. const ctx = canvas.getContext('2d');
  196. canvas.width = img.width;
  197. canvas.height = img.height;
  198. ctx.clearRect(0, 0, canvas.width, canvas.height);
  199. ctx.drawImage(img, 0, 0, canvas.width, canvas
  200. .height);
  201. // 使用异步的 toBlob 方法
  202. canvas.toBlob(async (blob) => {
  203. const fileSizeKB = blob.size /
  204. 1024;
  205. if (Math.abs(fileSizeKB -
  206. targetSizeKB) <
  207. tolerance || max - min <
  208. tolerance) {
  209. // 当前质量足够接近目标大小,使用当前质量解析
  210. reader.readAsDataURL(blob);
  211. reader.onload = () => {
  212. let result = that
  213. .uploadFilePromise(reader
  214. .result)
  215. setTimeout(() => {
  216. resolve(result)
  217. }, 300)
  218. }
  219. } else if (fileSizeKB >
  220. targetSizeKB) {
  221. // 如果文件大小太大,降低质量,继续二分查找
  222. binarySearch(min, midQuality);
  223. } else {
  224. // 如果文件大小太小,增加质量,继续二分查找
  225. binarySearch(midQuality, max);
  226. }
  227. }, urlData.type, midQuality);
  228. };
  229. }
  230. })
  231. }
  232. // 开始二分查找
  233. binarySearch(minQuality, maxQuality);
  234. })
  235. },
  236. // 拍照
  237. takePhoto() {
  238. let that = this
  239. // 调用uniapp的chooseImage API 选择图片
  240. uni.chooseImage({
  241. count: 1, // 默认9, 设置图片的数量
  242. sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
  243. sourceType: ['camera'], // 可以指定来源是相册还是相机,默认二者都有
  244. success: (chooseImageRes) => {
  245. uni.showLoading({
  246. title: "上传中"
  247. })
  248. const tempFilePaths = chooseImageRes.tempFiles[0];
  249. // 成功选择图片后进行压缩处理
  250. that.compressH5(tempFilePaths, 150).then(result => {
  251. const fileName = result.split(/[/\\=]/).pop();
  252. let item1 = {
  253. name: fileName,
  254. url: BASE_URL + result
  255. }
  256. let item = {
  257. name: fileName,
  258. path: result,
  259. }
  260. that.fileLists.push(item)
  261. that.imgList.push(item1)
  262. uni.hideLoading()
  263. })
  264. },
  265. fail: (error) => {
  266. uni.hideLoading()
  267. }
  268. });
  269. },
  270. // 拍照上传
  271. async uploadFilePromise(param) {
  272. return new Promise((resolve, reject) => {
  273. let a = uni.uploadFile({
  274. url: this.BASE_URL + '/gwfile/upload?uploadPath=commonseal',
  275. filePath: param,
  276. name: 'file',
  277. header: {
  278. "token": $auth.getUserToken()
  279. },
  280. success: (res) => {
  281. setTimeout(() => {
  282. resolve(res.data)
  283. }, 300)
  284. }
  285. })
  286. });
  287. },
  288. // 新增图片
  289. afterRead(files) {
  290. uni.showLoading({
  291. title: "上传中"
  292. })
  293. let lists = [...files.values()]
  294. this.files = files
  295. for (let i = 0; i < lists.length; i++) {
  296. if (lists[i].type == 'success') continue;
  297. if (isImageFormat(lists[i].name) && lists[i].size > 200 * 1024) {
  298. this.compressAPP(lists[i], 150).then(res => {
  299. this.files.get(lists[i].name).file = res
  300. this.upload(lists[i].name)
  301. })
  302. } else {
  303. this.upload(lists[i].name)
  304. }
  305. }
  306. },
  307. // app图片压缩
  308. compressAPP(urlData, targetSizeKB, initialQuality = 1.0) {
  309. const maxQuality = 1.0;
  310. const minQuality = 0.0;
  311. const tolerance = 0.01; // 根据需要调整公差
  312. let that = this
  313. return new Promise((resolve, reject) => {
  314. let binarySearch = (min, max) => {
  315. const midQuality = (min + max) / 2;
  316. uni.getImageInfo({
  317. src: urlData.path,
  318. success: function(res) {
  319. let img = new Image()
  320. img.src = res.path
  321. img.onload = function() {
  322. const canvas = document.createElement('canvas');
  323. const ctx = canvas.getContext('2d');
  324. canvas.width = img.width;
  325. canvas.height = img.height;
  326. ctx.clearRect(0, 0, canvas.width, canvas.height);
  327. ctx.drawImage(img, 0, 0, canvas.width, canvas
  328. .height);
  329. // 使用异步的 toBlob 方法
  330. canvas.toBlob(async (blob) => {
  331. const fileSizeKB = blob.size / 1024;
  332. if (Math.abs(fileSizeKB -
  333. targetSizeKB) <
  334. tolerance || max - min <
  335. tolerance) {
  336. // 当前质量足够接近目标大小,使用当前质量解析
  337. const file = new File([blob], urlData
  338. .name, {
  339. type: blob.type,
  340. lastModified: new Date()
  341. .getTime(), // 使用当前时间作为最后修改时间
  342. });
  343. setTimeout(() => {
  344. resolve(file)
  345. }, 300)
  346. } else if (fileSizeKB >
  347. targetSizeKB) {
  348. // 如果文件大小太大,降低质量,继续二分查找
  349. binarySearch(min, midQuality);
  350. } else {
  351. // 如果文件大小太小,增加质量,继续二分查找
  352. binarySearch(midQuality, max);
  353. }
  354. }, urlData.file.type, midQuality);
  355. };
  356. },
  357. fail: function(err) {
  358. resolve(false);
  359. }
  360. });
  361. }
  362. // 开始二分查找
  363. binarySearch(minQuality, maxQuality);
  364. })
  365. },
  366. // APP手动上传
  367. upload(name) {
  368. // name=指定文件名,不指定则上传所有type等于waiting和fail的文件
  369. this.$refs['lsjUpload'].upload(name);
  370. },
  371. onuploadEnd(item) {
  372. console.log(`${item.name}已上传结束,上传状态=${item.type}`);
  373. // 更新当前窗口状态变化的文件
  374. this.files.set(item.name, item);
  375. let file = {
  376. name: item.name,
  377. path: item.responseText
  378. }
  379. this.fileLists.push(file)
  380. const fileName = item.name.split(/[/\\=]/).pop();
  381. if (isImageFormat(item.name)) {
  382. let item1 = {
  383. name: fileName,
  384. url: this.BASE_URL + item.responseText
  385. }
  386. this.imgList.push(item1)
  387. } else {
  388. let a = {
  389. name: fileName,
  390. url: this.BASE_URL + item.responseText
  391. }
  392. this.fileList.push(a)
  393. }
  394. uni.hideLoading()
  395. // 微信小程序Map对象for循环不显示,所以转成普通数组,
  396. // 如果你用不惯Map对象,也可以像这样转普通数组,组件使用Map主要是避免反复文件去重操作
  397. // #ifdef MP-WEIXIN
  398. this.wxFiles = [...this.files.values()];
  399. // #endif
  400. // 强制更新视图
  401. this.$forceUpdate();
  402. // ---可删除--演示判断是否所有文件均已上传成功
  403. let isAll = [...this.files.values()].find(item => item.type !== 'success');
  404. if (!isAll) {
  405. } else {
  406. console.log(isAll.name + '待上传');
  407. }
  408. },
  409. // 下载文件
  410. download(param) {
  411. fileService.download(param).then(data)
  412. },
  413. // 表单提交
  414. formSubmit() {
  415. this.loading = true
  416. let auditForm = Object.assign({}, this.inputForm);
  417. let files = []
  418. this.fileLists.forEach(item => {
  419. files.push(item.path)
  420. })
  421. auditForm.attachment = files.join(",");
  422. auditForm.cardNum = this.cardNum
  423. this.$refs.inputForm.validate().then(valid => {
  424. if (valid) {
  425. yzCirculationCardService.save(auditForm).then((data) => {
  426. let param = {
  427. type: 'success',
  428. message: data,
  429. iconUrl: 'https://cdn.uviewui.com/uview/demo/toast/success.png',
  430. url: "/pages/index/index"
  431. }
  432. this.showToast(param);
  433. }).catch(() => {
  434. let param = {
  435. type: 'error',
  436. message: data,
  437. iconUrl: 'https://cdn.uviewui.com/uview/demo/toast/error.png',
  438. }
  439. this.showToast(param);
  440. })
  441. }
  442. }).catch(e => {
  443. this.loading = false
  444. })
  445. }
  446. }
  447. }
  448. </script>
  449. <style>
  450. .warp {
  451. display: flex;
  452. align-items: center;
  453. justify-content: center;
  454. height: 100%;
  455. }
  456. .default_title {
  457. padding-top: 0px;
  458. }
  459. .main_info {
  460. margin-top: 15px;
  461. }
  462. .u-form-item__body__right__message span {
  463. font-size: 12px !important;
  464. }
  465. .submit_btn {
  466. background-color: #fefefe;
  467. margin-top: 20px;
  468. box-shadow: none;
  469. margin-bottom: 20px;
  470. }
  471. .submit_btn button {
  472. height: 40px;
  473. width: 80%;
  474. border-radius: 30px;
  475. }
  476. .addfile {
  477. width: 80px;
  478. height: 80px;
  479. background-color: #eee;
  480. padding-left: 30%;
  481. /* padding-left: 18%; */
  482. margin: 10px;
  483. }
  484. .takephoto {
  485. padding-left: 9%;
  486. }
  487. .other_info {
  488. width: 100%;
  489. }
  490. </style>