perfectStore.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. <template>
  2. <div class="perfectStore">
  3. <!-- 顶部条-->
  4. <van-nav-bar class="navBar" title="AI完美门店报告" left-arrow @click-left="onClickLeft">
  5. <template #right v-if="list">
  6. <template v-if="list.wanmeiStore">
  7. <span
  8. style="
  9. color: white;
  10. background: #74a4d9;
  11. display: block;
  12. padding: 6px 10px;
  13. border-radius: 6px;
  14. "
  15. @click="editorFn"
  16. v-if="!remarkShow && sameDay"
  17. >编辑
  18. </span>
  19. </template>
  20. <template v-else>
  21. <!-- 新的生成中动画组件 -->
  22. <div class="ai-generating">
  23. <!-- AI 星星图标 -->
  24. <div class="ai-icon">
  25. <svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
  26. <defs>
  27. <linearGradient id="starGrad" x1="0%" y1="0%" x2="100%" y2="100%">
  28. <stop offset="0%" stop-color="#6366f1" />
  29. <stop offset="100%" stop-color="#a855f7" />
  30. </linearGradient>
  31. </defs>
  32. <!-- 大星星 -->
  33. <path
  34. d="M10 2 L11.2 7.8 L17 9 L11.2 10.2 L10 16 L8.8 10.2 L3 9 L8.8 7.8 Z"
  35. fill="url(#starGrad)"
  36. style="
  37. animation: starPulse 1.8s ease-in-out infinite;
  38. transform-origin: 10px 9px;
  39. ">
  40. <animateTransform
  41. attributeName="transform"
  42. type="scale"
  43. values="1;1.12;1"
  44. dur="1.8s"
  45. repeatCount="indefinite"
  46. additive="sum"
  47. calcMode="ease" />
  48. </path>
  49. <!-- 小星星 -->
  50. <circle cx="15.5" cy="4.5" r="1.5" fill="#a855f7" opacity="0.7">
  51. <animate
  52. attributeName="opacity"
  53. values="0.4;1;0.4"
  54. dur="1.4s"
  55. repeatCount="indefinite" />
  56. <animate
  57. attributeName="r"
  58. values="1.2;1.8;1.2"
  59. dur="1.4s"
  60. repeatCount="indefinite" />
  61. </circle>
  62. <!-- 微星 -->
  63. <circle cx="4.5" cy="14.5" r="1" fill="#6366f1" opacity="0.5">
  64. <animate
  65. attributeName="opacity"
  66. values="0.3;0.9;0.3"
  67. dur="1.8s"
  68. begin="0.5s"
  69. repeatCount="indefinite" />
  70. <animate
  71. attributeName="r"
  72. values="0.8;1.4;0.8"
  73. dur="1.8s"
  74. begin="0.5s"
  75. repeatCount="indefinite" />
  76. </circle>
  77. </svg>
  78. </div>
  79. <!-- 三个跳动点 -->
  80. <div class="dots-container">
  81. <div class="dot"></div>
  82. <div class="dot"></div>
  83. <div class="dot"></div>
  84. </div>
  85. <!-- 渐变文字 -->
  86. <span class="gen-text">生成中</span>
  87. </div>
  88. <!-- <span style="font-size: 18px; color: #1989fa; display: flex; align-items: center"
  89. ><img width="35px" :src="require('@/assets/wanmeiStoreImg.gif')" />生成中</span
  90. > -->
  91. </template>
  92. </template>
  93. </van-nav-bar>
  94. <!-- 主体内容-->
  95. <div class="container" v-if="list">
  96. <div class="lineGrey"></div>
  97. <div class="card mt10">
  98. <div class="title">
  99. {{ list.storeName }}(<span style="color: #1989fa">{{ list.storeCode }}</span
  100. >)
  101. </div>
  102. <div class="subtitle">地址:{{ list.addressLine }}</div>
  103. <div class="subtitle">拜访人:{{ list.nickName }}</div>
  104. <div class="subtitle">拜访日期:{{ list.startTime }}~{{ list.stopTime }}</div>
  105. <div class="subtitle" v-if="list.dwellTime">拜访时长:{{ list.dwellTime }}</div>
  106. <!-- 分销店 -->
  107. <template
  108. v-if="
  109. verifyStoreType(list.storeCategory) && verifyStoreType(list.storeCategory).type == 'fxd'
  110. ">
  111. <div class="subtitle" style="display: flex">
  112. <div class="label" style="width: 75px">经销商:</div>
  113. <div class="valuue TCFXList">
  114. <div
  115. class="sfaStoreChainsContactList"
  116. v-for="(item, index) in list.sfaStoreChainsContactList"
  117. :key="index">
  118. {{ item.categoryDescribe }}
  119. {{ item.chainCode }}
  120. {{ item.chainName }}
  121. </div>
  122. </div>
  123. </div>
  124. </template>
  125. <template v-else>
  126. <div class="subtitle">经销商:{{ list.chainName }}</div>
  127. </template>
  128. <div class="subtitle" v-if="updateTimeShow">更新时间:{{ list.updateTime }}</div>
  129. </div>
  130. <!-- 特殊任务展示 -->
  131. <!-- 店招 -->
  132. <div class="shopSign specialTask" v-if="shopSignDetail && shopSignDetail.qualifiedState">
  133. <div class="specialTaskLeft" @click="openPerfectStoreSign(shopSignDetail)">
  134. <div class="SignText">AI 店招识别</div>
  135. <div class="signContent">
  136. <div class="" style="display: flex">
  137. <template v-if="shopSignDetail.qualifiedState != null">
  138. <van-button round type="primary" v-if="shopSignDetail.qualifiedState == '1'"
  139. >通过</van-button
  140. >
  141. <van-button round type="danger" v-else-if="shopSignDetail.qualifiedState == '0'"
  142. >不通过</van-button
  143. >
  144. <div class="jiantou">
  145. <van-icon name="arrow" />
  146. </div>
  147. </template>
  148. <template v-else>
  149. <span class="AISpan">AI识别中</span>
  150. </template>
  151. </div>
  152. </div>
  153. </div>
  154. </div>
  155. <!-- 调色机 -->
  156. <div class="TSJBox specialTask" v-if="tiaoSJDetail">
  157. <div class="specialTaskLeft" @click="openPerfectStoreTSJ(tiaoSJDetail)">
  158. <div class="SignText">AI 调色机识别</div>
  159. <div class="signContent">
  160. <div class="" style="display: flex">
  161. <template v-if="tiaoSJDetail.qualifiedState != null">
  162. <van-button round type="primary" v-if="tiaoSJDetail.qualifiedState == '1'"
  163. >通过</van-button
  164. >
  165. <van-button round type="danger" v-if="tiaoSJDetail.qualifiedState == '0'"
  166. >不通过</van-button
  167. >
  168. <div class="jiantou">
  169. <van-icon name="arrow" />
  170. </div>
  171. </template>
  172. <template v-else>
  173. <span class="AISpan">AI识别中</span>
  174. </template>
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. <!-- 陈列SKU个数: -->
  180. <div class="TSJBox specialTask" v-if="list.isSku == '是'">
  181. <div class="specialTaskLeft">
  182. <div class="SignText">
  183. AI SKU个数识别: <span v-if="list.skuNum">{{ list.skuNum }}个</span>
  184. </div>
  185. <div class="signContent" @click="toSkuRecognize">
  186. <div class="" style="display: flex">
  187. <template v-if="list.wanmeiStore">
  188. <span style="color: rgb(25, 137, 250)">查看详情</span>
  189. <div class="jiantou">
  190. <van-icon name="arrow" />
  191. </div>
  192. </template>
  193. <template v-else>
  194. <span class="AISpan">AI识别中</span>
  195. </template>
  196. </div>
  197. </div>
  198. </div>
  199. </div>
  200. <!-- 目前陈列任务 -->
  201. <div class="TSJBox specialTask" v-if="taskTypeArr && taskTypeArr.length">
  202. <div class="specialTaskLeft">
  203. <div class="SignText">AI 陈列任务识别</div>
  204. </div>
  205. </div>
  206. <div class="SKUBox" v-if="taskTypeArr && taskTypeArr.length">
  207. <div class="SKUList">
  208. <div
  209. class="itemList"
  210. v-for="(value, index) in taskTypeArr"
  211. @click="historiStoreVisit(value)">
  212. <div class="itemTitle">{{ convertToChinese(index + 1) }}、{{ value.taskName }}</div>
  213. <div class="" style="display: flex">
  214. <template v-if="value.taskPhotoConditionPassed != null">
  215. <van-button round type="primary" v-if="value.taskPhotoConditionPassed == 1"
  216. >通过</van-button
  217. >
  218. <van-button round type="danger" v-if="value.taskPhotoConditionPassed == 0"
  219. >不通过</van-button
  220. >
  221. <div class="jiantou">
  222. <van-icon name="arrow" />
  223. </div>
  224. </template>
  225. <template v-else>
  226. <span class="AISpan">AI识别中</span>
  227. </template>
  228. </div>
  229. </div>
  230. </div>
  231. </div>
  232. <div style="padding: 15px 16px; font-size: 16px; font-weight: bold; background: #f5f5f5">
  233. 其他拜访任务
  234. </div>
  235. <div class="card" v-if="list.visitSource != 2">
  236. <div
  237. class="info"
  238. style="
  239. font-size: 14px;
  240. display: flex;
  241. align-items: center;
  242. justify-content: space-between;
  243. padding: 3px;
  244. "
  245. v-for="(item, index) in list.sfaTaskList"
  246. :key="index"
  247. v-if="
  248. item.photoIdentifyType != '1' && item.photoIdentifyType != '3' && item.taskType != '5'
  249. "
  250. @click="historiStoreVisit(item, index)">
  251. <p style="flex: 1; margin: 0">
  252. {{ item.taskName }}
  253. </p>
  254. <div class="taskPhotoConditionPassed" @click.stop>
  255. <el-popover
  256. :popper-class="item.taskPhotoConditionPassed == 1 ? 'zpoverSuccess' : 'zpover'"
  257. placement="bottom"
  258. width="120"
  259. trigger="click"
  260. :content="
  261. item.taskPhotoConditionPassed == 1
  262. ? '陈列奖励案拍照AI识别通过'
  263. : '陈列奖励案拍照AI识别不通过'
  264. ">
  265. <div class="taskPhotoConditionPassed" slot="reference">
  266. <img
  267. v-if="item.taskPhotoConditionPassed == 1"
  268. :src="require('@/assets/taskPhotoSu.png')" />
  269. <img
  270. v-if="item.taskPhotoConditionPassed == 0"
  271. :src="require('@/assets/taskPhotoErr.png')" />
  272. </div>
  273. </el-popover>
  274. </div>
  275. <p class="arrowdetils1">
  276. <van-icon name="arrow" />
  277. </p>
  278. </div>
  279. </div>
  280. </div>
  281. </div>
  282. </template>
  283. <script>
  284. import deleteUploadImg from '@/components/deleteUploadImg';
  285. import {
  286. getVisitsDetailPerfectStore,
  287. getPhotoTypeList1,
  288. insertVisitRemark,
  289. getListHistoryList,
  290. } from '@/api/index';
  291. import { getDictOption } from '@/api/index';
  292. import { ImagePreview } from 'vant';
  293. export default {
  294. components: { deleteUploadImg },
  295. data() {
  296. return {
  297. userShow: false,
  298. visitsId: '',
  299. imgs: '',
  300. typeList: [],
  301. active: ['1'],
  302. sameDay: false,
  303. ListHistoryTOTLE: '',
  304. managerRemarkContents: null,
  305. managerRemarkContent: '',
  306. CWShow: false,
  307. dataform: {
  308. remarkContent: '',
  309. visitsId: 0,
  310. },
  311. updateTimeShow: false,
  312. insert: true,
  313. remarkShow: false,
  314. ListHistoryList: [],
  315. list: null,
  316. AIResultOption: [],
  317. shopSignDetail: null,
  318. tiaoSJDetail: null,
  319. taskTypeArr: null,
  320. };
  321. },
  322. activated() {
  323. this.list = null;
  324. this.toastLoading(0, '加载中...', true);
  325. this.visitsId = this.$route.query.visitId;
  326. this.dataform.visitsId = this.$route.query.visitId;
  327. this.getVisitsDetailFn();
  328. // 获取店招异常原因字典
  329. getDictOption({}, 'feedback_error_msg').then((res) => {
  330. this.AIResultOption = res.data;
  331. });
  332. this.getPhotoTypeList();
  333. },
  334. methods: {
  335. resultCorrect(resultCorrect) {
  336. let data = this.AIResultOption.find((item) => item.dictValue == resultCorrect);
  337. return data ? data.dictLabel : '';
  338. },
  339. filterTitle(item) {
  340. switch (item) {
  341. case 1:
  342. return '店招识别异常,主管反馈:';
  343. // case '2':
  344. // return '门店代码识别';
  345. case 3:
  346. return '调色机识别异常,主管反馈:';
  347. // case '4':
  348. // return '更换店招';
  349. }
  350. },
  351. getListHistoryList(instanceId) {
  352. var form = { visitsId: this.$route.query.visitId, pageNum: 1, pageSize: 999 };
  353. getListHistoryList(form).then((res) => {
  354. this.ListHistoryList = res.data;
  355. });
  356. },
  357. formatter(value) {
  358. return value.replace(
  359. /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi,
  360. '',
  361. );
  362. },
  363. editorFn() {
  364. if (this.list.hideStr != '' && this.list.hideStr != null) {
  365. this.$toast(this.list.hideStr);
  366. } else {
  367. localStorage.setItem('ORGName', this.list.deptName);
  368. localStorage.setItem('chainNameR', this.list.storeName);
  369. localStorage.setItem('getRequestFlage', 'true');
  370. if (this.list.visitSource == '2') {
  371. this.$router.push({
  372. path: '/abnormalVisit',
  373. query: {
  374. type: 'edit',
  375. storeCode: this.$route.query.storeCode || this.list.storeCode,
  376. rdId: this.$route.query.visitId,
  377. visitId: this.$route.query.visitId,
  378. storeId: this.list.storeId,
  379. visitSource: this.list.visitSource,
  380. visitModel: this.list.visitModel,
  381. marklat: this.list.lat,
  382. marklon: this.list.lon,
  383. },
  384. });
  385. } else {
  386. var LCshow = false;
  387. if (this.$route.query.taskId != null) {
  388. LCshow = true;
  389. } else {
  390. LCshow = false;
  391. }
  392. this.$router.push({
  393. path: '/storeVisitpage',
  394. query: {
  395. type: 'edit',
  396. storeGroupId: this.list.storeGroupId,
  397. storeCode: this.$route.query.storeCode || this.list.storeCode,
  398. storeName: this.list.storeName,
  399. addressLine: this.list.addressLine,
  400. rdId: this.$route.query.visitId,
  401. visitId: this.$route.query.visitId,
  402. storeId: this.list.storeId,
  403. visitSource: this.list.visitSource,
  404. visitModel: this.list.visitModel,
  405. LCshow: LCshow,
  406. instanceId: this.list.instanceId,
  407. taskId: this.$route.query.taskId,
  408. marklat: this.list.lat,
  409. marklon: this.list.lon,
  410. from: 'outPlan',
  411. },
  412. });
  413. }
  414. }
  415. },
  416. submint() {
  417. if (this.dataform.remarkContent.trim() == '') {
  418. this.$toast('请填写点评内容!');
  419. } else {
  420. insertVisitRemark(this.dataform).then((res) => {
  421. if (res.code == 200) {
  422. this.getVisitsDetailFn();
  423. }
  424. });
  425. }
  426. },
  427. getPhotoTypeList() {
  428. getPhotoTypeList1({}).then((res) => {
  429. this.typeList = res.data;
  430. });
  431. },
  432. getVisitsDetailFn() {
  433. this.shopSignDetail = null;
  434. this.tiaoSJDetail = null;
  435. this.taskTypeArr = null;
  436. getVisitsDetailPerfectStore({ visitsId: this.$route.query.visitId }).then((res) => {
  437. this.toastLoading().clear();
  438. if (res.code == 200) {
  439. this.list = res.data;
  440. this.filterSfaTaskList(this.list.sfaTaskList);
  441. let shopSignArr = this.list.sfaTaskList.filter((val) => val.photoIdentifyType == '1');
  442. if (shopSignArr.length) this.shopSignDetail = shopSignArr[0];
  443. let tiaoSJArr = this.list.sfaTaskList.filter((val) => val.photoIdentifyType == '3');
  444. if (tiaoSJArr.length) {
  445. let TSJqualifiedState0 = tiaoSJArr.filter((val) => val.qualifiedState == '0');
  446. let TSJqualifiedState1 = tiaoSJArr.filter((val) => val.qualifiedState == '1');
  447. if (TSJqualifiedState0 && TSJqualifiedState0.length) {
  448. this.tiaoSJDetail = TSJqualifiedState0[0];
  449. } else if (TSJqualifiedState1 && TSJqualifiedState1.length) {
  450. this.tiaoSJDetail = TSJqualifiedState1[0];
  451. } else {
  452. this.tiaoSJDetail = tiaoSJArr[0];
  453. }
  454. console.log(this.tiaoSJDetail);
  455. }
  456. if (res.data.visitSource != 2) {
  457. this.getListHistoryList(res.data.instanceId);
  458. }
  459. if (res.data.stopTime != res.data.updateTime) {
  460. this.updateTimeShow = true;
  461. } else {
  462. this.updateTimeShow = false;
  463. }
  464. if (localStorage.getItem('userId') == this.$route.query.userId) {
  465. this.userShow = true;
  466. } else {
  467. this.userShow = false;
  468. }
  469. if (this.$route.query.taskId != null) {
  470. this.CWShow = true;
  471. } else {
  472. this.CWShow = false;
  473. }
  474. this.sameDay = res.data.sameDay;
  475. if (localStorage.getItem('userId') == res.data.userId) {
  476. this.remarkShow = false;
  477. } else {
  478. this.remarkShow = true;
  479. }
  480. if (res.data.visitRemarks != null) {
  481. if (res.data.visitRemarks.length > 0) {
  482. this.managerRemarkContents = res.data.visitRemarks;
  483. } else {
  484. this.managerRemarkContents = null;
  485. }
  486. }
  487. if (res.data.visitSource == 2) {
  488. this.imgs = res.data.sysFileInfos;
  489. }
  490. } else {
  491. this.$toast.fail(res.msg);
  492. }
  493. });
  494. },
  495. filterSfaTaskList(list) {
  496. this.taskTypeArr = list.filter((val) => val.taskType == '5');
  497. },
  498. historiStoreVisit(val, index) {
  499. if (val.taskType == '5') {
  500. if (val.taskPhotoConditionPassed == null) {
  501. return;
  502. }
  503. this.$router.push({
  504. path: '/perfectStoreTask',
  505. query: {
  506. storeCode: this.$route.query.storeCode || this.list.storeCode,
  507. visitsId: this.visitsId,
  508. taskId: val.taskId,
  509. storeGroupId: this.list.storeGroupId,
  510. insert: 0,
  511. source: 'historicalDetails',
  512. },
  513. });
  514. } else {
  515. this.$router.push({
  516. path: '/historiStoreVisit',
  517. query: { visitId: this.visitsId, ids: index, taskType: val.taskType, taskId: val.taskId },
  518. });
  519. }
  520. sessionStorage.setItem('collectionItemList', JSON.stringify(val.collectionItemList));
  521. },
  522. toSkuRecognize() {
  523. if (this.list.wanmeiStore) {
  524. this.$router.push({
  525. path: '/perfectStoreSku',
  526. query: { visitId: this.visitsId },
  527. });
  528. }
  529. },
  530. onClickLeft() {
  531. if (this.$route.query.token) {
  532. this.$router.push({
  533. path: '/historicalVisit',
  534. });
  535. } else {
  536. this.$router.go(-1);
  537. }
  538. },
  539. previewsImg(url) {
  540. ImagePreview([url]);
  541. },
  542. openPerfectStoreSign(val) {
  543. if (val.qualifiedState == null) {
  544. return;
  545. }
  546. this.$router.push({
  547. path: '/perfectStoreSign',
  548. query: { visitId: this.visitsId, taskId: val.taskId },
  549. });
  550. },
  551. openPerfectStoreTSJ(val) {
  552. if (val.qualifiedState == null) {
  553. return;
  554. }
  555. let tiaoSJArr = this.list.sfaTaskList.filter((val) => val.photoIdentifyType == '3');
  556. let taskIds = tiaoSJArr.map((item) => item.taskId).join(',');
  557. this.$router.push({
  558. path: '/perfectStoreTSJ',
  559. query: { visitId: this.visitsId, taskId: taskIds },
  560. });
  561. },
  562. },
  563. };
  564. </script>
  565. <style lang="scss" scoped>
  566. .perfectStore {
  567. background: #fff;
  568. .specialTask {
  569. display: flex;
  570. flex-direction: row;
  571. margin: 10px;
  572. border-radius: 10px;
  573. // min-height: 90px;
  574. padding: 10px 0px 10px 10px;
  575. font-size: 16px;
  576. justify-content: space-between;
  577. background: #e5faff;
  578. .specialTaskLeft {
  579. display: flex;
  580. flex-direction: row;
  581. justify-content: space-between;
  582. width: 100%;
  583. }
  584. .SignText {
  585. font-weight: 600;
  586. }
  587. .signContent {
  588. display: flex;
  589. flex-direction: row;
  590. margin: 0 8px;
  591. .icon {
  592. padding-top: 2px;
  593. margin-right: 5px;
  594. }
  595. }
  596. }
  597. // .shopSign {
  598. // background: #e5faff;
  599. // }
  600. // .TSJBox {
  601. // background: #fff4e4;
  602. // margin-top: 20px;
  603. // }
  604. .SKUBox {
  605. margin: 0px 10px 10px 10px;
  606. border-radius: 10px;
  607. // min-height: 90px;
  608. padding: 5px 10px;
  609. font-size: 16px;
  610. // background: #ffecf4;
  611. .SKUTotal {
  612. display: flex;
  613. justify-content: space-between;
  614. width: 100%;
  615. color: rgb(25, 137, 250);
  616. }
  617. .SKUList {
  618. .itemList {
  619. display: flex;
  620. flex-direction: row;
  621. justify-content: space-between;
  622. align-items: center;
  623. padding: 3px 0;
  624. margin: 10px 0;
  625. }
  626. }
  627. }
  628. .itemList,
  629. .signContent {
  630. .itemTitle {
  631. flex: 1;
  632. // text-decoration: underline;
  633. // color: rgb(25, 137, 250);
  634. }
  635. .jiantou {
  636. margin-left: 5px;
  637. color: rgb(25, 137, 250);
  638. display: flex;
  639. align-items: center;
  640. }
  641. button {
  642. width: 55px;
  643. height: 25px;
  644. padding: 0;
  645. font-size: 12px;
  646. }
  647. }
  648. }
  649. .container {
  650. padding-bottom: 50px;
  651. }
  652. .container .custom-titles {
  653. white-space: break-spaces;
  654. }
  655. .card {
  656. background: #fff;
  657. padding: 10px 15px;
  658. box-sizing: border-box;
  659. .title {
  660. line-height: 30px;
  661. font-size: 16px;
  662. font-weight: bold;
  663. color: #333;
  664. }
  665. .subtitle {
  666. line-height: 24px;
  667. font-size: 14px;
  668. color: #7b7b7b;
  669. }
  670. .info {
  671. font-size: 16px;
  672. color: #484848;
  673. line-height: 40px;
  674. border-bottom: 1px solid #dedede;
  675. position: relative;
  676. &:last-child {
  677. border-bottom: 0;
  678. }
  679. .arrow {
  680. float: right;
  681. display: inline-block;
  682. height: 20px;
  683. width: 20px;
  684. line-height: 20px;
  685. text-align: center;
  686. border-radius: 50%;
  687. background: #1989fa;
  688. color: #fff;
  689. font-weight: bold;
  690. font-size: 14px;
  691. margin-top: 9px;
  692. }
  693. .taskPhotoConditionPassed {
  694. width: 33px;
  695. margin: 0 5px;
  696. display: inline-flex;
  697. img {
  698. width: 33px;
  699. height: 25px;
  700. }
  701. }
  702. .arrowdetils1 {
  703. background: #fff;
  704. color: #444;
  705. margin: 0;
  706. margin-left: 5px;
  707. }
  708. }
  709. }
  710. .TCFXList {
  711. .van-field__control--custom {
  712. flex-direction: column;
  713. align-items: self-start;
  714. .TCFXListTreeSelec {
  715. padding: 3px;
  716. }
  717. }
  718. }
  719. </style>
  720. <style lang="scss">
  721. .fontWeit .van-cell__title {
  722. font-weight: bold;
  723. font-size: 16px;
  724. }
  725. .fontWeit .van-cell__title p {
  726. margin: 0;
  727. }
  728. .comment .van-field__control {
  729. background-color: #ebf4ff;
  730. border-radius: 6px;
  731. }
  732. .contern .van-cell {
  733. background-color: #ebf4ff;
  734. border-radius: 6px;
  735. overflow: hidden;
  736. }
  737. .perfectStore {
  738. .card {
  739. .el-popover__reference-wrapper {
  740. display: flex;
  741. }
  742. }
  743. .van-button--danger {
  744. background-color: #ee0a24 !important;
  745. border: 1px solid #ee0a24 !important;
  746. }
  747. }
  748. .zpoverSuccess {
  749. background-color: #28e978 !important;
  750. color: #fff !important;
  751. padding: 8px 10px !important;
  752. z-index: 1 !important;
  753. border-radius: 6px !important;
  754. border: 0 !important;
  755. box-shadow: none !important;
  756. }
  757. .perfectStore {
  758. /* ===== AI 生成中动画 ===== */
  759. .ai-generating {
  760. display: flex;
  761. align-items: center;
  762. gap: 5px;
  763. background: linear-gradient(135deg, rgba(99, 102, 241, 0.08), rgba(168, 85, 247, 0.08));
  764. border: 1px solid rgba(99, 102, 241, 0.2);
  765. border-radius: 20px;
  766. padding: 3px 10px 3px 7px;
  767. }
  768. /* AI 图标 - 彩色渐变扫描动效 */
  769. .ai-icon {
  770. width: 20px;
  771. height: 20px;
  772. position: relative;
  773. flex-shrink: 0;
  774. }
  775. .ai-icon svg {
  776. width: 20px;
  777. height: 20px;
  778. }
  779. /* 三个跳动圆点 */
  780. .dots-container {
  781. display: flex;
  782. align-items: center;
  783. gap: 3px;
  784. }
  785. .dot {
  786. width: 5px;
  787. height: 5px;
  788. border-radius: 50%;
  789. background: linear-gradient(135deg, #6366f1, #a855f7);
  790. animation: dotBounce 1.4s ease-in-out infinite;
  791. }
  792. .dot:nth-child(1) {
  793. animation-delay: 0s;
  794. }
  795. .dot:nth-child(2) {
  796. animation-delay: 0.2s;
  797. }
  798. .dot:nth-child(3) {
  799. animation-delay: 0.4s;
  800. }
  801. @keyframes dotBounce {
  802. 0%,
  803. 60%,
  804. 100% {
  805. transform: translateY(0);
  806. opacity: 0.5;
  807. }
  808. 30% {
  809. transform: translateY(-5px);
  810. opacity: 1;
  811. }
  812. }
  813. /* 生成中文字 */
  814. .gen-text {
  815. font-size: 12px;
  816. font-weight: 500;
  817. background: linear-gradient(90deg, #6366f1, #a855f7, #6366f1);
  818. background-size: 200% auto;
  819. -webkit-background-clip: text;
  820. -webkit-text-fill-color: transparent;
  821. background-clip: text;
  822. animation: textShimmer 2s linear infinite;
  823. }
  824. @keyframes textShimmer {
  825. 0% {
  826. background-position: 0% center;
  827. }
  828. 100% {
  829. background-position: 200% center;
  830. }
  831. }
  832. /* AI 图标内部的星星动画 */
  833. @keyframes starPulse {
  834. 0%,
  835. 100% {
  836. transform: scale(1) rotate(0deg);
  837. opacity: 0.9;
  838. }
  839. 50% {
  840. transform: scale(1.15) rotate(15deg);
  841. opacity: 1;
  842. }
  843. }
  844. @keyframes starOrbit {
  845. 0% {
  846. transform: rotate(0deg) translateX(5px) rotate(0deg);
  847. }
  848. 100% {
  849. transform: rotate(360deg) translateX(5px) rotate(-360deg);
  850. }
  851. }
  852. /* 光晕扫描 */
  853. .scan-line {
  854. position: absolute;
  855. top: 0;
  856. left: -100%;
  857. width: 60%;
  858. height: 100%;
  859. background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent);
  860. animation: scanAnim 2s ease-in-out infinite;
  861. border-radius: 50%;
  862. }
  863. @keyframes scanAnim {
  864. 0% {
  865. left: -60%;
  866. }
  867. 100% {
  868. left: 160%;
  869. }
  870. }
  871. .AISpan {
  872. display: flex;
  873. align-items: center;
  874. color: #1989fa;
  875. margin-right: 16px;
  876. }
  877. .AISpan::before {
  878. content: '';
  879. display: inline-block;
  880. width: 6px;
  881. height: 6px;
  882. border-radius: 50%;
  883. background: #2979ff;
  884. animation: blink 1.2s ease-in-out infinite;
  885. margin-right: 5px;
  886. }
  887. @keyframes blink {
  888. 0%,
  889. 100% {
  890. opacity: 0.3;
  891. }
  892. 50% {
  893. opacity: 1;
  894. }
  895. }
  896. }
  897. </style>