shot.vue 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757
  1. <template>
  2. <headerBar
  3. :title="configInfoStore.appModel === 1 ? '拍摄商品' : '处理图像'"
  4. showUser
  5. :menu="menu"
  6. />
  7. <hardware-check/>
  8. <div class="photography-page flex-col">
  9. <div class="main-container">
  10. <template v-if="configInfoStore.appModel === 1 ">
  11. <div class="content-wrapper flex-row">
  12. <!-- <img class="camera-image" referrerpolicy="no-referrer" src="@/assets/images/Photography/camera-icon.png" />-->
  13. <div class="step-number flex-col"><span class="text_22">1</span></div>
  14. <div class="step-one flex-col justify-between">
  15. <div class="step-header flex-row">
  16. <span class="step-title">第一步:获取商品货号</span>
  17. <img class="step-icon" referrerpolicy="no-referrer" src="@/assets/images/Photography/step1-icon.png" />
  18. <img class="step-divider" referrerpolicy="no-referrer"
  19. src="@/assets/images/Photography/step-divider-line.png" />
  20. </div>
  21. <div class="step-content flex-row justify-between">
  22. <div class="method-container flex-col">
  23. <div class="input-container flex-row">
  24. <el-input class="input-item" ref="goodsArtNo" v-model="goods_art_no" placeholder="请输入货号"> </el-input>
  25. </div>
  26. <div class="auto-method flex-row justify-between">
  27. <div class="text-method-tag flex-col"><span class="text_4">自动获取</span></div>
  28. <span class="method-description">用遥控器扫描商品资料二维码</span>
  29. </div>
  30. <div class="scan-method flex-row justify-between">
  31. <div class="remote-control flex-col">
  32. </div>
  33. <!-- <span class="scan-label">遥控器扫描键</span>-->
  34. </div>
  35. </div>
  36. <img class="remote-image" referrerpolicy="no-referrer"
  37. src="@/assets/images/Photography/remote-control.png" />
  38. </div>
  39. </div>
  40. <div class="step-number flex-col"><span class="text_22">2</span></div>
  41. <div class="step-two flex-col justify-between">
  42. <span class="step-title">第二步:启动拍摄(根据按遥控器左右键启动)</span>
  43. <div class="shooting-container flex-col">
  44. <div class="shooting-tips flex-row justify-between">
  45. <img class="info-icon" referrerpolicy="no-referrer" src="@/assets/images/Photography/info-icon.png" />
  46. <span class="tips-text">遥控左右按键可启动拍摄,中间按钮可在拍摄5张主图后解锁,用于拍摄自定义图</span>
  47. </div>
  48. <div class="wifi mar-top-20">
  49. <img referrerpolicy="no-referrer"
  50. src="@/assets/images/Photography/wifi.png" style="width: 60px" />
  51. </div>
  52. <div class="remote-control-wrap">
  53. <RemoteControl
  54. @onRemoteControl="onRemoteControl"
  55. />
  56. </div>
  57. </div>
  58. </div>
  59. </div>
  60. <div class="last-photo" v-show="showlastPhoto" v-key="lastPhoto.file_path">
  61. <!-- <div class="flex between">
  62. <div></div>
  63. <div class="flex-item">{{ lastPhoto.action_name || '' }}</div>
  64. <div class="close">
  65. <el-icon style="color: #000" @click="showlastPhoto = false" class="close-icon" v-log="{ describe: { action: '关闭最近拍照预览' } }">
  66. <Close/>
  67. </el-icon>
  68. </div>
  69. </div>-->
  70. <el-image :src="getFilePath(lastPhoto.file_path)" fit="cover" ></el-image>
  71. </div>
  72. </template>
  73. <div class="history-section flex-col"
  74. :class="configInfoStore.appModel === 2 ? 'koutu-section' : ''"
  75. >
  76. <span class="history-title flex between">
  77. <div>拍摄记录</div>
  78. <div class="c-666 fs-12" v-if="goodsList.length" >
  79. <el-button :disabled="!(runLoading || takePictureLoading)" @click="oneClickStop" v-if="configInfoStore.appModel === 1" class="input-button" type="primary" size="mini" v-log="{ describe: { action: '一键停止拍摄' } }">一键停止</el-button>
  80. <el-button :disabled="runLoading || takePictureLoading" @click="delAll" class="input-button" type="danger" size="mini" v-log="{ describe: { action: '一键删除所有记录' } }">一键删除</el-button>
  81. </div>
  82. </span>
  83. <img class="divider-line" referrerpolicy="no-referrer" src="@/assets/images/Photography/divider-line.png" />
  84. <div class="history-warp">
  85. <div v-if="!goodsList.length" class="fs-14 c-666 mar-top-50">
  86. {{ loading ? '数据正在加载中,请稍候...' : '暂无数据,请先进行拍摄'}}
  87. </div>
  88. <div v-else class="history-item clearfix" v-for="item,index in goodsList" style="padding:10px;">
  89. <div class="flex between flex-item c-333">
  90. <div class="chaochu flex-item flex left">货号:{{ item.goods_art_no }}</div>
  91. <div >
  92. <!--
  93. <el-button :disabled="runLoading || takePictureLoading" size="small" plain >高级生成</el-button>
  94. -->
  95. <el-dropdown @command="handleGenerateCommand" :disabled="runLoading || takePictureLoading" >
  96. <el-button :disabled="runLoading || takePictureLoading" size="small" plain style="margin-right: 5px" >高级生成</el-button>
  97. <template #dropdown>
  98. <el-dropdown-menu>
  99. <el-dropdown-item
  100. v-for="menu in generate.children"
  101. @click.native="onGenerateCLick(menu,item)">{{ menu.name }}</el-dropdown-item>
  102. </el-dropdown-menu>
  103. </template>
  104. </el-dropdown>
  105. <el-button size="small" :disabled="runLoading || takePictureLoading" @click="delGoods({goods_art_nos:[item.goods_art_no]})" v-log="{ describe: { action: '删除货号', goods_art_no: item.goods_art_no } }">删除</el-button>
  106. </div>
  107. </div>
  108. <div class="flex between flex-item c-333" style="margin-top: 5px">
  109. <div class="c-999 fs-12">{{ getTime(item.action_time) }}</div>
  110. <el-button size="small" :disabled="runLoading || takePictureLoading" type="primary" @click="reTakePictureNos(item.goods_art_no,item)" plain v-if="configInfoStore.appModel === 1" v-log="{ describe: { action: '重拍货号', goods_art_no: item.goods_art_no } }">重拍</el-button>
  111. </div>
  112. <div class="mar-top-10 clearfix history-item_image_wrap" style="width: 100%" >
  113. <component class="history-item_image"
  114. v-for="image,index in item.items"
  115. v-loading="!image.PhotoRecord.image_path && runAction.goods_art_no == item.goods_art_no"
  116. :is="image.PhotoRecord.image_path ? 'div' : 'p'"
  117. >
  118. <span class="tag">{{ image.action_name }}</span>
  119. <el-popover
  120. :popper-class="configInfoStore.appModel === 1 ? 'shot-image-popper' : 'koutu-image-popper'"
  121. :placement=" configInfoStore.appModel === 1 ? 'left' : 'right'"
  122. :hide-after="0"
  123. width="50%"
  124. offset="20"
  125. v-if="image.PhotoRecord.image_path"
  126. >
  127. <template #reference>
  128. <div class="flex el-image_view">
  129. <el-image :src="getFilePath(image.PhotoRecord.image_path)" fit="contain" >
  130. <template #error>
  131. <div class="image-slot"></div>
  132. </template>
  133. </el-image>
  134. <el-button :disabled="runLoading || takePictureLoading" class="reset-button" @click="reTakePicture(image.PhotoRecord)" v-log="{ describe: { action: '重拍单张图片', goods_art_no: image.PhotoRecord.goods_art_no, action_name: image.action_name } }">重拍</el-button>
  135. </div>
  136. </template>
  137. <el-image :src="getFilePath(image.PhotoRecord.image_path)" fit="contain" >
  138. <template #error>
  139. <div class="image-slot"></div>
  140. </template>
  141. </el-image>
  142. </el-popover>
  143. <div class="flex el-image_view" v-else>
  144. <el-image :src="getFilePath(image.PhotoRecord.image_path)" fit="contain">
  145. <template #error>
  146. <div class="image-slot"></div>
  147. <el-button :disabled="runLoading || takePictureLoading" class="reset-button" @click="reTakePicture(image.PhotoRecord)" v-log="{ describe: { action: '重拍单张图片', goods_art_no: image.PhotoRecord.goods_art_no, action_name: image.action_name } }">重拍</el-button>
  148. </template>
  149. </el-image>
  150. </div>
  151. </component>
  152. <div v-if="item.items.length < 5"
  153. v-for="item in (5 - item.items.length)"
  154. class="history-item_image"
  155. >
  156. <span class="tag" style="font-size: 12px;">暂未配置</span>
  157. </div>
  158. </div>
  159. </div>
  160. </div>
  161. <!-- 无数据 -->
  162. <!-- <div class="empty-state flex-col justify-between">
  163. <img
  164. class="empty-icon"
  165. referrerpolicy="no-referrer"
  166. src="@/assets/images/Photography/empty-state-icon.png"
  167. />
  168. <span class="empty-text">暂无数据</span>
  169. </div>-->
  170. <div
  171. class="next-step button--primary1 flex-col"
  172. :class="{ 'is-disabled': !goodsList.length || runLoading || takePictureLoading }"
  173. @click="(!goodsList.length || runLoading || takePictureLoading) ? null : openPhotographyDetail()"
  174. v-log="{ describe: { action: '点击开始生成' } }"
  175. >
  176. <span class="next-step-text">{{ configInfoStore.appModel === 1 ? '开始生成' : '开始生成'}}</span>
  177. </div>
  178. </div>
  179. </div>
  180. </div>
  181. </template>
  182. <script setup lang="ts">
  183. import headerBar from '@/components/header-bar/index.vue'
  184. import { ref, reactive, onMounted, onBeforeUnmount,watchEffect, computed} from 'vue'
  185. import icpList from '@/utils/ipc'
  186. import client from "@/stores/modules/client";
  187. import socket from "@/stores/modules/socket";
  188. import { ElMessage ,ElMessageBox } from 'element-plus'
  189. import { getFilePath,getRouterUrl } from '@/utils/appfun'
  190. import {useRouter} from "vue-router";
  191. import HardwareCheck from '@/components/check/index.vue'
  192. import checkInfo from "@/stores/modules/check";
  193. import RemoteControl from '@/views/RemoteControl/index'
  194. import generate from '@/utils/menus/generate'
  195. const loading = ref(false)
  196. const runLoading = ref(false)
  197. const takePictureLoading = ref(false)
  198. import { Close } from '@element-plus/icons-vue'
  199. import { clickLog, setLogInfo } from '@/utils/log'
  200. import { useUuidStore } from '@/stores/modules/uuid'
  201. import { useRoute } from 'vue-router'
  202. import useUserInfo from "@/stores/modules/user";
  203. const useUserInfoStore = useUserInfo();
  204. const route = useRoute();
  205. import configInfo from '@/stores/modules/config';
  206. const configInfoStore = configInfo();
  207. import qiehuan from '@/components/header-bar/assets/qiehuan.svg'
  208. import tokenInfo from "@/stores/modules/token";
  209. const tokenInfoStore = tokenInfo();
  210. const menu = computed(()=>{
  211. if(configInfoStore.appModel === 2){
  212. return [
  213. {
  214. type:'setting'
  215. },
  216. {
  217. name:'切换模式',
  218. click(){
  219. configInfoStore.updateAppModel(1)
  220. Router.push({
  221. name:'PhotographyCheck'
  222. })
  223. }
  224. },
  225. {
  226. name:'生成图目录',
  227. click(){
  228. openOutputDir()
  229. }
  230. },
  231. {
  232. ...generate
  233. }
  234. ]
  235. }
  236. if(useUserInfoStore.userInfo.brand_company_code === '1300' || configInfoStore.appConfig.debug){
  237. return [
  238. {
  239. type:'setting'
  240. },
  241. {
  242. type:'developer'
  243. },
  244. {
  245. name:'生成图目录',
  246. click(){
  247. openOutputDir()
  248. }
  249. },
  250. {
  251. ...generate,
  252. }
  253. ]
  254. }
  255. return [
  256. {
  257. type:'setting'
  258. },
  259. {
  260. name:'生成图目录',
  261. click(){
  262. openOutputDir()
  263. }
  264. },
  265. {
  266. ...generate
  267. }
  268. ]
  269. })
  270. // 打开输出目录:appConfig.appPath + '/build/extraResources/py/output'
  271. const openOutputDir = () => {
  272. try {
  273. const appPath = configInfoStore?.appConfig?.appPath || ''
  274. if (!appPath) {
  275. ElMessage.error('未获取到应用目录 appPath')
  276. return
  277. }
  278. const fullPath = `${appPath}\\output`
  279. clientStore.ipc.removeAllListeners(icpList.utils.shellFun);
  280. clientStore.ipc.send(icpList.utils.shellFun, {
  281. action: 'openMkPath',
  282. params: fullPath.replace(/\//g, '\\')
  283. });
  284. } catch (e) {
  285. console.error(e)
  286. ElMessage.error('打开目录失败')
  287. }
  288. }
  289. const clientStore = client();
  290. const Router = useRouter()
  291. /*const goodsList = ref([
  292. {
  293. "goods_art_no": "123456789",
  294. "items": [
  295. {
  296. "record_id":1,
  297. "image_deal_mode":0,
  298. "image_path": "C:\\Users\\Administrator\\Pictures\\digiCamControl\\Session1\\DSC_0001.jpg",
  299. },
  300. {
  301. "record_id":2,
  302. "image_deal_mode":0,
  303. "image_path": "C:\\Users\\Administrator\\Pictures\\digiCamControl\\Session1\\DSC_0002.jpg",
  304. },
  305. {
  306. "record_id":3,
  307. "image_deal_mode":0,
  308. "image_path": "C:\\Users\\Administrator\\Pictures\\digiCamControl\\Session1\\DSC_0003.jpg",
  309. },
  310. {
  311. "record_id":4,
  312. "image_deal_mode":0,
  313. "image_path": "C:\\Users\\Administrator\\Pictures\\digiCamControl\\Session1\\DSC_0004.jpg",
  314. },
  315. {
  316. "record_id":5,
  317. "image_deal_mode":0,
  318. "image_path": "C:\\Users\\Administrator\\Pictures\\digiCamControl\\Session1\\DSC_0005.jpg",
  319. }
  320. ]
  321. }
  322. ])*/
  323. const goodsList = ref([])
  324. const goods_art_no_tpl = ref('')
  325. const goods_art_no = ref('')
  326. const runAction = ref({
  327. "action": "",
  328. "goods_art_no": ""
  329. })
  330. // 初始化 WebSocket 状态管理
  331. const socketStore = socket()
  332. const uuidStore = useUuidStore();
  333. // 抠图请求去重与延迟队列(key: goods_art_no, value: timeoutId)
  334. const segmentQueue = new Map<string, ReturnType<typeof setTimeout>>()
  335. function isGoodsStillInList(goodsArtNo: string): boolean {
  336. return goodsList.value?.some((g: any) => g.goods_art_no === goodsArtNo) || false
  337. }
  338. function scheduleSegment(goodsArtNo: string) {
  339. if (!goodsArtNo) return
  340. // 若已存在,则重置计时(重新插入)
  341. if (segmentQueue.has(goodsArtNo)) {
  342. const t = segmentQueue.get(goodsArtNo)
  343. if (t) clearTimeout(t)
  344. segmentQueue.delete(goodsArtNo)
  345. }
  346. const timeoutId = setTimeout(async () => {
  347. segmentQueue.delete(goodsArtNo)
  348. if (!isGoodsStillInList(goodsArtNo)) return
  349. try {
  350. await socketStore.connectSocket();
  351. socketStore.sendMessage({
  352. type: 'segment_progress',
  353. data: {
  354. token:tokenInfoStore.getToken,
  355. uuid: uuidStore?.getUuid || '',
  356. goods_art_no: [goodsArtNo],
  357. }
  358. })
  359. } catch (e) {
  360. // 忽略发送异常,避免打断主流程
  361. }
  362. }, 20000)
  363. segmentQueue.set(goodsArtNo, timeoutId)
  364. }
  365. /**
  366. * 保存货号模板到货号变量中。
  367. */
  368. function saveGoodsArtNo(){
  369. if(goods_art_no_tpl.value){
  370. goods_art_no.value = goods_art_no_tpl.value
  371. ElMessage.success('商品货号'+goods_art_no.value+'获取成功,请在遥控器上按下左或右脚按键,启动拍摄')
  372. }
  373. }
  374. /**
  375. * 获取拍照记录。
  376. * @param params - 可选参数,用于分页或其他筛选条件。
  377. */
  378. async function getPhotoRecords(params?:{}) {
  379. if(loading.value) return;
  380. loading.value = true;
  381. clientStore.ipc.send(icpList.takePhoto.getPhotoRecords,{
  382. ...params,
  383. page:1,
  384. size:100,
  385. });
  386. clientStore.ipc.on(icpList.takePhoto.getPhotoRecords, (event, result) => {
  387. loading.value = false;
  388. if(result.code === 0){
  389. clientStore.ipc.removeAllListeners(icpList.takePhoto.getPhotoRecords);
  390. console.log('getPhotoRecords print_time:'+new Date().toLocaleString()) // 打印当前时间
  391. console.log('getPhotoRecords print_time:'+JSON.stringify(result.data.list)) // 打印当前时间
  392. goodsList.value = result.data.list
  393. if(isDelGoodsGetList.value){
  394. isDelGoodsGetList.value = false;
  395. return;
  396. }
  397. getLastPhotoRecord()
  398. }else if(result.msg) {
  399. ElMessage.error(result.msg)
  400. }
  401. });
  402. }
  403. /**
  404. * 执行拍照操作。
  405. * @param data - 包含拍摄所需的数据对象。
  406. */
  407. async function runGoods(data) {
  408. if(runLoading.value || takePictureLoading.value){
  409. ElMessage.error('拍摄程序正在运行,请稍候')
  410. return
  411. }
  412. await socketStore.connectSocket();
  413. socketStore.sendMessage({
  414. type: 'run_mcu',
  415. data,
  416. })
  417. runLoading.value = true;
  418. runAction.value.action = data.action
  419. runAction.value.goods_art_no = data.goods_art_no
  420. goods_art_no.value = ''
  421. goods_art_no_tpl.value = ''
  422. reNosObj.value.goods_art_no = null;
  423. reNosObj.value.action = null;
  424. clientStore.ipc.on(icpList.socket.message + '_run_mcu', (event, result) => {
  425. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu');
  426. console.log('_run_mcu');
  427. console.log(result);
  428. if(result.code !== 0 && result.msg){
  429. ElMessage.error(result.msg)
  430. runLoading.value = false
  431. return;
  432. }else{
  433. ElMessage.success('开始拍摄,请稍后')
  434. }
  435. })
  436. }
  437. /**
  438. * 格式化时间字符串。
  439. * @param time - 原始时间字符串。
  440. * @returns 格式化后的时间字符串,若输入为空则返回 null。
  441. */
  442. const getTime = function(time){
  443. if(!time) return null
  444. return time.replace('T',' ').substr(5,11)
  445. }
  446. /**
  447. * 删除所有商品货号的历史记录。
  448. */
  449. async function delAll(){
  450. let params = goodsList.value.map(item=>item.goods_art_no)
  451. try {
  452. await ElMessageBox.confirm('确定要删除当下的历史记录吗?', '提示', {
  453. confirmButtonText: '确定',
  454. cancelButtonText: '取消',
  455. })
  456. await clickLog({ describe: { action: '点击确认一键删除', goods_art_nos: params } }, route)
  457. del({goods_art_nos:params})
  458. } catch (e) {
  459. await clickLog({ describe: { action: '点击取消一键删除' } }, route)
  460. }
  461. }
  462. /**
  463. * 删除指定的商品货号。
  464. * @param params - 包含需要删除的货号列表的对象。
  465. */
  466. const delGoods = async function(params){
  467. try {
  468. await ElMessageBox.confirm('确定要删除货号:'+params.goods_art_nos[0]+'的拍摄数据吗?', '提示', {
  469. confirmButtonText: '确定',
  470. cancelButtonText: '取消',
  471. })
  472. await clickLog({ describe: { action: '点击确认删除货号', goods_art_no: params.goods_art_nos?.[0] } }, route)
  473. del(params)
  474. } catch (e) {
  475. await clickLog({ describe: { action: '点击取消删除货号', goods_art_no: params.goods_art_nos?.[0] } }, route)
  476. }
  477. }
  478. /**
  479. * 删除指定的商品货号。
  480. * @param params - 包含需要删除的货号列表的对象。
  481. */
  482. const isDelGoodsGetList = ref(false)
  483. const del = async function(params){
  484. clientStore.ipc.removeAllListeners(icpList.takePhoto.delectGoodsArts);
  485. clientStore.ipc.send(icpList.takePhoto.delectGoodsArts,params);
  486. clientStore.ipc.on(icpList.takePhoto.delectGoodsArts, (event, result) => {
  487. clientStore.ipc.removeAllListeners(icpList.takePhoto.delectGoodsArts);
  488. if(result.code === 0){
  489. isDelGoodsGetList.value =true
  490. ElMessage.info('货号删除成功')
  491. getPhotoRecords()
  492. if(reNosObj.value.goods_art_no){
  493. runGoods(
  494. {
  495. "action": reNosObj.value.action,
  496. "goods_art_no":reNosObj.value.goods_art_no
  497. })
  498. }
  499. }else if(result.msg) {
  500. ElMessage.error(result.msg)
  501. }
  502. });
  503. }
  504. //单个重拍
  505. const reTakePicture = async (img)=>{
  506. if(!img.id) return;
  507. if(img.image_path){
  508. try {
  509. await ElMessageBox.confirm('此操作会先删除此数据,需要继续吗?', '提示', {
  510. confirmButtonText: '确定',
  511. cancelButtonText: '取消',
  512. })
  513. await clickLog({ describe: { action: '点击确认单张重拍', goods_art_no: img.goods_art_no, action_name: img.action_name } }, route)
  514. } catch (e) {
  515. await clickLog({ describe: { action: '点击取消单张重拍', goods_art_no: img.goods_art_no, action_name: img.action_name } }, route)
  516. return
  517. }
  518. }
  519. runLoading.value = true;
  520. reNosObj.value.goods_art_no = img.goods_art_no
  521. reNosObj.value.action = 're_take_picture'
  522. let params = {
  523. id: img.action_id
  524. }
  525. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigDetail);
  526. clientStore.ipc.send(icpList.setting.getDeviceConfigDetail, params);
  527. clientStore.ipc.on(icpList.setting.getDeviceConfigDetail, (event, result) => {
  528. console.log('getDeviceConfigDetail')
  529. console.log(result)
  530. if(result.code == 0 && result.data){
  531. clientStore.ipc.removeAllListeners(icpList.setting.getDeviceConfigDetail);
  532. this_run_mcu_single(result.data)
  533. }else if(result.msg){
  534. runLoading.value = false;
  535. reNosObj.value.goods_art_no = ''
  536. reNosObj.value.action = ''
  537. ElMessage.error(result.msg)
  538. }
  539. });
  540. function this_run_mcu_single(data){
  541. clientStore.ipc.removeAllListeners(icpList.socket.message+'_run_mcu_single');
  542. socketStore.sendMessage({
  543. type: 'run_mcu_single',
  544. data: {
  545. camera_height: Number(data.camera_height),
  546. camera_angle: Number(data.camera_angle),
  547. led_switch:data.led_switch,
  548. id:0,
  549. mode_type:data.mode_type,
  550. turntable_position:Number(data.turntable_position),
  551. action_name:data.action_name || '测试',
  552. turntable_angle: Number(data.turntable_angle),
  553. shoe_upturn: Number(data.shoe_upturn),
  554. action_index:1,
  555. number_focus:0,
  556. take_picture:false,
  557. pre_delay:0,
  558. after_delay:0,
  559. }
  560. });
  561. clientStore.ipc.on(icpList.socket.message+'_run_mcu_single', async (event, result) => {
  562. console.log('_run_mcu_single_row')
  563. clientStore.ipc.removeAllListeners(icpList.socket.message+'_run_mcu_single');
  564. this_re_take_picture()
  565. })
  566. }
  567. async function this_re_take_picture(){
  568. await ElMessageBox.alert('已复位到该视图下,请把鞋子摆放完毕之后,点击按钮开始重拍', '提示',{
  569. confirmButtonText:"开始重拍",
  570. showClose:false,
  571. closeOnClickModal:false,
  572. closeOnPressEscape:false
  573. })
  574. await clickLog({ describe: { action: '点击开始重拍', goods_art_no: img.goods_art_no } }, route)
  575. socketStore.sendMessage({
  576. type: 'smart_shooter_photo_take',
  577. "data":{"id":img.id,"goods_art_no":img.goods_art_no},
  578. })
  579. }
  580. }
  581. const resetStatus = ()=>{
  582. runLoading.value = false;
  583. reNosObj.value.goods_art_no = ''
  584. reNosObj.value.action = ''
  585. runAction.value.goods_art_no = '';
  586. runAction.value.action = '';
  587. }
  588. const reNosObj = ref({
  589. goods_art_no:null,
  590. action:null,
  591. })
  592. //货号重拍
  593. const reTakePictureNos = async (goods_art_no,item)=>{
  594. try {
  595. await ElMessageBox.confirm('此操作会先删除删除货号:'+goods_art_no+'的拍摄数据吗,需要继续吗?', '提示', {
  596. confirmButtonText: '确定',
  597. cancelButtonText: '取消',
  598. })
  599. await clickLog({ describe: { action: '点击确认重拍货号', goods_art_no } }, route)
  600. } catch (e) {
  601. await clickLog({ describe: { action: '点击取消重拍货号', goods_art_no } }, route)
  602. return
  603. }
  604. reNosObj.value.goods_art_no = goods_art_no
  605. reNosObj.value.action = '执行左脚程序'
  606. console.log(item);
  607. if(item.items && typeof item.items === 'object' && item.items[0].PhotoRecord.image_deal_mode){
  608. reNosObj.value.action = '执行右脚程序'
  609. }
  610. del({goods_art_nos:[goods_art_no]})
  611. }
  612. /**
  613. * 检查是否可以进入下一步操作。
  614. */
  615. const next = async function(){
  616. if(runLoading.value){
  617. ElMessage.error('正在拍摄中,请稍候')
  618. return;
  619. }
  620. if(goodsList.length){
  621. ElMessage.error('请先拍摄商品。')
  622. return;
  623. }
  624. }
  625. const oneClickStop = ()=>{
  626. if(!(runLoading.value || takePictureLoading.value)){
  627. ElMessage.error('拍摄程序已结束,不需要单独停止!')
  628. return
  629. }else{
  630. socketStore.sendMessage({
  631. type: 'stop_action',
  632. })
  633. }
  634. }
  635. const goodsArtNo = ref()
  636. /**
  637. * 页面挂载时初始化事件监听器并获取初始数据。
  638. */
  639. onMounted(async () => {
  640. // 监听蓝牙扫描事件
  641. clientStore.ipc.on(icpList.socket.message + '_blue_tooth_scan', (event, result) => {
  642. console.log('_blue_tooth_scan')
  643. if (result.code === 0 && result.data?.data) {
  644. console.log(goods_art_no.value);
  645. if(!goods_art_no.value){
  646. ElMessage.error('请在左侧第一步中,先扫描货号或者手动输入货号!')
  647. goodsArtNo.value?.focus() // 聚焦输入框
  648. return;
  649. }
  650. runGoods({
  651. ...result.data?.data,
  652. goods_art_no: goods_art_no.value
  653. })
  654. }
  655. });
  656. /* window.addEventListener('storage', handleStorageEvent);*/
  657. await getPhotoRecords();
  658. // 监听图片处理完成事件
  659. clientStore.ipc.on(icpList.socket.message + '_image_process', (event, result) => {
  660. console.log('_image_process')
  661. console.log(result)
  662. getPhotoRecords()
  663. // 延迟两秒再获取一遍数据
  664. setTimeout(()=>{
  665. getPhotoRecords()
  666. },3000)
  667. })
  668. // 监听拍照完成事件
  669. clientStore.ipc.on(icpList.socket.message + '_photo_take', (event, result) => {
  670. console.log('_photo_take')
  671. console.log(result)
  672. if(result.status === 2 && result.msg.includes('执行完成')){
  673. getPhotoRecords()
  674. // 延迟两秒再获取一遍数据
  675. setTimeout(()=>{
  676. getPhotoRecords()
  677. },3000)
  678. takePictureLoading.value = false;
  679. return;
  680. }
  681. if(result.code !== 0 && result.msg){
  682. ElMessage.error(result.msg)
  683. takePictureLoading.value = false;
  684. }
  685. })
  686. // 监听一键停止
  687. clientStore.ipc.on(icpList.socket.message + '_stop_action', (event, result) => {
  688. console.log('_stop_action')
  689. console.log(result)
  690. oneClickStop()
  691. })
  692. // 监听一键停止结束
  693. clientStore.ipc.on(icpList.socket.message + '_run_mcu_stop', (event, result) => {
  694. console.log('_run_mcu_stop')
  695. resetStatus()
  696. })
  697. // 监听拍照完成后的最终状态事件
  698. clientStore.ipc.on(icpList.socket.message + '_photo_take_finish', (event, result) => {
  699. console.log('_photo_take_finish')
  700. console.log(result)
  701. if(result.code === 0) {
  702. setLogInfo(route, { action: '全部拍摄完成', goods_art_no: runAction.value.goods_art_no });
  703. // 全部拍摄完成后,触发抠图队列
  704. if (runAction.value.goods_art_no) {
  705. scheduleSegment(runAction.value.goods_art_no)
  706. }
  707. runLoading.value = false;
  708. runAction.value.goods_art_no = '';
  709. runAction.value.action = '';
  710. setTimeout(()=>{
  711. showlastPhoto.value = false
  712. },3000)
  713. }
  714. })
  715. // 监听手动触发拍照事件
  716. clientStore.ipc.on(icpList.socket.message + '_handler_take_picture', async (event, result) => {
  717. console.log('_handler_take_picture')
  718. console.log(result)
  719. if(result.code === 0){
  720. if(runLoading.value || takePictureLoading.value){
  721. ElMessage.error('拍摄程序正在运行,请稍候')
  722. return
  723. }
  724. ElMessage.success('正在拍摄中,请稍候')
  725. takePictureLoading.value = true;
  726. /* setTimeout(()=>{
  727. takePictureLoading.value = false;
  728. },3000)*/
  729. await socketStore.connectSocket();
  730. socketStore.sendMessage(result.data)
  731. getPhotoRecords()
  732. // 延迟两秒再获取一遍数据
  733. setTimeout(()=>{
  734. getPhotoRecords()
  735. },3000)
  736. }
  737. })
  738. })
  739. const onRemoteControl = (type)=>{
  740. if(type == 'take_picture'){
  741. // 埋点:手动拍照
  742. clickLog({ describe: { action: '点击遥控器拍照按钮' } }, route);
  743. if(runLoading.value || takePictureLoading.value){
  744. ElMessage.error('拍摄程序正在运行,请稍候')
  745. return
  746. }
  747. ElMessage.success('正在拍摄中,请稍候')
  748. socketStore.sendMessage({
  749. type: 'handler_take_picture',
  750. })
  751. return;
  752. }
  753. if(!goods_art_no.value){
  754. ElMessage.error('请在左侧第一步中,先扫描货号或者手动输入货号!')
  755. goodsArtNo.value?.focus() // 聚焦输入框
  756. return;
  757. }
  758. let action = '执行左脚程序'
  759. if(type === 'right') action = '执行右脚程序'
  760. // 埋点:遥控器启动拍摄
  761. clickLog({ describe: { action: `点击遥控器${type === 'left' ? '左脚' : '右脚'}按钮`, goods_art_no: goods_art_no.value } }, route);
  762. runGoods({
  763. "action": action,
  764. "goods_art_no": goods_art_no.value,
  765. })
  766. }
  767. /*const handleStorageEvent = (e) => {
  768. if(e.key === 'run_mcu' && e.newValue){
  769. if(!goods_art_no.value){
  770. ElMessage.error('请先扫描货号或者手动输入货号!')
  771. localStorage.setItem('run_mcu','')
  772. return;
  773. }
  774. let action = '执行左脚程序'
  775. if(e.newValue === 'right') action = '执行右脚程序'
  776. runGoods({
  777. "action": action,
  778. "goods_art_no": goods_art_no.value,
  779. })
  780. localStorage.setItem('run_mcu','')
  781. }
  782. };*/
  783. const checkInfoStore = checkInfo()
  784. checkInfoStore.set_blue_tooth_scan_NO('')
  785. watchEffect(async ()=>{
  786. if(checkInfoStore.blue_tooth_scan_NO){
  787. ElMessage.success('商品货号'+checkInfoStore.blue_tooth_scan_NO+'获取成功,请在遥控器上按下左或右脚按键,启动拍摄')
  788. goods_art_no.value = checkInfoStore.blue_tooth_scan_NO
  789. checkInfoStore.set_blue_tooth_scan_NO('')
  790. }
  791. })
  792. /**
  793. * 页面卸载时移除所有事件监听器。
  794. */
  795. onBeforeUnmount(() => {
  796. clientStore.ipc.removeAllListeners(icpList.socket.message + '_blue_tooth_scan');
  797. clientStore.ipc.removeAllListeners(icpList.socket.message + '_image_process');
  798. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu');
  799. clientStore.ipc.removeAllListeners(icpList.socket.message + '_photo_take');
  800. clientStore.ipc.removeAllListeners(icpList.socket.message + '_photo_take_finish');
  801. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_update');
  802. clientStore.ipc.removeAllListeners(icpList.socket.message + '_stop_action');
  803. clientStore.ipc.removeAllListeners(icpList.socket.message + '_smart_shooter_photo_take');
  804. clientStore.ipc.removeAllListeners(icpList.socket.message + '_run_mcu_stop');
  805. clientStore.ipc.removeAllListeners(icpList.socket.message + '_digicam_take_picture');
  806. clientStore.ipc.removeAllListeners(icpList.socket.message + '_segment_progress');
  807. /* window.removeEventListener('storage', handleStorageEvent);*/
  808. // 清理抠图队列的定时器
  809. try {
  810. segmentQueue.forEach((t) => { if (t) clearTimeout(t) })
  811. segmentQueue.clear()
  812. } catch (e) {}
  813. })
  814. /*
  815. * 打开最近一张拍摄图
  816. * */
  817. const lastPhoto = ref({})
  818. const showlastPhoto = ref(false)
  819. const getLastPhotoRecord = async ()=>{
  820. return;
  821. if(goodsList.value && goodsList.value.length === 0) return;
  822. clientStore.ipc.removeAllListeners(icpList.takePhoto.getLastPhotoRecord);
  823. clientStore.ipc.send(icpList.takePhoto.getLastPhotoRecord,);
  824. clientStore.ipc.on(icpList.takePhoto.getLastPhotoRecord, (event, result) => {
  825. console.log('getLastPhotoRecord');
  826. console.log( result.data?.goods_art_no);
  827. clientStore.ipc.removeAllListeners(icpList.takePhoto.getLastPhotoRecord);
  828. if(result.code === 0){
  829. if(lastPhoto.value?.photo_file_name){
  830. // if( lastPhoto.value?.image_path == result.data?.image_path) return;
  831. if(runAction.value.goods_art_no === result.data?.goods_art_no){
  832. showlastPhoto.value = true
  833. }
  834. }
  835. lastPhoto.value = result.data
  836. }else if(result.msg) {
  837. ElMessage.error(result.msg)
  838. }
  839. });
  840. }
  841. let smartShooterTimeout = null; // 在合适的位置定义一个全局变量用于保存定时器
  842. //拍照成功 SmartShooter
  843. clientStore.ipc.on(icpList.socket.message+'_smart_shooter_photo_take', async (event, result) => {
  844. console.log('_smart_shooter_photo_take');
  845. console.log(result);
  846. // runLoading.value = false;
  847. //
  848. if(result.code === 0){
  849. if(!result.data.goods_art_no ) return;
  850. setLogInfo(route, { action: '单张拍摄完成', goods_art_no: result.data.goods_art_no });
  851. if(reNosObj.value?.goods_art_no === result.data.goods_art_no){
  852. runLoading.value = false;
  853. }
  854. // 单张重拍完成且存在重拍货号时,触发抠图队列
  855. scheduleSegment(result.data.goods_art_no)
  856. if (smartShooterTimeout) {
  857. clearTimeout(smartShooterTimeout);
  858. }
  859. setTimeout(() => {
  860. showlastPhoto.value = true;
  861. lastPhoto.value = {
  862. file_path:result.data.photo_file_name
  863. };
  864. setTimeout(()=>{
  865. if(!runAction.value.goods_art_no){
  866. showlastPhoto.value = false;
  867. }
  868. },3000)
  869. }, 100);
  870. smartShooterTimeout = setTimeout(() => {
  871. getPhotoRecords();
  872. if(!runAction.value.goods_art_no){
  873. showlastPhoto.value = false;
  874. }
  875. }, 2000);
  876. }else if(result.msg) {
  877. runLoading.value = false;
  878. reNosObj.value.goods_art_no = ''
  879. reNosObj.value.action = ''
  880. ElMessage.error(result.msg)
  881. }
  882. })
  883. // 监听拍照完成后的最终状态事件
  884. clientStore.ipc.on(icpList.socket.message + '_run_mcu_update', (event, result) => {
  885. console.log('run_mcu_updat print_time:'+new Date().toLocaleString()) // 打印当前时间
  886. console.log('run_mcu_update print_time:'+JSON.stringify(result))
  887. if(result.code === 0){
  888. if(result.data?.file_path){
  889. if( lastPhoto.value?.file_path == result.data?.file_path) return;
  890. let goods_art_no = runAction.value.goods_art_no || reNosObj.value.goods_art_no
  891. if(goods_art_no === result.data?.goods_art_no){
  892. showlastPhoto.value = true
  893. goodsList.value.map(item=>{
  894. if(item.goods_art_no === result.data?.goods_art_no){
  895. item.items[result.data.image_index].PhotoRecord.image_path = result.data?.file_path
  896. result.data.action_name = item.items[result.data.image_index].action_name
  897. setTimeout(()=>{
  898. item.items[result.data.image_index].PhotoRecord.image_path = result.data?.file_path
  899. },1000)
  900. setTimeout(()=>{
  901. showlastPhoto.value = false
  902. },3000)
  903. }
  904. })
  905. // getPhotoRecords()
  906. setTimeout(()=>{
  907. getPhotoRecords()
  908. },2000)
  909. }
  910. lastPhoto.value = result.data
  911. }
  912. }else if(result.msg) {
  913. ElMessage.error(result.msg)
  914. }
  915. if(reNosObj.value.goods_art_no){
  916. resetStatus()
  917. }
  918. })
  919. /**
  920. * 打开主图详情页面。
  921. */
  922. function openPhotographyDetail() {
  923. // 埋点:开始生成
  924. clickLog({ describe: { action: '开始生成', goods_count: goodsList.value.length, goods_art_nos: goodsList.value.map(item=>item.goods_art_no) } }, route);
  925. if(runLoading.value || takePictureLoading.value){
  926. ElMessage.error('正在拍摄中,请稍候')
  927. return;
  928. }
  929. const { href } = Router.resolve({
  930. name: 'PhotographyDetail',
  931. query:{
  932. goods_art_nos:goodsList.value.map(item=>item.goods_art_no),
  933. }
  934. })
  935. clientStore.ipc.removeAllListeners(icpList.utils.openMain);
  936. let params = {
  937. title: '主图与详情生成',
  938. width: 3840,
  939. height: 2160,
  940. frame: true,
  941. id: "PhotographyDetail",
  942. url: getRouterUrl(href)
  943. }
  944. clientStore.ipc.send(icpList.utils.openMain, params);
  945. }
  946. /*高级生成*/
  947. const onGenerateCLick = (menu,item)=>{
  948. if(menu.name === '历史记录'){
  949. menu.click()
  950. return
  951. }
  952. const firstWithImagePath = item.items.find(
  953. (image) => image.PhotoRecord.image_path
  954. );
  955. if (firstWithImagePath) {
  956. menu.click({
  957. query:{
  958. image_path:firstWithImagePath.PhotoRecord.image_path
  959. }
  960. })
  961. } else {
  962. menu.click()
  963. }
  964. }
  965. </script>
  966. <style lang="scss">
  967. .shot-image-popper {
  968. width: calc(100vw - 470px) !important;
  969. left: 70px !important;
  970. top: 100px !important;
  971. height: calc(100vh - 170px) !important;
  972. transform: translate(0px, 0px) !important;
  973. .el-image {
  974. width: 100%;
  975. height:100%;
  976. display: block;
  977. .el-image__inner {
  978. width: 100%;
  979. height:100%;
  980. display: block;
  981. }
  982. }
  983. }
  984. </style>
  985. <style scoped lang="scss">
  986. .photography-page {
  987. background-color: rgba(255, 255, 255, 1);
  988. position: relative;
  989. .main-container {
  990. position: relative;
  991. display: flex;
  992. .content-wrapper {
  993. flex-grow: 1 ;
  994. position: relative;
  995. top: 0;
  996. left: 0;
  997. right: 0;
  998. bottom: 0;
  999. margin: auto;
  1000. justify-content: center;
  1001. .step-number {
  1002. background-color: rgba(22, 119, 255, 1);
  1003. border-radius: 50%;
  1004. height: 32px;
  1005. margin-top: 51px;
  1006. width: 32px;
  1007. .text_22 {
  1008. width: 6px;
  1009. height: 22px;
  1010. overflow-wrap: break-word;
  1011. color: rgba(255, 255, 255, 1);
  1012. font-size: 14px;
  1013. font-weight: NaN;
  1014. text-align: right;
  1015. white-space: nowrap;
  1016. line-height: 22px;
  1017. margin: 5px 0 0 13px;
  1018. }
  1019. }
  1020. .step-one {
  1021. width: 426px;
  1022. height: 521px;
  1023. margin: 55px 0 0 5px;
  1024. .step-header {
  1025. width: 391px;
  1026. height: 24px;
  1027. margin-left: 3px;
  1028. .step-title {
  1029. width: 160px;
  1030. height: 24px;
  1031. overflow-wrap: break-word;
  1032. color: rgba(0, 0, 0, 0.85);
  1033. font-size: 16px;
  1034. font-family: PingFangSC-Medium;
  1035. font-weight: 500;
  1036. text-align: left;
  1037. white-space: nowrap;
  1038. line-height: 24px;
  1039. }
  1040. .step-icon {
  1041. width: 32px;
  1042. height: 20px;
  1043. margin-top: 4px;
  1044. }
  1045. .step-divider {
  1046. width: 191px;
  1047. height: 1px;
  1048. margin: 13px 0 0 8px;
  1049. }
  1050. }
  1051. .step-content {
  1052. width: 426px;
  1053. height: 469px;
  1054. margin-top: 28px;
  1055. .method-container {
  1056. background-color: rgba(247, 247, 247, 1);
  1057. height: 484px;
  1058. width: 353px;
  1059. .auto-method {
  1060. width: 253px;
  1061. height: 24px;
  1062. margin: 28px 0 0 14px;
  1063. .text-method-tag {
  1064. background-color: rgba(0, 174, 30, 1);
  1065. height: 24px;
  1066. width: 65px;
  1067. .text_4 {
  1068. width: 56px;
  1069. height: 20px;
  1070. overflow-wrap: break-word;
  1071. color: rgba(255, 255, 255, 1);
  1072. font-size: 14px;
  1073. font-family: PingFangSC-Semibold;
  1074. font-weight: 600;
  1075. text-align: left;
  1076. white-space: nowrap;
  1077. line-height: 20px;
  1078. margin: 2px 0 0 4px;
  1079. }
  1080. }
  1081. .method-description {
  1082. width: 182px;
  1083. height: 20px;
  1084. overflow-wrap: break-word;
  1085. color: rgba(71, 71, 71, 1);
  1086. font-size: 14px;
  1087. font-family: PingFangSC-Semibold;
  1088. font-weight: 600;
  1089. text-align: left;
  1090. white-space: nowrap;
  1091. line-height: 20px;
  1092. margin-top: 2px;
  1093. }
  1094. }
  1095. .scan-method {
  1096. width: 350px;
  1097. height: 350px;
  1098. margin: 10px;
  1099. .remote-control {
  1100. width: 350px;
  1101. height: 350px;
  1102. background: url(@/assets/images/Photography/left.png) 0px 0px no-repeat;
  1103. background-size: 300px 300px;
  1104. position: relative;
  1105. .scan-button {
  1106. background-color: rgba(0, 174, 30, 1);
  1107. border-radius: 50%;
  1108. width: 27px;
  1109. height: 27px;
  1110. margin: 27px 0 0 34px;
  1111. }
  1112. .scan-line {
  1113. position: absolute;
  1114. left: 52px;
  1115. top: 40px;
  1116. width: 112px;
  1117. height: 1px;
  1118. }
  1119. }
  1120. .scan-label {
  1121. width: 96px;
  1122. height: 22px;
  1123. overflow-wrap: break-word;
  1124. color: rgba(0, 174, 30, 1);
  1125. font-size: 16px;
  1126. font-family: PingFangSC-Semibold;
  1127. font-weight: 600;
  1128. text-align: left;
  1129. white-space: nowrap;
  1130. line-height: 22px;
  1131. margin-top: 30px;
  1132. }
  1133. }
  1134. .manual-method {
  1135. width: 155px;
  1136. height: 24px;
  1137. margin: 53px 0 0 14px;
  1138. .method-tag {
  1139. background-color: rgba(0, 148, 174, 1);
  1140. height: 24px;
  1141. width: 65px;
  1142. .text_7 {
  1143. width: 56px;
  1144. height: 20px;
  1145. overflow-wrap: break-word;
  1146. color: rgba(255, 255, 255, 1);
  1147. font-size: 14px;
  1148. font-family: PingFangSC-Semibold;
  1149. font-weight: 600;
  1150. text-align: left;
  1151. white-space: nowrap;
  1152. line-height: 20px;
  1153. margin: 2px 0 0 4px;
  1154. }
  1155. }
  1156. .method-description {
  1157. width: 84px;
  1158. height: 20px;
  1159. overflow-wrap: break-word;
  1160. color: rgba(71, 71, 71, 1);
  1161. font-size: 14px;
  1162. font-family: PingFangSC-Semibold;
  1163. font-weight: 600;
  1164. text-align: left;
  1165. white-space: nowrap;
  1166. line-height: 20px;
  1167. margin-top: 2px;
  1168. }
  1169. }
  1170. .input-container {
  1171. width: calc(100% - 20px );
  1172. height: 36px;
  1173. margin: 20px 10px 0;
  1174. .input-item {
  1175. :deep(.el-input__inner){
  1176. height: 36px;
  1177. line-height: 36px;
  1178. }
  1179. }
  1180. }
  1181. }
  1182. .remote-image {
  1183. width: 61px;
  1184. height: 38px;
  1185. margin-top: 216px;
  1186. }
  1187. }
  1188. }
  1189. .step-two {
  1190. width: 384px;
  1191. height: 521px;
  1192. margin: 55px 0 0 7px;
  1193. .step-title {
  1194. width: 384px;
  1195. height: 24px;
  1196. overflow-wrap: break-word;
  1197. color: rgba(0, 0, 0, 0.85);
  1198. font-size: 16px;
  1199. font-family: PingFangSC-Medium;
  1200. font-weight: 500;
  1201. text-align: left;
  1202. white-space: nowrap;
  1203. line-height: 24px;
  1204. }
  1205. .shooting-container {
  1206. background-color: rgba(247, 247, 247, 1);
  1207. width: 353px;
  1208. height: 484px;
  1209. margin: 28px 0 0 2px;
  1210. .remote-control-wrap {
  1211. width: 353px;
  1212. height: 300px;
  1213. }
  1214. .shooting-tips {
  1215. width: 325px;
  1216. height: 40px;
  1217. margin: 12px 0 0 15px;
  1218. .info-icon {
  1219. width: 16px;
  1220. height: 16px;
  1221. margin-top: 2px;
  1222. }
  1223. .tips-text {
  1224. width: 302px;
  1225. height: 40px;
  1226. overflow-wrap: break-word;
  1227. color: rgba(255, 76, 0, 1);
  1228. font-size: 14px;
  1229. font-weight: NaN;
  1230. text-align: left;
  1231. line-height: 20px;
  1232. }
  1233. }
  1234. .left-foot-text {
  1235. width: 240px;
  1236. height: 22px;
  1237. overflow-wrap: break-word;
  1238. color: rgba(0, 174, 30, 1);
  1239. font-size: 16px;
  1240. font-family: PingFangSC-Semibold;
  1241. font-weight: 600;
  1242. text-align: left;
  1243. white-space: nowrap;
  1244. line-height: 22px;
  1245. margin: 36px 0 0 9px;
  1246. }
  1247. .remote-control-container {
  1248. position: relative;
  1249. width: 280px;
  1250. height: 298px;
  1251. margin: 9px 0 0 35px;
  1252. .remote-buttons {
  1253. width: 206px;
  1254. height: 233px;
  1255. background: url(@/assets/images/Photography/right-button.png) 100% no-repeat;
  1256. background-size: 100% 100%;
  1257. margin: 30px 0 0 37px;
  1258. .left-button {
  1259. background-color: rgba(0, 174, 30, 1);
  1260. border-radius: 50%;
  1261. width: 55px;
  1262. height: 55px;
  1263. margin: 91px 0 0 1px;
  1264. }
  1265. .right-button {
  1266. background-color: rgba(0, 148, 174, 1);
  1267. border-radius: 50%;
  1268. width: 55px;
  1269. height: 55px;
  1270. margin: 91px 2px 0 93px;
  1271. }
  1272. }
  1273. .left-button-image {
  1274. width: 40px;
  1275. height: 148px;
  1276. margin: 150px 0 0 -3px;
  1277. }
  1278. .right-button-image {
  1279. position: absolute;
  1280. left: 0;
  1281. top: 0;
  1282. width: 40px;
  1283. height: 148px;
  1284. }
  1285. }
  1286. .right-foot-text {
  1287. width: 240px;
  1288. height: 22px;
  1289. overflow-wrap: break-word;
  1290. color: rgba(0, 148, 174, 1);
  1291. font-size: 16px;
  1292. font-family: PingFangSC-Semibold;
  1293. font-weight: 600;
  1294. text-align: left;
  1295. white-space: nowrap;
  1296. line-height: 22px;
  1297. margin: 12px 0 18px 98px;
  1298. }
  1299. }
  1300. }
  1301. }
  1302. .camera-image {
  1303. position: absolute;
  1304. left: 620px;
  1305. top: 220px;
  1306. width: 111px;
  1307. height: 111px;
  1308. }
  1309. .step-number-two {
  1310. background-color: rgba(22, 119, 255, 1);
  1311. border-radius: 50%;
  1312. height: 32px;
  1313. width: 32px;
  1314. position: absolute;
  1315. left: 450px;
  1316. top: 51px;
  1317. .step-text {
  1318. width: 9px;
  1319. height: 22px;
  1320. overflow-wrap: break-word;
  1321. color: rgba(255, 255, 255, 1);
  1322. font-size: 14px;
  1323. font-weight: NaN;
  1324. text-align: right;
  1325. white-space: nowrap;
  1326. line-height: 22px;
  1327. margin: 5px 0 0 12px;
  1328. }
  1329. }
  1330. }
  1331. }
  1332. .history-section {
  1333. background-color: rgba(234, 236, 237, 1);
  1334. width: 332px;
  1335. height: calc(100vh - 30px);
  1336. &.koutu-section {
  1337. width: 100%;
  1338. .reset-button {
  1339. display: none !important;
  1340. }
  1341. }
  1342. .history-title {
  1343. width: calc(100% - 20px);
  1344. height: 22px;
  1345. overflow-wrap: break-word;
  1346. color: rgba(51, 51, 51, 1);
  1347. font-size: 16px;
  1348. font-family: PingFangSC-Semibold;
  1349. font-weight: 600;
  1350. text-align: center;
  1351. white-space: nowrap;
  1352. line-height: 22px;
  1353. margin: 9px 0 0 10px;
  1354. }
  1355. .divider-line {
  1356. width: 100%;
  1357. height: 1px;
  1358. margin-top: 9px;
  1359. }
  1360. .history-warp {
  1361. flex-grow: 1;
  1362. overflow: auto;
  1363. height: calc(100% - 125px);
  1364. .history-item {
  1365. .history-item_image_wrap {
  1366. padding-bottom: 20px;
  1367. border-bottom: 1px solid #CCCCCC;
  1368. }
  1369. .history-item_image {
  1370. .tag {
  1371. color: #bbb;
  1372. position: absolute;
  1373. left: 0;
  1374. right: 0;
  1375. top:50%;
  1376. margin-top: -15px;
  1377. line-height: 20px;
  1378. }
  1379. /* &:nth-child(1)::before{
  1380. content:"俯视图";
  1381. }
  1382. &:nth-child(2)::before{
  1383. content:"侧视图";
  1384. }
  1385. &:nth-child(3)::before{
  1386. content:"后视图";
  1387. }
  1388. &:nth-child(4)::before{
  1389. content:"鞋底";
  1390. }
  1391. &:nth-child(5)::before{
  1392. content:"内里";
  1393. }*/
  1394. position: relative;
  1395. width: 70px;
  1396. height: 70px;
  1397. float: left;
  1398. margin: 6px 0 0 6px;
  1399. background: #F7F7F7;
  1400. .el-image {
  1401. display: block;
  1402. width:100%;
  1403. height: 100%;
  1404. }
  1405. &:first-child {
  1406. width: 146px;
  1407. height: 146px;
  1408. }
  1409. &.el-loading-parent--relative{
  1410. ::v-deep {
  1411. .el-loading-mask { display: none}
  1412. }
  1413. }
  1414. }
  1415. .el-image_view {
  1416. display: flex;
  1417. width: 100%;
  1418. height: 100%;
  1419. .reset-button {
  1420. width: 40px;
  1421. text-align: center;
  1422. height: 20px;
  1423. position: absolute;
  1424. left:50%;
  1425. top:50%;
  1426. padding: 0px;
  1427. margin-left:-20px;
  1428. margin-top:-10px;
  1429. color: #ffffff;
  1430. font-size: 14px;
  1431. background: rgba(0,0,0,0.6);
  1432. border-radius: 12px;
  1433. display: none;
  1434. cursor: pointer;
  1435. }
  1436. &:hover {
  1437. .reset-button {
  1438. display: block;
  1439. }
  1440. }
  1441. }
  1442. p:first-of-type {
  1443. ::v-deep {
  1444. .el-loading-mask { display: block !important;}
  1445. }
  1446. }
  1447. }
  1448. }
  1449. .empty-state {
  1450. width: 56px;
  1451. height: 48px;
  1452. .empty-icon {
  1453. width: 32px;
  1454. height: 18px;
  1455. margin-left: 12px;
  1456. }
  1457. .empty-text {
  1458. width: 56px;
  1459. height: 20px;
  1460. overflow-wrap: break-word;
  1461. color: rgba(153, 153, 153, 1);
  1462. font-size: 14px;
  1463. font-weight: NaN;
  1464. text-align: left;
  1465. white-space: nowrap;
  1466. line-height: 20px;
  1467. margin-top: 10px;
  1468. }
  1469. }
  1470. .next-step {
  1471. height: 50px;
  1472. background-size: 100% 100%;
  1473. width: 100%;
  1474. line-height: 50px;
  1475. cursor: pointer;
  1476. &.is-disabled {
  1477. opacity: 0.5;
  1478. cursor: not-allowed;
  1479. pointer-events: none;
  1480. }
  1481. .next-step-text {
  1482. width: 100%;
  1483. overflow-wrap: break-word;
  1484. color: rgba(255, 255, 255, 1);
  1485. text-align: center;
  1486. white-space: nowrap;
  1487. }
  1488. }
  1489. }
  1490. .last-photo{
  1491. position: fixed;
  1492. padding: 10px;
  1493. box-shadow: 0 0 5px rgb(0 0 0 / 50%);
  1494. left: 70px;
  1495. top: 100px;
  1496. bottom: 60px;
  1497. right: 400px;
  1498. z-index: 10;
  1499. .close {
  1500. position: absolute;
  1501. right: -7px;
  1502. top: -1px;
  1503. background: #fff;
  1504. width: 30px;
  1505. height: 30px;
  1506. border-radius: 30px;
  1507. z-index: 11;
  1508. text-align: center;
  1509. line-height: 30px;
  1510. box-shadow: 0 0 5px rgb(0 0 0 / 50%);
  1511. }
  1512. .el-image {
  1513. width: 100%;
  1514. height:100%;
  1515. display: block;
  1516. .el-image__inner {
  1517. width: 100%;
  1518. height:100%;
  1519. display: block;
  1520. }
  1521. }
  1522. }
  1523. </style>