camera-scan-code.uvue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. <template>
  2. <!-- #ifdef APP -->
  3. <scroll-view style="flex:1">
  4. <!-- #endif -->
  5. <!--
  6. <camera style="width: 100%; height: 300px;" :resolution="'high'" :mode="'scanCode'" @scancode="handleScanCode">
  7. </camera> -->
  8. <view class="my-page">
  9. <swiper class="swiper-box my-swiper" :current="swiperDotIndex" :indicator-dots="true">
  10. <swiper-item v-for="item in data">
  11. <view class="swiper-item" @tap="previewSingleImage(item.image)">
  12. <image class="my-image" :src="item.image" mode="aspectFill" />
  13. </view>
  14. <view>
  15. <text class="demo-view-label">{{ item?.name ?? ''}}</text>
  16. </view>
  17. </swiper-item>
  18. </swiper>
  19. <view class="camera-scan-code-back-wrap" v-show="false">
  20. <button class="btn block bg-blue lg round" @click="chooseImage">
  21. 浏览相册
  22. </button>
  23. </view>
  24. <view class="camera-scan-code-table">
  25. <view class="camera-scan-code-table-pair" v-if="joinRecord.imgname!=''">
  26. <view class="camera-scan-code-table-pair-label">
  27. <text>已存图片(最多能存{{joinRecord.num}}张)</text>
  28. </view>
  29. <view class="camera-scan-code-table-pair-value" v-for="itemName in joinRecord.imgname.split(',')" >
  30. <text class="txt">{{ itemName }}</text>
  31. </view>
  32. </view>
  33. <view class="camera-scan-code-table-pair">
  34. <view class="camera-scan-code-table-pair-label">
  35. <text>待存图片</text>
  36. </view>
  37. <view class="camera-scan-code-table-pair-value">
  38. <text class="txt">{{ dyImgName+"-"+minAvailableNumber+".jpg"}}</text>
  39. </view>
  40. </view>
  41. </view>
  42. <view class="camera-scan-code-back-wrap">
  43. <button class="btn block bg-blue lg round" @click="saveImage" style="min-width: 250px;">
  44. 保存图片
  45. </button>
  46. </view>
  47. <view class="camera-scan-code-back-wrap">
  48. <button type="default" class="btn bg-blue round" @click="navigateBack">返回拍照</button>
  49. <button type="default" class="btn bg-blue round" @click="navigateExit">退出拍照</button>
  50. </view>
  51. </view>
  52. <!-- #ifdef APP -->
  53. </scroll-view>
  54. <!-- #endif -->
  55. </template>
  56. <script lang="uts">
  57. type CameraScanCodeResult = {
  58. type : string | null;
  59. result : string | null;
  60. }
  61. type ImageItem = {
  62. image : string,
  63. name : string,
  64. checked : boolean
  65. }
  66. import { getJoinList, JoinRecord, updateData } from '@/api/work';
  67. export default {
  68. data() {
  69. return {
  70. result: null as CameraScanCodeResult | null,
  71. swiperDotIndex: 0 as number,
  72. path: '',
  73. recordId: 0,
  74. imgArrLen: 0,
  75. joinRecord: {
  76. sxid: 0,
  77. senum: 0,
  78. photoitem: "",
  79. productno: "",
  80. descb: "",
  81. part: "",
  82. date: "",
  83. partno: "",
  84. num: 0,
  85. status: 1,
  86. urlspl: "",
  87. imgname: "",
  88. urlpdt: "",
  89. pid: 0,
  90. workorder: "",
  91. invname: ""
  92. } as JoinRecord,
  93. num: 0,
  94. dyImgName: '',
  95. minAvailableNumber: 1,
  96. data: [{
  97. image: '/static/images/banner/banner01.png',
  98. name: 'banner01.png',
  99. checked: true
  100. }] as ImageItem[]
  101. }
  102. },
  103. onBackPress() {
  104. // 覆盖系统默认的返回行为,返回到指定页面
  105. //?photoitem=${photoitem}&num=${num}&pid=${pid}
  106. uni.navigateTo({
  107. url: `/pages/work/record/RecordList?photoitem=${this.joinRecord.photoitem}&num=${this.joinRecord.num}&pid=${this.joinRecord.pid}&senum=${this.joinRecord.senum}`,
  108. // 修改动画方向为从左到右退回
  109. animationType: 'slide-in-left', // 使用从左到右滑出的动画效果
  110. animationDuration: 300 // 动画持续时间,单位ms
  111. })
  112. // 返回true表示拦截默认返回行为
  113. return true
  114. },
  115. onLoad(options) {
  116. this.path = options?.['path'] ?? ''
  117. let recordId = options?.['recordId'] ?? ''
  118. let num = options?.['num'] ?? ''
  119. console.log(this.path)
  120. if (this.path != '') {
  121. this.data = []
  122. this.data.push({ image: this.path, name: '', checked: true })
  123. }
  124. if (recordId != '') {
  125. this.recordId = parseInt(recordId)
  126. getJoinList('app_media_record as r', 'app_media_info as i', 'r.*,i.workorder,i.invname', 'r.pid=i.pdid', 'sxid', recordId, null).then((res : UTSJSONObject) => {
  127. let dataList = res?.['data'] as UTSJSONObject[] ?? Array<UTSJSONObject>()
  128. if (dataList != null && dataList.length > 0) {
  129. dataList.forEach(item => {
  130. if (item != null) {
  131. let record = JSON.parse<JoinRecord>(item.toJSONString());
  132. if (record != null) {
  133. this.num = record.num;
  134. this.dyImgName = record.workorder + record.invname + record.part + record.photoitem + record.partno;
  135. this.joinRecord = record
  136. this.imgArrLen = record.imgname.indexOf(",") > -1 ? record.imgname.split(",").length : (record.imgname != '' ? 1 : 0)
  137. // 计算最小可用编号
  138. this.calculateMinAvailableNumber();
  139. }
  140. }
  141. });
  142. }
  143. });
  144. }
  145. if (num != '') {
  146. this.num = parseInt(num)
  147. }
  148. },
  149. methods: {
  150. navigateBack() {
  151. //uni.navigateBack()
  152. uni.navigateTo({
  153. url: `/pages/work/record/Camera?id=${this.recordId}&num=${this.num}`
  154. })
  155. },
  156. navigateExit() {
  157. uni.navigateTo({
  158. url: `/pages/work/record/InfoDetail?id=${this.joinRecord.pid}`
  159. })
  160. },
  161. checkboxChange() {
  162. console.log("选择图片名称")
  163. },
  164. chooseImage() {
  165. uni.chooseImage({
  166. sourceType: ['album'],
  167. success: (res) => {
  168. //this.data = res.tempFilePaths; // 获取选中的图片路径
  169. this.data = []
  170. for (let i = 0; i < res.tempFilePaths.length; i++) {
  171. this.data.push({ image: res.tempFilePaths[i], name: '', checked: true })
  172. }
  173. },
  174. fail: (err) => {
  175. console.error('选择图片失败', err);
  176. }
  177. });
  178. },
  179. saveImage() {
  180. //保存图片进入相册文件
  181. if (this.path == '') {
  182. uni.showToast({
  183. title: '没有拍照文件',
  184. icon: 'error',
  185. duration: 2000
  186. });
  187. return;
  188. }
  189. if (this.imgArrLen == this.joinRecord.num) {
  190. uni.showToast({
  191. title: '拍照图片已满',
  192. icon: 'error',
  193. duration: 2000
  194. });
  195. return;
  196. }
  197. let updateImgs = ''
  198. let updateNames = ''
  199. let updateStatus = ''
  200. // 动态生成最小的可用图片编号
  201. const getMinAvailableNumber = () => {
  202. if (this.imgArrLen === 0) return 1;
  203. // 从已有的图片名称中提取编号
  204. const existingNumbers = new Set<number>();
  205. const imgNames = this.joinRecord.imgname.split(',');
  206. imgNames.forEach((name : string) => {
  207. if (name != '') {
  208. // 提取图片名称中的数字部分
  209. const match = name.match(/-(\d+)\.jpg$/);
  210. if (match != null && match[1] != null) {
  211. const numStr = match[1] as string;
  212. existingNumbers.add(parseInt(numStr));
  213. }
  214. }
  215. });
  216. // 查找1到所需图片数量之间最小的未使用编号
  217. for (let i = 1; i <= this.joinRecord.num; i++) {
  218. if (!existingNumbers.has(i)) {
  219. return i;
  220. }
  221. }
  222. // 如果1到所需数量都被使用了,则使用当前数量+1
  223. return this.imgArrLen + 1;
  224. };
  225. const minAvailableNumber = getMinAvailableNumber();
  226. const newImgName = this.dyImgName + "-" + minAvailableNumber + ".jpg";
  227. const relativePath = `/uploadImgs/${newImgName}`
  228. if (this.imgArrLen == 0) {
  229. updateImgs = relativePath
  230. updateNames = newImgName;
  231. } else {
  232. updateImgs = this.joinRecord.urlpdt + "," + relativePath
  233. updateNames = this.joinRecord.imgname + "," + newImgName;
  234. }
  235. let updatedData = "imgname='" + updateNames + "',urlpdt='" + updateImgs + "'"
  236. if (this.joinRecord.num === this.imgArrLen + 1) {
  237. updateStatus = "status='3'"
  238. updatedData = updatedData + "," + updateStatus
  239. } else if (this.joinRecord.status === 1) {
  240. updateStatus = "status='2'"
  241. updatedData = updatedData + "," + updateStatus
  242. }
  243. console.log(updatedData)
  244. updateData('app_media_record', updatedData, 'sxid', this.recordId.toString()).then((res : UTSJSONObject) => {
  245. let data = res?.['data'] as boolean ?? false
  246. if (data != null && data== true) {
  247. uni.showToast({
  248. title: "保存成功!",
  249. });
  250. const newPath = `${uni.env.USER_DATA_PATH}/uploadImgs/${newImgName}`
  251. this.renameFile(this.path, newPath)
  252. uni.navigateTo({
  253. url: `/pages/work/record/RecordList?photoitem=${this.joinRecord.photoitem}&num=${this.joinRecord.num}&pid=${this.joinRecord.pid}&senum=${this.joinRecord.senum}`,
  254. // 修改动画方向为从左到右退回
  255. animationType: 'slide-in-left', // 使用从左到右滑出的动画效果
  256. animationDuration: 300 // 动画持续时间,单位ms
  257. })
  258. }
  259. });
  260. },
  261. previewSingleImage(imageUrl : string) {
  262. uni.previewImage({
  263. urls: [imageUrl], // 需要预览的图片链接列表
  264. current: 0, // 当前显示图片的索引
  265. indicator: 'number', // 图片指示器样式
  266. loop: false // 是否可循环预览
  267. });
  268. },
  269. renameFile(oldPath:string, newPath:string) {
  270. // 先拷贝文件到新路径
  271. uni.getFileSystemManager().copyFile({
  272. srcPath: oldPath,
  273. destPath: newPath,
  274. success: function () {
  275. // 可选:删除原文件,如果你需要释放空间的话
  276. uni.getFileSystemManager().unlink({
  277. filePath: oldPath,
  278. success: function () {
  279. console.log('原文件已删除');
  280. },
  281. fail: function (unlinkErr) {
  282. console.error('删除原文件失败', unlinkErr);
  283. }
  284. });
  285. console.log('文件重命名成功');
  286. },
  287. fail: function (copyErr) {
  288. console.error('拷贝文件失败', copyErr);
  289. }
  290. });
  291. },
  292. handleScanCode(ev : UniCameraScanCodeEvent) {
  293. const deatil = ev.detail;
  294. this.result = {
  295. type: deatil.type,
  296. result: deatil.result
  297. } as CameraScanCodeResult
  298. },
  299. // 计算最小的可用图片编号
  300. calculateMinAvailableNumber() {
  301. if (this.imgArrLen === 0) {
  302. this.minAvailableNumber = 1;
  303. return;
  304. }
  305. // 从已有的图片名称中提取编号
  306. const existingNumbers = new Set<number>();
  307. const imgNames = this.joinRecord.imgname.split(',');
  308. imgNames.forEach((name : string) => {
  309. if (name != '') {
  310. // 提取图片名称中的数字部分
  311. const match = name.match(/-(\d+)\.jpg$/);
  312. if (match != null && match[1] != null) {
  313. const numStr = match[1] as string;
  314. existingNumbers.add(parseInt(numStr));
  315. }
  316. }
  317. });
  318. // 查找1到所需图片数量之间最小的未使用编号
  319. for (let i = 1; i <= this.joinRecord.num; i++) {
  320. if (!existingNumbers.has(i)) {
  321. this.minAvailableNumber = i;
  322. return;
  323. }
  324. }
  325. // 如果1到所需数量都被使用了,则使用当前数量+1
  326. this.minAvailableNumber = this.imgArrLen + 1;
  327. },
  328. }
  329. }
  330. </script>
  331. <style>
  332. .camera-scan-code-back-wrap {
  333. display: flex;
  334. justify-content: center;
  335. align-items: center;
  336. flex-direction: row;
  337. }
  338. .camera-scan-code-table {
  339. background-color: white;
  340. margin-top: 20px;
  341. }
  342. .camera-scan-code-table-pair {
  343. height: 100px;
  344. flex-direction: column;
  345. justify-content: space-between;
  346. align-items: center;
  347. }
  348. .camera-scan-code-table-pair-label {
  349. flex-grow: 1;
  350. margin-left: 15px;
  351. }
  352. .camera-scan-code-table-pair-value {
  353. flex-grow: 2;
  354. flex-direction: column;
  355. }
  356. .camera-scan-code-table-pair-value .txt {
  357. font-size: 14px;
  358. }
  359. .camera-scan-code-table-top-line {
  360. border-top: 1px solid #eee;
  361. }
  362. .my-page {
  363. display: flex;
  364. flex-direction: column;
  365. box-sizing: border-box;
  366. background-color: #fff;
  367. /* #ifndef APP-ANDROID */
  368. min-height: 100%;
  369. /* #endif */
  370. height: 100%;
  371. }
  372. .swiper {
  373. height: 400px;
  374. }
  375. .swiper-box {
  376. height: 300px;
  377. }
  378. .swiper-item {
  379. /* #ifndef APP-NVUE */
  380. display: flex;
  381. /* #endif */
  382. flex-direction: column;
  383. justify-content: center;
  384. align-items: center;
  385. color: #fff;
  386. height: 400px;
  387. line-height: 400px;
  388. }
  389. .btn {
  390. /*margin-top: 30px; */
  391. height: 45px;
  392. margin: 20px 20px;
  393. }
  394. </style>