usePhotography.ts 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. import { ref, onMounted, onBeforeUnmount, watchEffect, computed } from 'vue'
  2. import icpList from '@/utils/ipc'
  3. import client from "@/stores/modules/client";
  4. import socket from "@/stores/modules/socket";
  5. import { ElMessage, ElMessageBox } from 'element-plus'
  6. import { getFilePath, getRouterUrl } from '@/utils/appfun'
  7. import { useRouter, useRoute } from "vue-router";
  8. import checkInfo from "@/stores/modules/check";
  9. import generate from '@/utils/menus/generate'
  10. import { clickLog, setLogInfo } from '@/utils/log'
  11. import { useUuidStore } from '@/stores/modules/uuid'
  12. import useUserInfo from "@/stores/modules/user";
  13. import configInfo from '@/stores/modules/config';
  14. import tokenInfo from "@/stores/modules/token";
  15. import { getAllUserConfigs } from '@/apis/setting';
  16. export default function usePhotography() {
  17. const loading = ref(false)
  18. const runLoading = ref(false)
  19. const takePictureLoading = ref(false)
  20. // pagination
  21. const pageSize = ref(10)
  22. const currentPage = ref(1)
  23. const totalPages = ref(1)
  24. const goodsList = ref([])
  25. const goods_art_no_tpl = ref('')
  26. const goods_art_no = ref('')
  27. const runAction = ref({
  28. "action": "",
  29. "goods_art_no": ""
  30. })
  31. const lastPhoto = ref({})
  32. const showlastPhoto = ref(false)
  33. const isDelGoodsGetList = ref(false)
  34. const reNosObj = ref({
  35. goods_art_no: null,
  36. action: null,
  37. })
  38. const goodsArtNo = ref()
  39. const searchGoodsArtNo = ref('')
  40. let smartShooterTimeout: ReturnType<typeof setTimeout> | null = null
  41. // 初始化 WebSocket 状态管理
  42. const socketStore = socket()
  43. const uuidStore = useUuidStore();
  44. const clientStore = client();
  45. const Router = useRouter()
  46. const route = useRoute();
  47. const useUserInfoStore = useUserInfo();
  48. const configInfoStore = configInfo();
  49. const tokenInfoStore = tokenInfo();
  50. const checkInfoStore = checkInfo()
  51. // 拍照点位配置
  52. const STORAGE_KEY = 'photo_point_name'
  53. // 获取已配置相机的点位列表(从 getAllUserConfigs API 获取,仅返回已绑定相机的点位)
  54. const getPointList = async (): Promise<string[]> => {
  55. try {
  56. const result = await getAllUserConfigs({})
  57. if (result.code == 0 && result.data?.configs?.camera_configs?.iso_config) {
  58. const isoConfig = result.data.configs.camera_configs.iso_config
  59. const points = Object.keys(isoConfig).filter(key => {
  60. const config = isoConfig[key]
  61. return config && config.CameraKey && config.CameraKey !== ''
  62. })
  63. return points.length > 0 ? points : ['A']
  64. }
  65. } catch (err) {
  66. console.error('获取点位配置失败:', err)
  67. }
  68. return ['A']
  69. }
  70. // 获取保存的点位(单相机模式默认A,多相机模式验证点位合法性)
  71. const getPhotoPointName = async (): Promise<string> => {
  72. if (!useUserInfoStore.isMultiCameraMode) {
  73. return 'A'
  74. }
  75. const pointList = await getPointList()
  76. const savedPoint = localStorage.getItem(STORAGE_KEY)
  77. if (savedPoint && pointList.includes(savedPoint)) {
  78. return savedPoint
  79. }
  80. return pointList[0] || 'A'
  81. }
  82. // 抠图请求去重与延迟队列(key: goods_art_no, value: timeoutId)
  83. const segmentQueue = new Map<string, ReturnType<typeof setTimeout>>()
  84. function isGoodsStillInList(goodsArtNo: string): boolean {
  85. return goodsList.value?.some((g: any) => g.goods_art_no === goodsArtNo) || false
  86. }
  87. function scheduleSegment(goodsArtNo: string) {
  88. if (!goodsArtNo) return
  89. // 若已存在,则重置计时(重新插入)
  90. if (segmentQueue.has(goodsArtNo)) {
  91. const t = segmentQueue.get(goodsArtNo)
  92. if (t) clearTimeout(t)
  93. segmentQueue.delete(goodsArtNo)
  94. }
  95. const timeoutId = setTimeout(async () => {
  96. segmentQueue.delete(goodsArtNo)
  97. if (!isGoodsStillInList(goodsArtNo)) return
  98. try {
  99. await socketStore.connectSocket();
  100. socketStore.sendMessage({
  101. type: 'segment_progress',
  102. data: {
  103. token: tokenInfoStore.getToken,
  104. uuid: uuidStore?.getUuid || '',
  105. goods_art_no: [goodsArtNo],
  106. }
  107. })
  108. } catch (e) {
  109. // 忽略发送异常,避免打断主流程
  110. }
  111. }, 20000)
  112. segmentQueue.set(goodsArtNo, timeoutId)
  113. }
  114. /**
  115. * 保存货号模板到货号变量中。
  116. */
  117. function saveGoodsArtNo() {
  118. if (goods_art_no_tpl.value) {
  119. goods_art_no.value = goods_art_no_tpl.value
  120. ElMessage.success('商品货号' + goods_art_no.value + '获取成功,请在遥控器上按下左或右脚按键,启动拍摄')
  121. }
  122. }
  123. /**
  124. * 获取拍照记录。
  125. * @param params - 可选参数,用于分页或其他筛选条件。
  126. */
  127. async function getPhotoRecords(params?: { page?: number; size?: number; goods_art_no?: string }) {
  128. if (loading.value) return;
  129. loading.value = true;
  130. const page = params?.page ?? currentPage.value ?? 1
  131. const size = params?.size ?? pageSize.value ?? 10
  132. console.log('params' , {
  133. ...params,
  134. page,
  135. size,
  136. })
  137. clientStore.ipc.send(icpList.takePhoto.getPhotoRecords, {
  138. ...params,
  139. page,
  140. size,
  141. });
  142. clientStore.ipc.on(icpList.takePhoto.getPhotoRecords, (event, result) => {
  143. loading.value = false;
  144. if (result.code === 0) {
  145. clientStore.ipc.removeAllListeners(icpList.takePhoto.getPhotoRecords);
  146. //console.log('getPhotoRecords print_time:' + new Date().toLocaleString())
  147. // console.log('getPhotoRecords print_time:' + JSON.stringify(result.data.list))
  148. console.log(result.data)
  149. // 在设置 goodsList.value 之前,检查 items 数组中的 action_name 是否为 null
  150. const modifiedList = result.data.list.map(item => {
  151. // 检查 items 数组中是否有 action_name 为 null 的情况
  152. const hasNullActionName = item.items && Array.isArray(item.items) &&
  153. item.items.some(image => image.action_name === null || image.action_name === undefined);
  154. // 根据检查结果设置 syncConfig
  155. return {
  156. ...item,
  157. syncConfig: hasNullActionName ? false : true
  158. };
  159. });
  160. goodsList.value = modifiedList;
  161. // update pagination info if provided by API
  162. if (result.data) {
  163. currentPage.value = result.data.current_page || page
  164. totalPages.value = result.data.total_pages || 1
  165. }
  166. if (isDelGoodsGetList.value) {
  167. isDelGoodsGetList.value = false;
  168. return;
  169. }
  170. getLastPhotoRecord()
  171. } else if (result.msg) {
  172. ElMessage.error(result.msg)
  173. }
  174. });
  175. }
  176. /**
  177. * 执行拍照操作。
  178. * @param data - 包含拍摄所需的数据对象。
  179. */
  180. async function runGoods(data) {
  181. if (runLoading.value || takePictureLoading.value) {
  182. ElMessage.error('拍摄程序正在运行,请稍候')
  183. return
  184. }
  185. await socketStore.connectSocket();
  186. socketStore.sendMessage({
  187. type: 'run_mcu',
  188. data,
  189. })
  190. runLoading.value = true;
  191. runAction.value.action = data.action
  192. runAction.value.goods_art_no = data.goods_art_no
  193. // goods_art_no.value = ''
  194. goods_art_no_tpl.value = ''
  195. reNosObj.value.goods_art_no = null;
  196. reNosObj.value.action = null;
  197. searchGoodsArtNo.value = ''
  198. clientStore.ipc.on(icpList.socket.message + '_run_mcu', (event, result) => {
  199. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu');
  200. console.log('_run_mcu');
  201. console.log(result);
  202. if (result.code !== 0 && result.msg) {
  203. ElMessage.error(result.msg)
  204. runLoading.value = false
  205. return;
  206. } else {
  207. ElMessage.success('开始拍摄,请稍后')
  208. }
  209. })
  210. }
  211. /**
  212. * 格式化时间字符串。
  213. * @param time - 原始时间字符串。
  214. * @returns 格式化后的时间字符串,若输入为空则返回 null。
  215. */
  216. const getTime = function (time) {
  217. if (!time) return null
  218. return time.replace('T', ' ').substr(5, 11)
  219. }
  220. /**
  221. * 删除所有商品货号的历史记录。
  222. */
  223. async function delAll() {
  224. let params = goodsList.value.map(item => item.goods_art_no)
  225. try {
  226. await ElMessageBox.confirm('确定要删除当下的历史记录吗?', '提示', {
  227. confirmButtonText: '确定',
  228. cancelButtonText: '取消',
  229. })
  230. await clickLog({ describe: { action: '点击确认一键删除', goods_art_nos: params } }, route)
  231. del({ goods_art_nos: params })
  232. } catch (e) {
  233. await clickLog({ describe: { action: '点击取消一键删除' } }, route)
  234. }
  235. }
  236. /**
  237. * 删除指定的商品货号。
  238. * @param params - 包含需要删除的货号列表的对象。
  239. */
  240. const delGoods = async function (params) {
  241. try {
  242. await ElMessageBox.confirm('确定要删除货号:' + params.goods_art_nos[0] + '的拍摄数据吗?', '提示', {
  243. confirmButtonText: '确定',
  244. cancelButtonText: '取消',
  245. })
  246. await clickLog({ describe: { action: '点击确认删除货号', goods_art_no: params.goods_art_nos?.[0] } }, route)
  247. del(params)
  248. } catch (e) {
  249. await clickLog({ describe: { action: '点击取消删除货号', goods_art_no: params.goods_art_nos?.[0] } }, route)
  250. }
  251. }
  252. /**
  253. * 删除指定的商品货号。
  254. * @param params - 包含需要删除的货号列表的对象。
  255. */
  256. const del = async function (params) {
  257. console.log(icpList.takePhoto.delectGoodsArts, params);
  258. clientStore.ipc.removeAllListeners(icpList.takePhoto.delectGoodsArts);
  259. clientStore.ipc.send(icpList.takePhoto.delectGoodsArts, params);
  260. clientStore.ipc.on(icpList.takePhoto.delectGoodsArts, (event, result) => {
  261. clientStore.ipc.removeAllListeners(icpList.takePhoto.delectGoodsArts);
  262. console.log("icpList.takePhoto.delectGoodsArts", params);
  263. if (result.code === 0) {
  264. isDelGoodsGetList.value = true
  265. ElMessage.info('货号删除成功')
  266. getPhotoRecords()
  267. if (reNosObj.value.goods_art_no) {
  268. runGoods(
  269. {
  270. "action": reNosObj.value.action,
  271. "goods_art_no": reNosObj.value.goods_art_no
  272. })
  273. }
  274. } else if (result.msg) {
  275. ElMessage.error(result.msg)
  276. }
  277. });
  278. }
  279. //单个重拍
  280. const reTakePicture = async (img) => {
  281. if (!img.id) return;
  282. if (img.image_path) {
  283. try {
  284. await ElMessageBox.confirm('此操作会先删除此数据,需要继续吗?', '提示', {
  285. confirmButtonText: '确定',
  286. cancelButtonText: '取消',
  287. })
  288. await clickLog({ describe: { action: '点击确认单张重拍', goods_art_no: img.goods_art_no, action_name: img.action_name } }, route)
  289. } catch (e) {
  290. await clickLog({ describe: { action: '点击取消单张重拍', goods_art_no: img.goods_art_no, action_name: img.action_name } }, route)
  291. return
  292. }
  293. }
  294. runLoading.value = true;
  295. reNosObj.value.goods_art_no = img.goods_art_no
  296. reNosObj.value.action = 're_take_picture'
  297. let params = {
  298. id: img.action_id
  299. }
  300. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigDetail);
  301. clientStore.ipc.send(icpList.setting.getDeviceConfigDetail, params);
  302. clientStore.ipc.on(icpList.setting.getDeviceConfigDetail, (event, result) => {
  303. console.log('getDeviceConfigDetail')
  304. console.log(result)
  305. if (result.code == 0 && result.data) {
  306. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigDetail);
  307. this_run_mcu_single(result.data)
  308. } else if (result.msg) {
  309. runLoading.value = false;
  310. reNosObj.value.goods_art_no = ''
  311. reNosObj.value.action = ''
  312. ElMessage.error(result.msg)
  313. }
  314. });
  315. function this_run_mcu_single(data) {
  316. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_single');
  317. socketStore.sendMessage({
  318. type: 'run_mcu_single',
  319. data: {
  320. camera_height: Number(data.camera_height),
  321. camera_angle: Number(data.camera_angle),
  322. led_switch: data.led_switch,
  323. id: 0,
  324. mode_type: data.mode_type,
  325. turntable_position: Number(data.turntable_position),
  326. action_name: data.action_name || '测试',
  327. turntable_angle: Number(data.turntable_angle),
  328. shoe_upturn: Number(data.shoe_upturn),
  329. action_index: 1,
  330. number_focus: 0,
  331. take_picture: false,
  332. point_name:data.point_name,
  333. is_move_device: data.is_move_device,
  334. pre_delay: 0,
  335. after_delay: 0,
  336. }
  337. });
  338. clientStore.ipc.on(icpList.socket.message + '_run_mcu_single', async (event, result) => {
  339. console.log('_run_mcu_single_row')
  340. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_single');
  341. this_re_take_picture(data)
  342. })
  343. }
  344. async function this_re_take_picture(data) {
  345. await ElMessageBox.alert('已复位到该视图下,请把鞋子摆放完毕之后,点击按钮开始重拍', '提示', {
  346. confirmButtonText: "开始重拍",
  347. showClose: false,
  348. closeOnClickModal: false,
  349. closeOnPressEscape: false
  350. })
  351. await clickLog({ describe: { action: '点击开始重拍', goods_art_no: img.goods_art_no } }, route)
  352. socketStore.sendMessage({
  353. type: 'smart_shooter_photo_take',
  354. "data": {
  355. "id": img.id,
  356. "goods_art_no": img.goods_art_no,
  357. point_name:data.point_name,
  358. is_move_device: data.is_move_device
  359. },
  360. })
  361. }
  362. }
  363. const resetStatus = () => {
  364. runLoading.value = false;
  365. reNosObj.value.goods_art_no = ''
  366. reNosObj.value.action = ''
  367. runAction.value.goods_art_no = '';
  368. runAction.value.action = '';
  369. }
  370. //货号重拍
  371. const reTakePictureNos = async (goods_art_no, item) => {
  372. try {
  373. await ElMessageBox.confirm('此操作会先删除删除货号:' + goods_art_no + '的拍摄数据吗,需要继续吗?', '提示', {
  374. confirmButtonText: '确定',
  375. cancelButtonText: '取消',
  376. })
  377. await clickLog({ describe: { action: '点击确认重拍货号', goods_art_no } }, route)
  378. } catch (e) {
  379. await clickLog({ describe: { action: '点击取消重拍货号', goods_art_no } }, route)
  380. return
  381. }
  382. reNosObj.value.goods_art_no = goods_art_no
  383. reNosObj.value.action = '执行左脚程序'
  384. console.log(item);
  385. if (item.items && typeof item.items === 'object' && item.items[0].PhotoRecord.image_deal_mode) {
  386. reNosObj.value.action = '执行右脚程序'
  387. }
  388. del({ goods_art_nos: [goods_art_no] })
  389. }
  390. /**
  391. * 检查是否可以进入下一步操作。
  392. */
  393. const next = async function () {
  394. if (runLoading.value) {
  395. ElMessage.error('正在拍摄中,请稍候')
  396. return;
  397. }
  398. if (goodsList.length) {
  399. ElMessage.error('请先拍摄商品。')
  400. return;
  401. }
  402. }
  403. const oneClickStop = () => {
  404. if (!(runLoading.value || takePictureLoading.value)) {
  405. ElMessage.error('拍摄程序已结束,不需要单独停止!')
  406. return
  407. } else {
  408. socketStore.sendMessage({
  409. type: 'stop_action',
  410. })
  411. }
  412. }
  413. /**
  414. * 打开最近一张拍摄图
  415. */
  416. const getLastPhotoRecord = async () => {
  417. return;
  418. if (goodsList.value && goodsList.value.length === 0) return;
  419. clientStore.ipc.removeAllListeners(icpList.takePhoto.getLastPhotoRecord);
  420. clientStore.ipc.send(icpList.takePhoto.getLastPhotoRecord,);
  421. clientStore.ipc.on(icpList.takePhoto.getLastPhotoRecord, (event, result) => {
  422. console.log('getLastPhotoRecord');
  423. console.log(result.data?.goods_art_no);
  424. clientStore.ipc.removeAllListeners(icpList.takePhoto.getLastPhotoRecord);
  425. if (result.code === 0) {
  426. if (lastPhoto.value?.photo_file_name) {
  427. // if( lastPhoto.value?.image_path == result.data?.image_path) return;
  428. if (runAction.value.goods_art_no === result.data?.goods_art_no) {
  429. showlastPhoto.value = true
  430. }
  431. }
  432. lastPhoto.value = result.data
  433. } else if (result.msg) {
  434. ElMessage.error(result.msg)
  435. }
  436. });
  437. }
  438. /**
  439. * 打开主图详情页面。
  440. */
  441. function openPhotographyDetail() {
  442. // 埋点:开始生成
  443. clickLog({ describe: { action: '开始生成', goods_count: goodsList.value.length, goods_art_nos: goodsList.value.map(item => item.goods_art_no) } }, route);
  444. if (runLoading.value || takePictureLoading.value) {
  445. ElMessage.error('正在拍摄中,请稍候')
  446. return;
  447. }
  448. const { href } = Router.resolve({
  449. name: 'PhotographyDetail',
  450. query: {
  451. goods_art_nos: goodsList.value.map(item => item.goods_art_no),
  452. }
  453. })
  454. clientStore.ipc.removeAllListeners(icpList.utils.openMain);
  455. let params = {
  456. title: '主图与详情生成',
  457. width: 3840,
  458. height: 2160,
  459. frame: true,
  460. id: "PhotographyDetail",
  461. url: getRouterUrl(href)
  462. }
  463. clientStore.ipc.send(icpList.utils.openMain, params);
  464. }
  465. /*高级生成*/
  466. const onGenerateCLick = (menu, item) => {
  467. if (menu.name === '历史记录') {
  468. menu.click()
  469. return
  470. }
  471. const firstWithImagePath = item.items.find(
  472. (image) => image.PhotoRecord.image_path
  473. );
  474. if (firstWithImagePath) {
  475. menu.click({
  476. query: {
  477. image_path: firstWithImagePath.PhotoRecord.image_path
  478. }
  479. })
  480. } else {
  481. menu.click()
  482. }
  483. }
  484. // 打开输出目录:appConfig.appPath + '/build/extraResources/py/output'
  485. const openOutputDir = () => {
  486. try {
  487. const appPath = configInfoStore?.appConfig?.appPath || ''
  488. if (!appPath) {
  489. ElMessage.error('未获取到应用目录 appPath')
  490. return
  491. }
  492. const fullPath = `${appPath}\\output`
  493. clientStore.ipc.removeAllListeners(icpList.utils.shellFun);
  494. clientStore.ipc.send(icpList.utils.shellFun, {
  495. action: 'openMkPath',
  496. params: fullPath.replace(/\//g, '\\')
  497. });
  498. } catch (e) {
  499. console.error(e)
  500. ElMessage.error('打开目录失败')
  501. }
  502. }
  503. const menu = computed(() => {
  504. if (configInfoStore.appModel === 2) {
  505. return [
  506. {
  507. type: 'setting'
  508. },
  509. {
  510. name: '切换模式',
  511. click() {
  512. configInfoStore.updateAppModel(1)
  513. Router.push({
  514. name: 'PhotographyCheck'
  515. })
  516. }
  517. },
  518. {
  519. name: '生成图目录',
  520. click() {
  521. openOutputDir()
  522. }
  523. },
  524. {
  525. ...generate
  526. }
  527. ]
  528. }
  529. if (useUserInfoStore.userInfo.brand_company_code === '1300' || configInfoStore.appConfig.debug) {
  530. return [
  531. {
  532. type: 'setting'
  533. },
  534. {
  535. type: 'developer'
  536. },
  537. {
  538. name: '生成图目录',
  539. click() {
  540. openOutputDir()
  541. }
  542. },
  543. {
  544. ...generate,
  545. }
  546. ]
  547. }
  548. return [
  549. {
  550. type: 'setting'
  551. },
  552. {
  553. name: '生成图目录',
  554. click() {
  555. openOutputDir()
  556. }
  557. },
  558. {
  559. ...generate
  560. }
  561. ]
  562. })
  563. const onRemoteControl = async (type) => {
  564. const pointName = await getPhotoPointName()
  565. if (type == 'take_picture') {
  566. // 埋点:手动拍照
  567. clickLog({ describe: { action: '点击遥控器拍照按钮', point_name: pointName } }, route);
  568. if (runLoading.value || takePictureLoading.value) {
  569. ElMessage.error('拍摄程序正在运行,请稍候')
  570. return
  571. }
  572. ElMessage.success('正在拍摄中,请稍候')
  573. takePictureLoading.value = true;
  574. socketStore.sendMessage({
  575. type: 'handler_take_picture',
  576. data: {
  577. point_name: pointName
  578. }
  579. })
  580. return;
  581. }
  582. if (!goods_art_no.value) {
  583. ElMessage.error('请在左侧第一步中,先扫描货号或者手动输入货号!')
  584. goodsArtNo.value?.focus() // 聚焦输入框
  585. return;
  586. }
  587. let action = '执行左脚程序'
  588. if (type === 'right') action = '执行右脚程序'
  589. // 埋点:遥控器启动拍摄
  590. clickLog({ describe: { action: `点击遥控器${type === 'left' ? '左脚' : '右脚'}按钮`, goods_art_no: goods_art_no.value, point_name: pointName } }, route);
  591. runGoods({
  592. "action": action,
  593. "goods_art_no": goods_art_no.value
  594. })
  595. }
  596. // 初始化事件监听
  597. const initEventListeners = () => {
  598. // 监听蓝牙扫描事件
  599. clientStore.ipc.on(icpList.socket.message + '_blue_tooth_scan', (event, result) => {
  600. console.log('_blue_tooth_scan')
  601. if (result.code === 0 && result.data?.data) {
  602. console.log(goods_art_no.value);
  603. if (!goods_art_no.value) {
  604. ElMessage.error('请在左侧第一步中,先扫描货号或者手动输入货号!')
  605. goodsArtNo.value?.focus() // 聚焦输入框
  606. return;
  607. }
  608. runGoods({
  609. ...result.data?.data,
  610. goods_art_no: goods_art_no.value
  611. })
  612. }
  613. });
  614. // 监听图片处理完成事件
  615. clientStore.ipc.on(icpList.socket.message + '_image_process', (event, result) => {
  616. console.log('_image_process')
  617. console.log(result)
  618. getPhotoRecords()
  619. // 延迟两秒再获取一遍数据
  620. setTimeout(() => {
  621. getPhotoRecords()
  622. }, 3000)
  623. })
  624. // 监听拍照完成事件
  625. clientStore.ipc.on(icpList.socket.message + '_photo_take', (event, result) => {
  626. console.log('_photo_take')
  627. console.log(result)
  628. if (result.status === 2 && result.msg.includes('执行完成')) {
  629. getPhotoRecords()
  630. searchGoodsArtNo.value = ''
  631. // 延迟两秒再获取一遍数据
  632. setTimeout(() => {
  633. searchGoodsArtNo.value = ''
  634. getPhotoRecords()
  635. }, 3000)
  636. takePictureLoading.value = false;
  637. return;
  638. }
  639. if (result.code !== 0 && result.msg) {
  640. ElMessage.error(result.msg)
  641. takePictureLoading.value = false;
  642. }
  643. })
  644. // 监听一键停止
  645. clientStore.ipc.on(icpList.socket.message + '_stop_action', (event, result) => {
  646. console.log('_stop_action')
  647. console.log(result)
  648. oneClickStop()
  649. })
  650. // 监听一键停止结束
  651. clientStore.ipc.on(icpList.socket.message + '_run_mcu_stop', (event, result) => {
  652. console.log('_run_mcu_stop')
  653. resetStatus()
  654. })
  655. // 监听拍照完成后的最终状态事件
  656. clientStore.ipc.on(icpList.socket.message + '_photo_take_finish', (event, result) => {
  657. console.log('_photo_take_finish')
  658. console.log(result)
  659. if (result.code === 0) {
  660. setLogInfo(route, { action: '全部拍摄完成', goods_art_no: runAction.value.goods_art_no });
  661. // 全部拍摄完成后,触发抠图队列
  662. if (runAction.value.goods_art_no) {
  663. scheduleSegment(runAction.value.goods_art_no)
  664. }
  665. runLoading.value = false;
  666. runAction.value.goods_art_no = '';
  667. runAction.value.action = '';
  668. setTimeout(() => {
  669. showlastPhoto.value = false
  670. }, 3000)
  671. }
  672. })
  673. // 监听手动触发拍照事件
  674. clientStore.ipc.on(icpList.socket.message + '_handler_take_picture', async (event, result) => {
  675. console.log('_handler_take_picture')
  676. console.log(result)
  677. if (result.code === 0) {
  678. if (runLoading.value || takePictureLoading.value) {
  679. ElMessage.error('拍摄程序正在运行,请稍候')
  680. return
  681. }
  682. ElMessage.success('正在拍摄中,请稍候')
  683. takePictureLoading.value = true;
  684. // await socketStore.connectSocket();
  685. // socketStore.sendMessage(result.data)
  686. getPhotoRecords()
  687. // 延迟两秒再获取一遍数据
  688. setTimeout(() => {
  689. searchGoodsArtNo.value = ''
  690. getPhotoRecords()
  691. }, 3000)
  692. } else if (result.msg) {
  693. ElMessage.error(result.msg)
  694. }
  695. })
  696. //拍照成功 SmartShooter
  697. clientStore.ipc.on(icpList.socket.message + '_smart_shooter_photo_take', async (event, result) => {
  698. console.log('_smart_shooter_photo_take');
  699. console.log(result);
  700. if (result.code === 0) {
  701. if (!result.data.goods_art_no) return;
  702. setLogInfo(route, { action: '单张拍摄完成', goods_art_no: result.data.goods_art_no });
  703. if (reNosObj.value?.goods_art_no === result.data.goods_art_no) {
  704. runLoading.value = false;
  705. reNosObj.value.goods_art_no = ''
  706. reNosObj.value.action = ''
  707. }
  708. // 单张重拍完成且存在重拍货号时,触发抠图队列
  709. scheduleSegment(result.data.goods_art_no)
  710. if (smartShooterTimeout) {
  711. clearTimeout(smartShooterTimeout);
  712. }
  713. setTimeout(() => {
  714. showlastPhoto.value = true;
  715. lastPhoto.value = {
  716. file_path: result.data.photo_file_name
  717. };
  718. setTimeout(() => {
  719. if (!runAction.value.goods_art_no) {
  720. showlastPhoto.value = false;
  721. }
  722. }, 3000)
  723. }, 100);
  724. smartShooterTimeout = setTimeout(() => {
  725. getPhotoRecords();
  726. if (!runAction.value.goods_art_no) {
  727. showlastPhoto.value = false;
  728. }
  729. }, 2000);
  730. } else if (result.msg) {
  731. runLoading.value = false;
  732. reNosObj.value.goods_art_no = ''
  733. reNosObj.value.action = ''
  734. ElMessage.error(result.msg)
  735. }
  736. })
  737. // 监听拍照完成后的最终状态事件
  738. clientStore.ipc.on(icpList.socket.message + '_run_mcu_update', (event, result) => {
  739. console.log('run_mcu_updat print_time:' + new Date().toLocaleString())
  740. console.log('run_mcu_update print_time:' + JSON.stringify(result))
  741. if (result.code === 0) {
  742. if (result.data?.file_path) {
  743. if (lastPhoto.value?.file_path == result.data?.file_path) return;
  744. let goods_art_no = runAction.value.goods_art_no || reNosObj.value.goods_art_no
  745. if (goods_art_no === result.data?.goods_art_no) {
  746. showlastPhoto.value = true
  747. goodsList.value.map(item => {
  748. if (item.goods_art_no === result.data?.goods_art_no) {
  749. item.items[result.data.image_index].PhotoRecord.image_path = result.data?.file_path
  750. result.data.action_name = item.items[result.data.image_index].action_name
  751. setTimeout(() => {
  752. item.items[result.data.image_index].PhotoRecord.image_path = result.data?.file_path
  753. }, 1000)
  754. setTimeout(() => {
  755. showlastPhoto.value = false
  756. }, 3000)
  757. }
  758. })
  759. setTimeout(() => {
  760. getPhotoRecords()
  761. }, 2000)
  762. }
  763. lastPhoto.value = result.data
  764. }
  765. } else if (result.msg) {
  766. ElMessage.error(result.msg)
  767. }
  768. if (reNosObj.value.goods_art_no) {
  769. resetStatus()
  770. }
  771. })
  772. }
  773. // 清理事件监听
  774. const cleanupEventListeners = () => {
  775. clientStore.ipc.removeAllListeners(icpList.socket.message + '_blue_tooth_scan');
  776. clientStore.ipc.removeAllListeners(icpList.socket.message + '_image_process');
  777. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu');
  778. clientStore.ipc.removeAllListeners(icpList.socket.message + '_photo_take');
  779. clientStore.ipc.removeAllListeners(icpList.socket.message + '_photo_take_finish');
  780. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_update');
  781. clientStore.ipc.removeAllListeners(icpList.socket.message + '_stop_action');
  782. clientStore.ipc.removeAllListeners(icpList.socket.message + '_smart_shooter_photo_take');
  783. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_stop');
  784. clientStore.ipc.removeAllListeners(icpList.socket.message + '_digicam_take_picture');
  785. clientStore.ipc.removeAllListeners(icpList.socket.message + '_segment_progress');
  786. // 清理抠图队列的定时器
  787. try {
  788. segmentQueue.forEach((t) => { if (t) clearTimeout(t) })
  789. segmentQueue.clear()
  790. } catch (e) { }
  791. }
  792. // 监听蓝牙扫描
  793. checkInfoStore.set_blue_tooth_scan_NO('')
  794. watchEffect(async () => {
  795. if (checkInfoStore.blue_tooth_scan_NO) {
  796. ElMessage.success('商品货号' + checkInfoStore.blue_tooth_scan_NO + '获取成功,请在遥控器上按下左或右脚按键,启动拍摄')
  797. goods_art_no.value = checkInfoStore.blue_tooth_scan_NO
  798. checkInfoStore.set_blue_tooth_scan_NO('')
  799. }
  800. })
  801. /**
  802. * 导入图片目录。
  803. * @param dirPath - 需要导入的目录路径。
  804. */
  805. const importDirs = function (dirPath: string) {
  806. clientStore.ipc.removeAllListeners(icpList.takePhoto.import_dirs);
  807. clientStore.ipc.send(icpList.takePhoto.import_dirs, { dir_path: dirPath });
  808. clientStore.ipc.on(icpList.takePhoto.import_dirs, (event, result) => {
  809. clientStore.ipc.removeAllListeners(icpList.takePhoto.import_dirs);
  810. if (result.code === 0) {
  811. getPhotoRecords()
  812. } else {
  813. ElMessage.error(result.msg || '导入图片失败')
  814. }
  815. });
  816. }
  817. /**
  818. * 删除所有货号。
  819. */
  820. const deleteAllGoods = function () {
  821. clientStore.ipc.removeAllListeners(icpList.takePhoto.delete_all_goods_arts);
  822. clientStore.ipc.send(icpList.takePhoto.delete_all_goods_arts);
  823. clientStore.ipc.on(icpList.takePhoto.delete_all_goods_arts, (event, result) => {
  824. clientStore.ipc.removeAllListeners(icpList.takePhoto.delete_all_goods_arts);
  825. if (result.code === 0) {
  826. ElMessage.success('删除所有货号成功')
  827. getPhotoRecords()
  828. } else {
  829. ElMessage.error(result.msg || '删除所有货号失败')
  830. }
  831. });
  832. }
  833. return {
  834. loading,
  835. runLoading,
  836. takePictureLoading,
  837. goodsList,
  838. pageSize,
  839. currentPage,
  840. totalPages,
  841. goods_art_no_tpl,
  842. goods_art_no,
  843. runAction,
  844. lastPhoto,
  845. showlastPhoto,
  846. goodsArtNo,
  847. searchGoodsArtNo,
  848. menu,
  849. configInfoStore,
  850. getTime,
  851. getFilePath,
  852. getPhotoRecords,
  853. delAll,
  854. delGoods,
  855. del,
  856. importDirs,
  857. deleteAllGoods,
  858. reTakePicture,
  859. reTakePictureNos,
  860. oneClickStop,
  861. onRemoteControl,
  862. openPhotographyDetail,
  863. onGenerateCLick,
  864. initEventListeners,
  865. cleanupEventListeners,
  866. }
  867. }