PipeInspectProject.vue 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. <template>
  2. <view class="inspect-project-container">
  3. <scroll-view class="scroll-list" scroll-y>
  4. <view class="report-list">
  5. <view v-for="item in reportList" :key="item.id" class="report-item">
  6. <view class="item-top" @click="handleSelectProject(item)">
  7. <view class="top-left">
  8. <radio
  9. :checked="selectedProjects.includes(item.id)"
  10. color="#4B8CD9"
  11. @click.stop="handleSelectProject(item)"
  12. />
  13. <text class="report-name">{{ item.reportName }}</text>
  14. <view
  15. class="type-tag"
  16. :style="{ backgroundColor: getReportTypeColor(item.reportType) }"
  17. >
  18. <text class="type-tag-text">{{ getReportTypeIcon(item.reportType) }}</text>
  19. </view>
  20. </view>
  21. <text class="status-text" :style="{ color: getStatusColor(item, useOnline) }">
  22. {{ getStatusText(item, useOnline) }}
  23. </text>
  24. </view>
  25. <view class="item-center">
  26. <view class="center-row">
  27. <text class="label">检验结论:</text>
  28. <view
  29. class="conclusion-box"
  30. :class="{
  31. 'conclusion-error': isConclusionError(item.reportConclusion),
  32. }"
  33. @click="handleUpdateConclusion(item, 'reportConclusion')"
  34. >
  35. <text
  36. class="conclusion-text"
  37. :class="{
  38. 'conclusion-error-text': isConclusionError(
  39. item.reportConclusion,
  40. ),
  41. }"
  42. >
  43. {{ item.reportConclusion || '无' }}
  44. </text>
  45. </view>
  46. <view class="right-area">
  47. <view
  48. v-if="item.reportType === PressureReportType.SINGLE && item.instructionTempId"
  49. class="instruction-tag"
  50. :class="{ 'instruction-tag-error': !item.instructionId }"
  51. @click="handleAssociationOperation(item)"
  52. >
  53. <text
  54. class="instruction-text"
  55. :class="{ 'instruction-text-error': !item.instructionId }"
  56. >
  57. {{ item.instructionId ? '已' : '未' }}关联操作指导书
  58. </text>
  59. </view>
  60. <text v-if="item.reportType === 100" class="inspector-name">
  61. 主检人:{{ equipment?.mainCheckerUser?.nickname || '无' }}
  62. </text>
  63. <view
  64. v-else-if="!isOffline && canModifyChecker"
  65. class="inspector-btn"
  66. @click="handleExChangeItemChecker(item)"
  67. >
  68. <text class="inspector-label">检验员:</text>
  69. <text class="inspector-value">{{ item.checkUsers?.[0]?.nickname || '无' }}</text>
  70. </view>
  71. <text v-else class="inspector-name">
  72. 检验员:{{ item.checkUsers?.[0]?.nickname || '无' }}
  73. </text>
  74. </view>
  75. </view>
  76. <view class="center-row">
  77. <text class="label">检验结果:</text>
  78. <view class="result-box" @click="handleUpdateConclusion(item, 'reportResult')">
  79. <text class="result-text">{{ item.reportResult || '-' }}</text>
  80. </view>
  81. </view>
  82. <view class="center-row">
  83. <text class="label">费用金额:</text>
  84. <view class="fee-area">
  85. <view
  86. v-if="
  87. (useOnline === '1' ? shouldShowFeeInput(item.taskStatus) : true) &&
  88. [
  89. PressureReportType.MAIN,
  90. PressureReportType.SUB,
  91. PressureReportType.SINGLE,
  92. ].includes(item.reportType)
  93. "
  94. class="fee-btns"
  95. >
  96. <view class="fee-value-box">
  97. <text class="fee-value">
  98. {{ typeof item.fee === 'number' && !isNaN(item.fee) ? item.fee : '0' }}
  99. </text>
  100. </view>
  101. <view class="fee-btn" @click="handleCalcFee(item)">
  102. <text class="fee-btn-text">费用录入</text>
  103. </view>
  104. </view>
  105. <text v-else class="fee-none">无</text>
  106. </view>
  107. <view class="action-btns">
  108. <template v-if="useOnline === '1'">
  109. <view
  110. v-if="shouldShowSign(item)"
  111. class="action-btn sign-btn"
  112. @click="handleSign(item)"
  113. >
  114. <text class="action-btn-text">签 名</text>
  115. </view>
  116. <view
  117. v-if="shouldShowAttachmentUpload(item.taskStatus)"
  118. class="action-btn attachment-btn"
  119. @click="handleUploadFile(item)"
  120. >
  121. <text class="action-btn-text">附件上传</text>
  122. </view>
  123. <view
  124. v-if="
  125. isEditable(item) &&
  126. shouldShowRecordInput(item.taskStatus) &&
  127. item.reportType !== PressureReportType.SUGGUESTION
  128. "
  129. class="action-btn record-btn"
  130. @click="handleRouteToInputWebview(item)"
  131. >
  132. <text class="action-btn-text">记录录入</text>
  133. </view>
  134. <view
  135. v-if="
  136. isEditable(item) &&
  137. shouldShowReInput(item.taskStatus) &&
  138. item.reportType !== PressureReportType.SUGGUESTION
  139. "
  140. class="action-btn re-input-btn"
  141. @click="handleRouteToInputWebview(item)"
  142. >
  143. <text class="action-btn-text">重新录入</text>
  144. </view>
  145. <view
  146. v-if="isEditable(item) && shouldShowSubmitCheck(item.taskStatus)"
  147. class="action-btn submit-check-btn"
  148. @click="handleSubmitCheck(item)"
  149. >
  150. <text class="action-btn-text">提交校核</text>
  151. </view>
  152. <view
  153. v-if="isEditable(item) && shouldShowSubmitReport(item.taskStatus)"
  154. class="action-btn submit-report-btn"
  155. @click="showSelectReportUserPopup(item)"
  156. >
  157. <text class="action-btn-text">提交报告</text>
  158. </view>
  159. </template>
  160. <template v-else>
  161. <view class="action-btn attachment-btn" @click="handleUploadFile(item)">
  162. <text class="action-btn-text">附件上传</text>
  163. </view>
  164. <view
  165. v-if="item.reportType !== PressureReportType.SUGGUESTION"
  166. class="action-btn record-btn"
  167. @click="handleRouteToInputWebview(item)"
  168. >
  169. <text class="action-btn-text">
  170. {{ !item.localReportUrl ? '记录录入' : '重新录入' }}
  171. </text>
  172. </view>
  173. <view
  174. class="action-btn submit-check-btn"
  175. @click="uploadFileAndSubmitCheckItemCallback.callback(item)"
  176. >
  177. <text class="action-btn-text">
  178. {{ item.hasSyncedData ? '重新上传' : '上传' }}
  179. </text>
  180. </view>
  181. <view
  182. v-if="
  183. item.reportType !== PressureReportType.SUGGUESTION &&
  184. ((useOnline === '1' && item.reportUrl) ||
  185. (useOnline !== '1' &&
  186. item.hasSyncedData &&
  187. item.localReportUrl &&
  188. item.reportUrl))
  189. "
  190. class="action-btn submit-check-btn"
  191. @click="handleSubmitCheck(item)"
  192. >
  193. <text class="action-btn-text">提交校核</text>
  194. </view>
  195. </template>
  196. </view>
  197. </view>
  198. </view>
  199. </view>
  200. <view v-if="!reportList || reportList.length === 0" class="empty-state">
  201. <text class="empty-text">暂无检验项目</text>
  202. </view>
  203. </view>
  204. </scroll-view>
  205. <view class="bottom-bar">
  206. <view class="select-all-box" @click="handleSelectAll">
  207. <checkbox
  208. class="square-checkbox"
  209. :checked="selectAll"
  210. color="#4B8CD9"
  211. @click.stop="handleSelectAll"
  212. />
  213. <text class="select-all-text">{{ selectAll ? '取消全选' : '全选' }}</text>
  214. </view>
  215. <view class="action-buttons">
  216. <view class="operate-btn delete-btn" @click="handleDelReport">
  217. <text class="operate-btn-text">作废项目</text>
  218. </view>
  219. <view class="operate-btn guide-btn" @click="showAddWorkInstructionPopup">
  220. <text class="operate-btn-text">添加指导书</text>
  221. </view>
  222. <view class="operate-btn add-btn" @click="showCheckProjectPopup">
  223. <text class="operate-btn-text">添加项目</text>
  224. </view>
  225. <view v-if="useOnline !== '1'" class="operate-btn upload-btn" @click="handleCheckReport">
  226. <text class="operate-btn-text">上传</text>
  227. </view>
  228. </view>
  229. </view>
  230. <TipsPopup ref="tipsPopupRef" />
  231. <CalcCheckItemPopup
  232. v-if="showCalcPopup"
  233. ref="calcCheckItemPopupRef"
  234. :check-item="selectedCheckItem"
  235. @hide="hideCalcPopup"
  236. @update-render-item="handleUpdateRenderItem"
  237. />
  238. <ExchangeChecker
  239. v-if="showExchangePopup"
  240. ref="exchangeCheckerPopupRef"
  241. :check-users="dataSource?.checkUsers"
  242. :current-checker="editCheckItem?.checkUsers?.[0]"
  243. :check-item-id="currentCheckItemId"
  244. @hide="hideExchangePopup"
  245. @update-check-item-checker="handleUpdateChecker"
  246. />
  247. <UpdateConclusionPopup
  248. v-if="showConclusionPopup"
  249. ref="updateConclusionPopupRef"
  250. :check-item="currentCheckItem"
  251. :field-key="currentFieldKey"
  252. @hide="hideConclusionPopup"
  253. @confirm="handleUpdateConclusionConfirm"
  254. />
  255. <view v-if="showSelectReportPopup" class="popup-overlay" @click="closeSelectReportPopup">
  256. <view class="popup-content" @click.stop>
  257. <text class="popup-title">选择审核人</text>
  258. <picker :range="recheckUserGroupList" range-key="label" @change="onReportUserChange">
  259. <view class="picker-value">
  260. <text>{{ currentReckUser?.label || '请选择' }}</text>
  261. </view>
  262. </picker>
  263. <view class="popup-actions">
  264. <button class="action-btn cancel-btn" @click="closeSelectReportPopup">取消</button>
  265. <button class="action-btn confirm-btn" @click="handleSubmitReport">确定</button>
  266. </view>
  267. </view>
  268. </view>
  269. <view v-if="showSelectTemplatePopup" class="popup-overlay" @click="closeSelectTemplatePopup">
  270. <view class="popup-content" @click.stop>
  271. <text class="popup-title">选择模板</text>
  272. <picker :range="templateList" range-key="label" @change="onTemplateChange">
  273. <view class="picker-value">
  274. <text>{{ selectedTemplate?.label || '请选择' }}</text>
  275. </view>
  276. </picker>
  277. <view class="popup-actions">
  278. <button class="action-btn cancel-btn" @click="closeSelectTemplatePopup">取消</button>
  279. <button class="action-btn confirm-btn" @click="handleConfirmTemplate">确定</button>
  280. </view>
  281. </view>
  282. </view>
  283. </view>
  284. </template>
  285. <script lang="ts" setup>
  286. import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
  287. import {
  288. PressureCheckerMyTaskStatus,
  289. PressureReportType,
  290. PressureCheckerMyTaskStatusMap,
  291. } from '@/utils/dictMap'
  292. import { isCheckItemEditable, isAssignedToOthers } from '@/utils/equipmentPermissions'
  293. import {
  294. getApprovalDetail,
  295. getUserGroupUserList,
  296. pressure2NotVerifyPageApi,
  297. } from '@/api/task'
  298. import { cancelPipeInSpectProject, addPipeMajorIssues, submitPipeReport } from '@/api/pipe/pipeTaskOrder'
  299. import { updatePipeTaskOrderItemReportConclusion } from '@/api/pipe/pipeTaskOrderReport'
  300. import TipsPopup from './inspectProjectComponent/TipsPopup.vue'
  301. import CalcCheckItemPopup from './inspectProject/component/calcCheckItemPopup.vue'
  302. import ExchangeChecker from './inspectProject/component/ExchangeChecker.vue'
  303. import UpdateConclusionPopup from './inspectProject/component/UpdateConclusionPopup.vue'
  304. import eventBus from '@/utils/eventBus'
  305. import { useUserStore } from '@/store/user.js'
  306. interface CheckConclusionItem {
  307. value: string
  308. id: string
  309. }
  310. interface CheckItem {
  311. id: string
  312. reportName: string
  313. localReportUrl?: string
  314. prepareJson?: string | object
  315. reportType?: number
  316. recordJson?: string
  317. [key: string]: any
  318. }
  319. interface Props {
  320. reportList: CheckItem[]
  321. taskOrder: StringAnyObj
  322. equipment: StringAnyObj
  323. dataSource: any
  324. orderId: string
  325. orderItemId: string
  326. useOnline?: string
  327. isMainChecker?: boolean
  328. canModifyAssignments?: boolean
  329. updateReportList?: (reportList: CheckItem[]) => void
  330. fetchGetEquipmentDetail?: () => void
  331. refreshDetail?: () => void
  332. showSelectUserPopup?: (checkItem: CheckItem) => void
  333. handleAssociationOperationManual?: (checkItem: CheckItem) => void
  334. showCheckProjectPopupFn?: () => void
  335. }
  336. const props = withDefaults(defineProps<Props>(), {
  337. reportList: () => [],
  338. useOnline: '1',
  339. isMainChecker: false,
  340. canModifyAssignments: false,
  341. })
  342. const emit = defineEmits<{
  343. updateReportList: [list: CheckItem[]]
  344. refresh: []
  345. }>()
  346. const selectAll = ref(false)
  347. const selectedProjects = ref<string[]>([])
  348. const selectedCheckItem = ref<any>(null)
  349. const editCheckItem = ref<any>(null)
  350. const currentCheckItemId = ref('')
  351. const currentCheckItem = ref<any>(null)
  352. const currentFieldKey = ref<'reportConclusion' | 'reportResult'>('reportConclusion')
  353. const refreshing = ref(false)
  354. const isOffline = ref(false)
  355. const showCalcPopup = ref(false)
  356. const showExchangePopup = ref(false)
  357. const showConclusionPopup = ref(false)
  358. const showSelectReportPopup = ref(false)
  359. const tipsPopupRef = ref<any>(null)
  360. const calcCheckItemPopupRef = ref<any>(null)
  361. const exchangeCheckerPopupRef = ref<any>(null)
  362. const updateConclusionPopupRef = ref<any>(null)
  363. const currentReportItem = ref<any>(null)
  364. const recheckUserGroupList = ref<any[]>([])
  365. const currentReckUser = ref<any>(null)
  366. const showSelectTemplatePopup = ref(false)
  367. const templateList = ref<any[]>([])
  368. const selectedTemplate = ref<any>(null)
  369. const userInfo = computed(() => useUserStore().userInfo)
  370. const canModifyChecker = computed(() => {
  371. return props.canModifyAssignments && props.isMainChecker
  372. })
  373. const isNetworkConnected = ref(true)
  374. watch(props.dataSource, (newVal) => {
  375. console.log('datasourcechange......', newVal)
  376. })
  377. onMounted(() => {
  378. console.log('datasource.......', props.dataSource)
  379. checkNetworkStatus()
  380. initSelected()
  381. setupEventListeners()
  382. })
  383. onUnmounted(() => {
  384. removeEventListeners()
  385. })
  386. const checkNetworkStatus = () => {
  387. isOffline.value = !isNetworkConnected.value
  388. }
  389. const setupEventListeners = () => {
  390. eventBus.on('RefreshInspectProject', () => {
  391. initSelected()
  392. props.fetchGetEquipmentDetail?.()
  393. })
  394. eventBus.on('webViewSaved', (data: any) => {
  395. initSelected()
  396. if (props.useOnline === '1' && data.isOnline) {
  397. const updatedReportList = (props.reportList || []).map((item: any) => {
  398. if (item.id === data.checkItemId) {
  399. return {
  400. ...item,
  401. reportUrl: data.reportUrl,
  402. bindingPathSchema: data.bindingPathSchema,
  403. prepareJson: data.prepareJson,
  404. }
  405. }
  406. return item
  407. })
  408. emit('updateReportList', updatedReportList)
  409. props.refreshDetail?.()
  410. } else {
  411. props.fetchGetEquipmentDetail?.()
  412. }
  413. })
  414. uni.$on('onNetworkStatusChange', (connected: boolean) => {
  415. isOffline.value = !connected
  416. })
  417. }
  418. const removeEventListeners = () => {
  419. eventBus.off('RefreshInspectProject')
  420. eventBus.off('webViewSaved')
  421. uni.$off('onNetworkStatusChange')
  422. }
  423. const onRefresh = async () => {
  424. if (props.useOnline !== '1') return
  425. refreshing.value = true
  426. try {
  427. props.refreshDetail?.()
  428. } catch (error) {
  429. console.error('下拉刷新失败:', error)
  430. } finally {
  431. refreshing.value = false
  432. }
  433. }
  434. const initSelected = () => {
  435. selectAll.value = false
  436. selectedProjects.value = []
  437. }
  438. const handleSelectAll = () => {
  439. selectAll.value = !selectAll.value
  440. if (selectAll.value) {
  441. selectedProjects.value = props.reportList.map((item) => item.id)
  442. } else {
  443. selectedProjects.value = []
  444. }
  445. }
  446. const handleSelectProject = (item: CheckItem) => {
  447. const index = selectedProjects.value.indexOf(item.id)
  448. if (index === -1) {
  449. selectedProjects.value.push(item.id)
  450. } else {
  451. selectedProjects.value.splice(index, 1)
  452. }
  453. selectAll.value = selectedProjects.value.length === props.reportList.length
  454. }
  455. const getRecordJson = (item: CheckItem): Record<string, any> => {
  456. try {
  457. return item.recordJson && typeof item.recordJson === 'string' ? JSON.parse(item.recordJson) : {}
  458. } catch {
  459. return {}
  460. }
  461. }
  462. const isConclusionError = (conclusion: string): boolean => {
  463. return /不合格|不符合/.test(conclusion || '')
  464. }
  465. const getReportTypeIcon = (reportType?: number): string | null => {
  466. switch (reportType) {
  467. case PressureReportType.MAIN:
  468. return '主'
  469. case PressureReportType.SINGLE:
  470. return '独'
  471. case PressureReportType.SUB:
  472. return '子'
  473. case PressureReportType.SUGGUESTION:
  474. case PressureReportType.MAINQUESTION:
  475. case PressureReportType.WORKINSTRUCTION:
  476. return '附'
  477. default:
  478. return null
  479. }
  480. }
  481. const getReportTypeColor = (reportType?: number): string => {
  482. switch (reportType) {
  483. case PressureReportType.MAIN:
  484. return 'rgb(68,127,241)'
  485. case PressureReportType.SINGLE:
  486. return 'rgb(230,162,60)'
  487. case PressureReportType.SUB:
  488. return 'rgb(145,213,255)'
  489. case PressureReportType.SUGGUESTION:
  490. case PressureReportType.MAINQUESTION:
  491. case PressureReportType.WORKINSTRUCTION:
  492. return '#fff'
  493. default:
  494. return '#fff'
  495. }
  496. }
  497. const getStatusText = (item: CheckItem, useOnline?: string): string => {
  498. if (useOnline === '1') {
  499. if (
  500. item.taskStatus === PressureCheckerMyTaskStatus.RECORD_CHECK &&
  501. item.recheckStatus === 200
  502. ) {
  503. return '校核已通过'
  504. }
  505. return PressureCheckerMyTaskStatusMap[item.taskStatus] || '待录入'
  506. } else {
  507. return !item.localReportUrl ? '待录入' : '已录入'
  508. }
  509. }
  510. const getStatusColor = (item: CheckItem, useOnline?: string): string => {
  511. if (useOnline === '1') {
  512. if (
  513. item.taskStatus === PressureCheckerMyTaskStatus.RECORD_CHECK &&
  514. item.recheckStatus === 200
  515. ) {
  516. return '#52C41A'
  517. }
  518. return '#4B8CD9'
  519. } else {
  520. return !item.localReportUrl ? '#FF3535' : '#4B8CD9'
  521. }
  522. }
  523. const shouldShowFeeInput = (taskStatus?: number): boolean => {
  524. return taskStatus !== undefined
  525. }
  526. const shouldShowSign = (item: CheckItem): boolean => {
  527. return item.isSignFunction === 1 && item.taskStatus === PressureCheckerMyTaskStatus.RECORD_INPUT
  528. }
  529. const shouldShowAttachmentUpload = (taskStatus?: number): boolean => {
  530. // return taskStatus !== undefined
  531. return false
  532. }
  533. const shouldShowRecordInput = (taskStatus?: number): boolean => {
  534. return taskStatus === PressureCheckerMyTaskStatus.CONFIRMED
  535. }
  536. const shouldShowReInput = (taskStatus?: number): boolean => {
  537. return taskStatus === PressureCheckerMyTaskStatus.RECORD_INPUT
  538. }
  539. const shouldShowSubmitCheck = (taskStatus?: number): boolean => {
  540. return taskStatus === PressureCheckerMyTaskStatus.RECORD_INPUT
  541. }
  542. const shouldShowSubmitReport = (taskStatus?: number): boolean => {
  543. return taskStatus === PressureCheckerMyTaskStatus.REPORT_INPUT
  544. }
  545. const isEditable = (item: CheckItem): boolean => {
  546. return isCheckItemEditable(item, userInfo.value, props.equipment)
  547. }
  548. const isAssignedToOther = (item: CheckItem): boolean => {
  549. return isAssignedToOthers(item, userInfo.value)
  550. }
  551. const handleRouteToInputWebview = (item: CheckItem) => {
  552. const userId =
  553. item.reportType === PressureReportType.MAIN
  554. ? props.equipment?.mainCheckerUser?.id
  555. : item?.checkUsers?.[0]?.id
  556. if (userId && userId !== userInfo.value?.id) {
  557. uni.showToast({ title: '已分配项目不支持记录录入', icon: 'error' })
  558. return
  559. }
  560. uni.navigateTo({
  561. url: `/pages/editor/equipCheckRecordEditor?userId=${userInfo.value?.id}&orderItemId=${props.orderItemId}&checkItemId=${item?.id}&templateId=${item.templateId}&equipCode=${item.equipCode}&useOnline=${props.useOnline}&reportUrl=${item.reportUrl || ''}`,
  562. })
  563. }
  564. const handleCalcFee = (item: CheckItem) => {
  565. const userId =
  566. item.reportType === PressureReportType.MAIN
  567. ? props.equipment?.mainCheckerUser?.id
  568. : item?.checkUsers?.[0]?.id
  569. if (userId && userId !== userInfo.value?.id) {
  570. uni.showToast({ title: '已分配项目不支持费用录入', icon: 'error' })
  571. return
  572. }
  573. selectedCheckItem.value = { ...item, orderItemId: props.orderItemId }
  574. showCalcPopup.value = true
  575. }
  576. const hideCalcPopup = () => {
  577. showCalcPopup.value = false
  578. selectedCheckItem.value = null
  579. }
  580. const handleUpdateRenderItem = async (calcData: any) => {
  581. await updatePipeTaskOrderItemReportConclusion(calcData)
  582. const report = props.reportList.find(item => item.id === calcData.id)
  583. const feeKey = 'fee'
  584. report[feeKey] = calcData[feeKey]
  585. props.refreshDetail()
  586. showCalcPopup.value = false
  587. // const updatedList = props.reportList.map((x) => {
  588. // if (x.id === calcData.id) {
  589. // return {
  590. // ...x,
  591. // fee: calcData.fee,
  592. // feeCalculateJson: calcData.feeCalculateJson,
  593. // }
  594. // }
  595. // return x
  596. // })
  597. // emit('updateReportList', updatedList)
  598. // initSelected()
  599. }
  600. const handleExChangeItemChecker = (item: CheckItem) => {
  601. if (item.isLocal) {
  602. uni.showToast({ title: '本地项目不能修改检验员,请上传', icon: 'error' })
  603. return
  604. }
  605. editCheckItem.value = item
  606. currentCheckItemId.value = item.id
  607. showExchangePopup.value = true
  608. }
  609. const hideExchangePopup = () => {
  610. showExchangePopup.value = false
  611. editCheckItem.value = null
  612. currentCheckItemId.value = ''
  613. }
  614. const handleUpdateChecker = async (checker: any, checkItemId: string) => {
  615. console.log('checker......', checker, checkItemId)
  616. // try {
  617. // const newChecker = typeof checker === 'string' ? JSON.parse(checker) : checker
  618. // if (!newChecker.id) {
  619. // console.warn('Checker missing id')
  620. // return
  621. // }
  622. // const { handleUpdateReportCheckUsers } = await import('@/api/task')
  623. // const result = await handleUpdateReportCheckUsers(newChecker, checkItemId)
  624. // if (result) {
  625. // uni.showToast({ title: '更新检验员成功' })
  626. // hideExchangePopup()
  627. // props.refreshDetail?.()
  628. // }
  629. // } catch (error) {
  630. // console.error('更新检验员失败:', error)
  631. // uni.showToast({ title: '更新检验员失败', icon: 'error' })
  632. // }
  633. }
  634. const handleUpdateConclusion = (item: CheckItem, fieldKey: 'reportConclusion' | 'reportResult') => {
  635. if (item.isLocal) {
  636. uni.showToast({ title: '本地项目不能修改检验结论', icon: 'error' })
  637. return
  638. }
  639. const canUpdate = [
  640. PressureCheckerMyTaskStatus.CONFIRMED,
  641. PressureCheckerMyTaskStatus.RECORD_INPUT,
  642. ].includes(item.taskStatus)
  643. if (!canUpdate) return
  644. currentCheckItem.value = item
  645. currentFieldKey.value = fieldKey
  646. showConclusionPopup.value = true
  647. }
  648. const hideConclusionPopup = () => {
  649. showConclusionPopup.value = false
  650. currentCheckItem.value = null
  651. currentFieldKey.value = 'reportConclusion'
  652. }
  653. const handleUpdateConclusionConfirm = async (conclusionData: any) => {
  654. await updatePipeTaskOrderItemReportConclusion(conclusionData)
  655. // 先前端缓存结果,让响应更快,从而可以不引入Loading动画表达中间过渡
  656. for (const key in conclusionData) {
  657. if (!Object.hasOwn(conclusionData, key)) continue;
  658. const element = conclusionData[key];
  659. currentCheckItem.value[key] = element
  660. }
  661. props.refreshDetail()
  662. showConclusionPopup.value = false
  663. }
  664. const handleSubmitCheck = (item: CheckItem) => {
  665. const { isSignFunction, signFunctionUrl, reportType } = item
  666. if (isSignFunction === 1 && !signFunctionUrl) {
  667. uni.showToast({
  668. title: '客户未签名,不支持提交校核',
  669. icon: 'none',
  670. })
  671. return
  672. }
  673. props.showSelectUserPopup?.(item)
  674. }
  675. const showSelectReportUserPopup = async (item: CheckItem) => {
  676. if (props.useOnline !== '1') {
  677. uni.showToast({ title: '离线模式不支持提交报告', icon: 'none' })
  678. return
  679. }
  680. currentReportItem.value = item
  681. await getAuditUserGroupList(item)
  682. showSelectReportPopup.value = true
  683. }
  684. const getAuditUserGroupList = async (checkItem: any) => {
  685. try {
  686. const groupRes: any = await getApprovalDetail({})
  687. const { recheckId, approveUser, yearCheckRecheckJson } = groupRes?.data || {}
  688. const yearCheckRecheckJsonData = yearCheckRecheckJson ? JSON.parse(yearCheckRecheckJson) : {}
  689. const { checkType } = props.taskOrder || {}
  690. const { reportType } = checkItem || {}
  691. const isYearCheckType = checkType === 200 && reportType === PressureReportType.MAIN
  692. const category = isYearCheckType ? 201 : 200
  693. const filterId = isYearCheckType ? yearCheckRecheckJsonData.yearCheckRecordAuditId : recheckId
  694. const userRes: any = await getUserGroupUserList({ category, status: 0 })
  695. const list = (userRes?.data || []).map((item: any) => ({
  696. ...item,
  697. label: item.nickname,
  698. value: item.id,
  699. }))
  700. const defaultItem = list.find((item: any) => item.value === filterId) || {}
  701. currentReckUser.value = defaultItem
  702. recheckUserGroupList.value = list
  703. } catch (error) {
  704. console.error('获取审核人列表失败:', error)
  705. uni.showToast({ title: '获取审核人列表失败', icon: 'error' })
  706. }
  707. }
  708. const onReportUserChange = (e: any) => {
  709. const index = e.detail.value
  710. currentReckUser.value = recheckUserGroupList.value[index]
  711. }
  712. const handleSubmitReport = async () => {
  713. // if (!currentReckUser.value) {
  714. // uni.showToast({ title: '请选择审核人', icon: 'error' })
  715. // return
  716. // }
  717. if (!currentReportItem.value) {
  718. uni.showToast({ title: '报告信息丢失,请重试', icon: 'error' })
  719. return
  720. }
  721. try {
  722. uni.showLoading({ title: '提交中...' })
  723. const params = {
  724. id: currentReportItem.value.id,
  725. approveId: userInfo.value?.id,
  726. reportType: currentReportItem.value.reportType,
  727. }
  728. const result: any = await submitPipeReport(params)
  729. uni.hideLoading()
  730. if (result?.code === 0) {
  731. uni.showToast({ title: '提交报告成功', icon: 'success' })
  732. showSelectReportPopup.value = false
  733. props.fetchGetEquipmentDetail?.()
  734. props.refreshDetail?.()
  735. currentReportItem.value = null
  736. } else {
  737. uni.showToast({ title: result?.msg || '提交失败', icon: 'error' })
  738. }
  739. } catch (error: any) {
  740. uni.hideLoading()
  741. console.error('提交报告失败:', error)
  742. uni.showToast({ title: error?.msg || '提交失败,请重试', icon: 'error' })
  743. }
  744. }
  745. const closeSelectReportPopup = () => {
  746. showSelectReportPopup.value = false
  747. currentReportItem.value = null
  748. }
  749. const handleSign = (item: CheckItem) => {
  750. const { unitContact, unitPhone } = props.taskOrder || {}
  751. uni.navigateTo({
  752. url: `/pages/sign-report/index?reportId=${item.id}&pushName=${unitContact}&pushPhone=${unitPhone}`,
  753. })
  754. }
  755. const handleUploadFile = (item: CheckItem) => {
  756. const userId =
  757. item.reportType === PressureReportType.MAIN
  758. ? props.equipment?.mainCheckerUser?.id
  759. : item?.checkUsers?.[0]?.id
  760. const readOnly = isAssignedToOther(item)
  761. const fileList = props.reportList?.map((i: any) => ({
  762. checkItemId: i?.id,
  763. reportName: i?.reportName,
  764. image: i.image,
  765. video: i.video,
  766. attachment: i.attachment,
  767. }))
  768. uni.navigateTo({
  769. url: `/pages/uploadFile/UploadFile?isEdit=${!readOnly}&checkItemId=${item?.id}&fileList=${encodeURIComponent(JSON.stringify(fileList))}&useOnline=${props.useOnline}&readOnly=${readOnly}`,
  770. })
  771. }
  772. const handleAssociationOperation = (item: CheckItem) => {
  773. props.handleAssociationOperationManual?.(item)
  774. }
  775. const showAddWorkInstructionPopup = async () => {
  776. try {
  777. const result = await pressure2NotVerifyPageApi({ reportType: PressureReportType.WORKINSTRUCTION, status: 200, pageNo: 1, pageSize: 9999 })
  778. const list = (result?.data || []).map((item: any) => ({
  779. ...item,
  780. label: item.tbName || '',
  781. value: item.id || '',
  782. }))
  783. if (!list.length) {
  784. uni.showToast({ title: '暂无指导书模板', icon: 'error' })
  785. return
  786. }
  787. templateList.value = list
  788. selectedTemplate.value = null
  789. showSelectTemplatePopup.value = true
  790. } catch (error) {
  791. console.error('获取操作指导书模板失败:', error)
  792. uni.showToast({ title: '获取操作指导书模板失败', icon: 'error' })
  793. }
  794. }
  795. const closeSelectTemplatePopup = () => {
  796. showSelectTemplatePopup.value = false
  797. selectedTemplate.value = null
  798. }
  799. const onTemplateChange = (e: any) => {
  800. const index = e.detail.value
  801. selectedTemplate.value = templateList.value[index]
  802. }
  803. const handleConfirmTemplate = async () => {
  804. if (!selectedTemplate.value) {
  805. uni.showToast({ title: '请选择模板', icon: 'error' })
  806. return
  807. }
  808. try {
  809. uni.showLoading({ title: '添加中...' })
  810. const params = {
  811. orderId: props.orderId,
  812. orderItemId: props.orderItemId,
  813. templateId: selectedTemplate.value.value,
  814. prepareId: userInfo.value?.id || '',
  815. prepareName: userInfo.value?.nickname || '',
  816. }
  817. const result = await addPipeMajorIssues(params)
  818. if (result.code !== 0) {
  819. uni.hideLoading()
  820. uni.showToast({ title: result?.msg || '添加失败', icon: 'error' })
  821. return
  822. }
  823. const newReportId = result?.data || ''
  824. if (!newReportId) {
  825. uni.hideLoading()
  826. uni.showToast({ title: '添加失败', icon: 'error' })
  827. return
  828. }
  829. uni.navigateTo({
  830. url: `/pages/editor/workInstructionEditor?templateId=${selectedTemplate.value.value}&refId=${newReportId}`,
  831. })
  832. } catch (error) {
  833. uni.hideLoading()
  834. console.error('添加指导书失败:', error)
  835. uni.showToast({ title: '添加指导书失败', icon: 'error' })
  836. } finally {
  837. uni.hideLoading()
  838. closeSelectTemplatePopup()
  839. props.refreshDetail?.()
  840. }
  841. }
  842. const showCheckProjectPopup = () => {
  843. props.showCheckProjectPopupFn?.()
  844. }
  845. const handleCheckReport = async () => {
  846. if (selectedProjects.value.length === 0) {
  847. uni.showToast({ title: '请选择要上传的项目', icon: 'error' })
  848. return
  849. }
  850. try {
  851. const itemArray = selectedProjects.value
  852. .map((id) => props.reportList.find((i) => i.id === id))
  853. .filter(Boolean)
  854. for (const checkItem of itemArray) {
  855. const userId =
  856. checkItem.reportType === PressureReportType.MAIN
  857. ? props.equipment?.mainCheckerUser?.id
  858. : checkItem?.checkUsers?.[0]?.id
  859. if (userId && userId !== userInfo.value?.id) {
  860. uni.showToast({ title: '已分配项目不支持上传', icon: 'error' })
  861. return
  862. }
  863. }
  864. const { checkedCheckItemhasSubmited } = await import('@/api/task')
  865. const promiseArr = itemArray.map((item) => checkedCheckItemhasSubmited({ id: item.id }))
  866. const result = await Promise.all(promiseArr)
  867. const checkNameArr = []
  868. for (const res of result) {
  869. if (res?.code === 0 && res?.data?.isSubmit) {
  870. checkNameArr.push(res?.data.checkName)
  871. }
  872. }
  873. if (checkNameArr?.length) {
  874. tipsPopupRef.value?.show({
  875. text: `检验员:${checkNameArr.join('、')}已经提交过,确定要覆盖吗?`,
  876. confirm: handleBatchUpload,
  877. })
  878. } else {
  879. handleBatchUpload()
  880. }
  881. } catch (error) {
  882. console.error('批量上传失败:', error)
  883. uni.showToast({ title: '项目检验失败', icon: 'error' })
  884. }
  885. }
  886. const handleBatchUpload = async () => {
  887. try {
  888. uni.showLoading({ title: '上传中...' })
  889. const itemArray = selectedProjects.value
  890. .map((id) => props.reportList.find((i) => i.id === id))
  891. .filter(Boolean)
  892. const params: any = { addList: [], updateList: [] }
  893. itemArray.forEach((item) => {
  894. const dic = {
  895. orderId: props.orderId,
  896. orderItemId: props.orderItemId,
  897. reportUrl: item.reportUrl || '',
  898. dataJson: '',
  899. prepareUrl: '',
  900. prepareJson: item.prepareJson || '',
  901. modifiedReason: '',
  902. templateId: item.templateId,
  903. reportType: item.reportType,
  904. equipAddress: props.equipment?.equipAddress || '',
  905. equipLatitude: props.equipment?.equipLatitude || '',
  906. equipLongitude: props.equipment?.equipLongitude || '',
  907. fee: item?.fee || 0,
  908. }
  909. if (item.isLocal) {
  910. dic.localId = item.id
  911. params.addList.push(dic)
  912. } else {
  913. dic.id = item.id
  914. params.updateList.push(dic)
  915. }
  916. })
  917. const { postCheckItemRecordEnter } = await import('@/api/task')
  918. const postResult = await postCheckItemRecordEnter(params)
  919. uni.hideLoading()
  920. if (postResult.data) {
  921. uni.showToast({ title: '提交成功', icon: 'success' })
  922. props.refreshDetail?.()
  923. initSelected()
  924. } else {
  925. uni.showToast({ title: postResult?.msg || '提交失败', icon: 'error' })
  926. }
  927. } catch (error) {
  928. uni.hideLoading()
  929. console.error('批量上传失败:', error)
  930. uni.showToast({ title: '批量上传失败', icon: 'error' })
  931. }
  932. }
  933. const handleDelReport = () => {
  934. if (selectedProjects.value.length === 0) {
  935. uni.showToast({ title: '请选择要作废的项目', icon: 'error' })
  936. return
  937. }
  938. const hasMain = selectedProjects.value.some((id) => {
  939. const item = props.reportList.find((i) => i.id === id)
  940. return item?.reportType === PressureReportType.MAIN
  941. })
  942. if (hasMain) {
  943. uni.showToast({ title: '主报告不能作废', icon: 'error' })
  944. return
  945. }
  946. const hasReportEnd =
  947. props.useOnline === '1' &&
  948. selectedProjects.value.some((id) => {
  949. const item = props.reportList.find((i) => i.id === id)
  950. return item?.taskStatus === PressureCheckerMyTaskStatus.REPORT_END
  951. })
  952. if (hasReportEnd) {
  953. uni.showToast({ title: '报告办结状态的项目不能作废', icon: 'error' })
  954. return
  955. }
  956. tipsPopupRef.value?.show({
  957. text: '是否作废已选择的检验项目?',
  958. confirm: async () => {
  959. try {
  960. uni.showLoading({ title: '作废中...' })
  961. const cancelIds = selectedProjects.value
  962. let result = null
  963. if (props.useOnline === '1') {
  964. const cancelReq: any[] = []
  965. cancelIds.forEach((id) => {
  966. cancelReq.push({ id, reason: '' })
  967. })
  968. const fetchResult = await cancelPipeInSpectProject(cancelReq)
  969. result = fetchResult.data
  970. } else {
  971. uni.showToast({ title: '离线模式作废功能开发中', icon: 'none' })
  972. uni.hideLoading()
  973. return
  974. }
  975. uni.hideLoading()
  976. if (result) {
  977. props.refreshDetail?.()
  978. initSelected()
  979. uni.showToast({ title: '作废成功', icon: 'success' })
  980. } else {
  981. uni.showToast({ title: '作废失败', icon: 'error' })
  982. }
  983. } catch (error) {
  984. uni.hideLoading()
  985. console.error('作废失败:', error)
  986. uni.showToast({ title: '作废失败', icon: 'error' })
  987. }
  988. },
  989. })
  990. }
  991. const uploadFileAndSubmitCheckItemCallback = {
  992. callback: async (item: CheckItem) => {
  993. const userId =
  994. item.reportType === PressureReportType.MAIN
  995. ? props.equipment?.mainCheckerUser?.id
  996. : item?.checkUsers?.[0]?.id
  997. if (userId && userId !== userInfo.value?.id) {
  998. uni.showToast({ title: '已分配项目不支持上传', icon: 'error' })
  999. return
  1000. }
  1001. try {
  1002. uni.showLoading({ title: '上传中...' })
  1003. const params = {
  1004. orderId: props.orderId,
  1005. orderItemId: props.orderItemId,
  1006. reportUrl: item.reportUrl || '',
  1007. dataJson: '',
  1008. prepareUrl: '',
  1009. prepareJson: item.prepareJson || '',
  1010. modifiedReason: '',
  1011. templateId: item.templateId,
  1012. reportType: item.reportType,
  1013. fee: item?.fee || 0,
  1014. }
  1015. const newParams: any = {}
  1016. if (item.isLocal) {
  1017. params.localId = item.id
  1018. newParams.addList = [params]
  1019. } else {
  1020. params.id = item.id
  1021. newParams.updateList = [params]
  1022. }
  1023. const { postCheckItemRecordEnter } = await import('@/api/task')
  1024. const postResult = await postCheckItemRecordEnter(newParams)
  1025. uni.hideLoading()
  1026. if (postResult.data) {
  1027. uni.showToast({ title: '提交成功', icon: 'success' })
  1028. props.refreshDetail?.()
  1029. } else {
  1030. uni.showToast({ title: postResult?.msg || '提交失败', icon: 'error' })
  1031. }
  1032. } catch (error) {
  1033. uni.hideLoading()
  1034. console.error('上传失败:', error)
  1035. uni.showToast({ title: '上传失败', icon: 'error' })
  1036. }
  1037. },
  1038. }
  1039. </script>
  1040. <style lang="scss" scoped>
  1041. .inspect-project-container {
  1042. display: flex;
  1043. flex-direction: column;
  1044. height: 100%;
  1045. background-color: #f5f5f5;
  1046. }
  1047. .scroll-list {
  1048. flex: 1;
  1049. padding: 12px;
  1050. padding-bottom: 80px;
  1051. }
  1052. .report-list {
  1053. display: flex;
  1054. flex-direction: column;
  1055. }
  1056. .report-item {
  1057. padding: 15px;
  1058. margin-bottom: 12px;
  1059. background-color: #fff;
  1060. border-radius: 5px;
  1061. }
  1062. .item-top {
  1063. display: flex;
  1064. flex-direction: row;
  1065. align-items: center;
  1066. justify-content: space-between;
  1067. padding-bottom: 10px;
  1068. border-bottom: 1px solid rgb(244, 244, 244);
  1069. }
  1070. .top-left {
  1071. display: flex;
  1072. flex: 1;
  1073. flex-direction: row;
  1074. align-items: center;
  1075. }
  1076. .report-name {
  1077. margin-left: 8px;
  1078. font-size: 15px;
  1079. color: rgb(51, 51, 51);
  1080. }
  1081. .type-tag {
  1082. display: flex;
  1083. align-items: center;
  1084. justify-content: center;
  1085. width: 20px;
  1086. height: 20px;
  1087. margin-left: 10px;
  1088. border-radius: 4px;
  1089. }
  1090. .type-tag-text {
  1091. font-size: 12px;
  1092. color: rgb(252, 255, 253);
  1093. }
  1094. .status-text {
  1095. font-size: 15px;
  1096. }
  1097. .item-center {
  1098. margin-top: 10px;
  1099. }
  1100. .center-row {
  1101. display: flex;
  1102. flex-direction: row;
  1103. align-items: center;
  1104. margin-bottom: 10px;
  1105. }
  1106. .label {
  1107. width: 80px;
  1108. font-size: 15px;
  1109. color: rgb(51, 51, 51);
  1110. }
  1111. .conclusion-box {
  1112. min-width: 80px;
  1113. padding: 10px;
  1114. background-color: rgb(243, 245, 247);
  1115. border: 1px solid rgb(187, 187, 187);
  1116. border-radius: 4px;
  1117. }
  1118. .conclusion-error {
  1119. background-color: #fff2f2;
  1120. border-color: #ff3535;
  1121. }
  1122. .conclusion-text {
  1123. font-size: 13px;
  1124. color: #4b8cd9;
  1125. }
  1126. .conclusion-error-text {
  1127. color: #ff3535;
  1128. }
  1129. .result-box {
  1130. flex: 1;
  1131. padding: 10px;
  1132. background-color: rgb(243, 245, 247);
  1133. border: 1px solid rgb(187, 187, 187);
  1134. border-radius: 4px;
  1135. }
  1136. .result-text {
  1137. font-size: 13px;
  1138. }
  1139. .right-area {
  1140. display: flex;
  1141. flex: 1;
  1142. flex-direction: row;
  1143. flex-wrap: wrap;
  1144. align-items: center;
  1145. justify-content: flex-end;
  1146. }
  1147. .instruction-tag {
  1148. padding: 4px 8px;
  1149. margin-right: 8px;
  1150. background-color: #f2f6ff;
  1151. border: 1px solid #4b8cd9;
  1152. border-radius: 4px;
  1153. }
  1154. .instruction-tag-error {
  1155. background-color: #fff2f2;
  1156. border-color: #ff3535;
  1157. }
  1158. .instruction-text {
  1159. font-size: 12px;
  1160. color: #4b8cd9;
  1161. }
  1162. .instruction-text-error {
  1163. color: #ff3535;
  1164. }
  1165. .inspector-name {
  1166. font-size: 15px;
  1167. color: rgb(51, 51, 51);
  1168. }
  1169. .inspector-btn {
  1170. display: flex;
  1171. flex-direction: row;
  1172. align-items: center;
  1173. }
  1174. .inspector-label {
  1175. font-size: 15px;
  1176. color: rgb(51, 51, 51);
  1177. }
  1178. .inspector-value {
  1179. font-size: 15px;
  1180. color: rgb(75, 140, 217);
  1181. }
  1182. .fee-area {
  1183. display: flex;
  1184. flex: 1;
  1185. flex-direction: row;
  1186. align-items: center;
  1187. justify-content: space-between;
  1188. }
  1189. .fee-btns {
  1190. display: flex;
  1191. flex-direction: row;
  1192. align-items: center;
  1193. }
  1194. .fee-value-box {
  1195. padding: 4px 8px;
  1196. margin-right: 3px;
  1197. background-color: #f3f5f7;
  1198. border: 1px solid rgb(182, 216, 236);
  1199. border-radius: 4px;
  1200. }
  1201. .fee-value {
  1202. font-size: 12px;
  1203. color: rgb(75, 140, 217);
  1204. }
  1205. .fee-none {
  1206. font-size: 12px;
  1207. color: rgb(75, 140, 217);
  1208. }
  1209. .fee-btn {
  1210. padding: 4px 8px;
  1211. background-color: rgb(47, 142, 255);
  1212. border: 1px solid rgb(47, 142, 255);
  1213. border-radius: 4px;
  1214. }
  1215. .fee-btn-text {
  1216. font-size: 12px;
  1217. color: rgb(222, 238, 255);
  1218. }
  1219. .action-btns {
  1220. display: flex;
  1221. flex: 1;
  1222. flex-direction: row;
  1223. flex-wrap: wrap;
  1224. justify-content: flex-end;
  1225. }
  1226. .action-btn {
  1227. display: flex;
  1228. align-items: center;
  1229. justify-content: center;
  1230. height: 29px;
  1231. padding: 0 5px;
  1232. margin-left: 3px;
  1233. background-color: #f3f5f7;
  1234. border: 1px solid rgb(182, 216, 236);
  1235. border-radius: 4px;
  1236. }
  1237. .action-btn-text {
  1238. font-size: 12px;
  1239. color: rgb(75, 140, 217);
  1240. }
  1241. .sign-btn {
  1242. background-color: rgba(78, 185, 95, 1);
  1243. border-color: rgba(78, 185, 95, 1);
  1244. }
  1245. .sign-btn .action-btn-text {
  1246. color: rgb(222, 238, 255);
  1247. }
  1248. .attachment-btn {
  1249. background-color: rgb(230, 162, 60);
  1250. border-color: rgb(230, 162, 60);
  1251. }
  1252. .attachment-btn .action-btn-text {
  1253. color: rgb(222, 238, 255);
  1254. }
  1255. .record-btn,
  1256. .re-input-btn {
  1257. background-color: #f3f5f7;
  1258. }
  1259. .submit-check-btn,
  1260. .submit-report-btn {
  1261. margin-right: 0;
  1262. background-color: rgb(47, 142, 255);
  1263. border-color: rgb(47, 142, 255);
  1264. }
  1265. .submit-check-btn .action-btn-text,
  1266. .submit-report-btn .action-btn-text {
  1267. color: rgb(222, 238, 255);
  1268. }
  1269. .empty-state {
  1270. display: flex;
  1271. align-items: center;
  1272. justify-content: center;
  1273. padding: 40px 0;
  1274. }
  1275. .empty-text {
  1276. font-size: 14px;
  1277. color: #999;
  1278. }
  1279. .bottom-bar {
  1280. position: fixed;
  1281. right: 0;
  1282. bottom: 0;
  1283. left: 0;
  1284. z-index: 100;
  1285. display: flex;
  1286. flex-direction: row;
  1287. align-items: center;
  1288. justify-content: space-between;
  1289. height: 68px;
  1290. padding: 0 12px;
  1291. background-color: #fff;
  1292. border-top: 1px solid rgb(244, 244, 244);
  1293. }
  1294. .select-all-box {
  1295. display: flex;
  1296. flex: 1;
  1297. flex-direction: row;
  1298. align-items: center;
  1299. }
  1300. .square-checkbox {
  1301. border-radius: 0 !important;
  1302. transform: scale(0.9);
  1303. }
  1304. .select-all-text {
  1305. margin-left: 10px;
  1306. font-size: 15px;
  1307. line-height: 1.4;
  1308. color: rgb(51, 51, 51);
  1309. white-space: pre-line;
  1310. }
  1311. .action-buttons {
  1312. display: flex;
  1313. flex: 2;
  1314. flex-direction: row;
  1315. align-items: center;
  1316. justify-content: flex-end;
  1317. }
  1318. .operate-btn {
  1319. display: flex;
  1320. align-items: center;
  1321. justify-content: center;
  1322. min-width: 66px;
  1323. height: 40px;
  1324. padding: 0 5px;
  1325. margin-left: 5px;
  1326. border-radius: 4px;
  1327. }
  1328. .operate-btn-text {
  1329. font-size: 14px;
  1330. color: rgb(251, 253, 255);
  1331. }
  1332. .delete-btn {
  1333. background-color: #ff4445;
  1334. }
  1335. .guide-btn {
  1336. background-color: #e6a23c;
  1337. }
  1338. .add-btn {
  1339. background-color: #e6a23c;
  1340. }
  1341. .upload-btn {
  1342. background-color: rgb(47, 142, 255);
  1343. }
  1344. .popup-overlay {
  1345. position: fixed;
  1346. top: 0;
  1347. right: 0;
  1348. bottom: 0;
  1349. left: 0;
  1350. z-index: 999;
  1351. display: flex;
  1352. align-items: center;
  1353. justify-content: center;
  1354. background-color: rgba(0, 0, 0, 0.5);
  1355. }
  1356. .popup-content {
  1357. width: 80%;
  1358. max-width: 300px;
  1359. padding: 20px;
  1360. background-color: #fff;
  1361. border-radius: 8px;
  1362. }
  1363. .popup-title {
  1364. display: block;
  1365. margin-bottom: 20px;
  1366. font-size: 18px;
  1367. font-weight: bold;
  1368. color: #333;
  1369. text-align: center;
  1370. }
  1371. .picker-value {
  1372. padding: 10px;
  1373. margin-bottom: 20px;
  1374. border: 1px solid #ddd;
  1375. border-radius: 4px;
  1376. }
  1377. .popup-actions {
  1378. display: flex;
  1379. justify-content: space-between;
  1380. }
  1381. .popup-actions .action-btn {
  1382. flex: 1;
  1383. padding: 10px 0;
  1384. margin: 0 5px;
  1385. font-size: 14px;
  1386. text-align: center;
  1387. border-radius: 4px;
  1388. }
  1389. .popup-actions .cancel-btn {
  1390. color: #666;
  1391. background-color: #f5f5f5;
  1392. }
  1393. .popup-actions .confirm-btn {
  1394. color: #fff;
  1395. background-color: #007aff;
  1396. }
  1397. </style>