index.vue 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  1. <template>
  2. <home-container>
  3. <view class="report-container">
  4. <!-- 表单区域 -->
  5. <uni-forms ref="form" :rules="rules" :modelValue="formData" label-position="top" err-show-type="modal">
  6. <!-- <scroll-view class="form-scroll" scroll-y> -->
  7. <!-- 安检员信息分组 (默认折叠) -->
  8. <!-- <view class="card" style="overflow: visible;"> -->
  9. <uni-collapse class="collapse" :class="firstCollapsed.length > 0 ? 'collapse-card' : 'collapse-card-hidden'"
  10. :accordion="false" v-model="firstCollapsed" @change="changeCollapse">
  11. <uni-collapse-item class="collapse-item" title="安检员信息" name="group1" :show-animation="true">
  12. <template v-slot:title>
  13. <view class="header-section collapse-title userInfo">
  14. <view class="userName">{{ `${type !== 'add' ? '查获人:' : ''}` }}{{ type !==
  15. 'add' ? `${formData.inspectUserName}(${formData.createBy})` :
  16. `${userInfo.nickName}(${userInfo.userName})`
  17. }}
  18. </view>
  19. <view class="teamInfo" v-if="type !== 'add'">
  20. <view>{{ formData.inspectUserRoleName }}</view>
  21. <view class="team">
  22. <view v-if="formData.inspectStationName">
  23. {{ formData.inspectStationName }}
  24. </view>
  25. <view v-if="formData.inspectDepartmentName">
  26. /{{ formData.inspectDepartmentName }}
  27. </view>
  28. <view v-if="formData.inspectTeamName">
  29. /{{ formData.inspectTeamName }}
  30. </view>
  31. </view>
  32. </view>
  33. <view class="teamInfo" v-else>
  34. <view>安检员</view>
  35. <view class="team">
  36. <view v-if="userInfo.stationName">
  37. {{ userInfo.stationName }}
  38. </view>
  39. <view v-if="userInfo.departmentName">
  40. /{{ userInfo.departmentName }}
  41. </view>
  42. <view v-if="userInfo.teamsName">
  43. /{{ userInfo.teamsName }}
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </template>
  49. <!-- kezhang角色显示查获人员选择 -->
  50. <uni-forms-item v-if="isKezhang && !isDetailMode" label="查获人员" name="inspectUserId" required>
  51. <uni-data-picker :readonly="isDetailMode" :localdata="departmentUserOptions" popup-title="请选择查获人员"
  52. v-model="formData.inspectUserId" @change="onInspectUserChange" />
  53. </uni-forms-item>
  54. <uni-forms-item v-else-if="isKezhang && isDetailMode" label="查获人员">
  55. <uni-easyinput :disabled="true" placeholder="查获人员" :value="formData.inspectUserName" />
  56. </uni-forms-item>
  57. <uni-forms-item label="查获时间" name="seizureTime" required>
  58. <uni-datetime-picker :disabled="isDetailMode" type="datetime" :start="startDate" :end="endDate"
  59. v-model="formData.seizureTime" />
  60. </uni-forms-item>
  61. <uni-forms-item label="安检岗位" name="checkMethodText" required>
  62. <uni-combox :disabled="isDetailMode" :candidates="checkMethodCandidates" placeholder="请选择安检岗位"
  63. v-model="formData.checkMethodText" @input="onCheckMethodComboxChange" />
  64. </uni-forms-item>
  65. <uni-forms-item label="查获位置" name="securityLocation" required>
  66. <uni-data-picker v-if="!isDetailMode" :readonly="isDetailMode" :localdata="position_options"
  67. popup-title="请选择查获位置" v-model="formData.securityLocation" @change="onLocationChange" />
  68. <uni-easyinput v-else :disabled="true" placeholder="请选择查获班组" :value="formData.securityLocationText" />
  69. </uni-forms-item>
  70. <uni-forms-item label="查获班组" name="reportTeam" required>
  71. <uni-data-picker v-if="!isDetailMode" :readonly="isDetailMode" :localdata="teams" popup-title="请选择查获班组"
  72. v-model="formData.reportTeam" @change="onReportTeamChange" />
  73. <uni-easyinput v-else :disabled="true" placeholder="请选择查获班组" :value="formData.attendanceTeamName" />
  74. </uni-forms-item>
  75. <!-- 开机指令(仅开箱检查岗位显示) -->
  76. <uni-forms-item v-if="isPackageInspection" label="开机指令" name="powerOnInstruction" required>
  77. <radio-group v-if="!isDetailMode" @change="onpowerOnInstructionChange" class="radio-group"
  78. :class="{ 'disabled-group': isDetailMode }">
  79. <label class="radio-item" v-for="(item, index) in powerOnInstructionOptions" :key="index">
  80. <radio :value="item.value" :checked="formData.powerOnInstruction == item.value" color="#409EFF" />
  81. <text>{{ item.text }}</text>
  82. </label>
  83. </radio-group>
  84. <uni-easyinput v-else :disabled="true" placeholder="请选择开机指令" :value="formData.powerOnInstructionText" />
  85. </uni-forms-item>
  86. <!-- X光开机员(仅非指令时显示) -->
  87. <uni-forms-item v-if="showXrayOperator" label="X光开机员" name="xrayOperatorId" required>
  88. <fuzzy-select v-if="!isDetailMode" v-model="formData.xrayOperatorId" :options="xrayOperatorOptions"
  89. placeholder="请输入X光开机员姓名搜索" data-value="userId" data-text="nickName" @change="handleXrayOperatorSelect"
  90. :disabled="isDetailMode" />
  91. <uni-easyinput v-else :disabled="true" placeholder="请选择X光开机员" :value="formData.xrayOperatorName" />
  92. </uni-forms-item>
  93. </uni-collapse-item>
  94. </uni-collapse>
  95. <!-- </view> -->
  96. <!-- 违禁品信息分组 -->
  97. <view class="card">
  98. <uni-collapse class="collapse" :accordion="false" :value="['group2']">
  99. <uni-collapse-item class="collapse-item" title="违禁品信息" name="group2" :show-animation="true">
  100. <uni-forms-item label="常用违禁品" v-if="type == 'add'">
  101. <view class="gridWrap">
  102. <uni-tag v-for="item of commonlyList.forbidden" :key="item.categoryId" @click="selectCategory(item)"
  103. :text="item.categoryName" type="primary"
  104. :inverted="formData.forbiddenCategory !== item.categoryId" />
  105. </view>
  106. </uni-forms-item>
  107. <uni-forms-item label="搜索违禁品" v-if="type == 'add'">
  108. <SearchView title="搜索违禁品" :load="searchLoadData" placeholder="请选择/输入违禁品名称"
  109. :map="{ text: 'name', value: 'id' }" @change="searchSelectChange" />
  110. </uni-forms-item>
  111. <uni-forms-item label="违禁品类别/类型" name="forbiddenType" required>
  112. <uni-data-picker v-if="!isDetailMode" :readonly="isDetailMode" :localdata="item_category_options"
  113. :map="dataTreeOptionMap" popup-title="请选择违禁品类别" v-model="formData.forbiddenType"
  114. @change="onCategoryChange" />
  115. <uni-easyinput v-else :disabled="true" placeholder="请选择违禁品类别/类型"
  116. :value="`${formData.forbiddenCategoryText} / ${formData.forbiddenTypeText}`" />
  117. </uni-forms-item>
  118. <uni-forms-item label="违禁品名称" name="forbiddenName">
  119. <uni-easyinput :disabled="isDetailMode" placeholder="请输入违禁品名称" v-model="formData.forbiddenName" />
  120. </uni-forms-item>
  121. <uni-forms-item label="数量" name="quantity" required>
  122. <view class="number-input">
  123. <uni-easyinput :disabled="isDetailMode" v-model="formData.quantity" type="number" placeholder="1"
  124. class="input-number" />
  125. <!-- <uni-data-picker :localdata="item_unit_options" :map="dataOptionMap" popup-title="请选择单位"
  126. v-model="formData.unit" @change="onUnitChange" name="unit" required /> -->
  127. </view>
  128. </uni-forms-item>
  129. <uni-forms-item label="是否常见违禁品" name="commonContraband" required>
  130. <radio-group @change="onCommonForbiddenChange" class="radio-group"
  131. :class="{ 'disabled-group': isDetailMode }">
  132. <label class="radio-item" v-for="(item, index) in commonForbiddenOptions" :key="index">
  133. <radio :value="item.value" :checked="formData.commonContraband == item.value" color="#409EFF" />
  134. <text>{{ item.text }}</text>
  135. </label>
  136. </radio-group>
  137. </uni-forms-item>
  138. <uni-forms-item v-if="formData.commonContraband == 0" label="违禁品描述" name="contrabandDesc" required>
  139. <uni-easyinput :disabled="isDetailMode" placeholder="请输入违禁品详细描述" v-model="formData.contrabandDesc" />
  140. </uni-forms-item>
  141. <!-- 违禁品照片 (当选择"否"时显示) -->
  142. <uni-forms-item
  143. v-if="(!isDetailMode || isDetailMode && formData.images.length > 0) && formData.commonContraband == 0"
  144. label="违禁品照片">
  145. <view style="padding: 0 15px 15px 15px;">
  146. <uni-file-picker :disabled="isDetailMode" :readonly="isDetailMode" v-model="formData.images" limit="3"
  147. title="最多上传3张" :image-styles="imageStyles" fileMediatype="image" mode="grid" @select="onSelect" />
  148. </view>
  149. </uni-forms-item>
  150. </uni-collapse-item>
  151. </uni-collapse>
  152. </view>
  153. <!-- 查获部位分组 -->
  154. <view class="card">
  155. <uni-collapse class="collapse" :accordion="false" :value="['group3']">
  156. <uni-collapse-item class="collapse-item" title="查获部位" name="group3" :show-animation="true">
  157. <uni-forms-item label="常用查获部位" v-if="type == 'add'">
  158. <view class="gridWrap">
  159. <uni-tag v-for="item of commonlyList.part" :key="item.categoryId" @click="selectPart(item)"
  160. :text="item.categoryName" type="primary" :inverted="formData.partCategory !== item.categoryId" />
  161. </view>
  162. </uni-forms-item>
  163. <uni-forms-item label="部位类别/类型" name="partType" required>
  164. <uni-data-picker v-if="!isDetailMode" :readonly="isDetailMode" :localdata="check_point_options"
  165. :map="dataTreeOptionMap" popup-title="请选择部位类别" :value="formData.partType"
  166. @change="onPartCategoryChange" />
  167. <uni-easyinput v-else :disabled="true" placeholder="请选择部位类别"
  168. :value="`${formData.partCategoryText} / ${formData.partTypeText}`" />
  169. </uni-forms-item>
  170. <uni-forms-item label="具体位置" name="location">
  171. <uni-easyinput :disabled="isDetailMode" placeholder="请输入具体位置" v-model="formData.location" />
  172. </uni-forms-item>
  173. <uni-forms-item label="处理方式" name="handlingMethod" required>
  174. <uni-data-picker v-if="!isDetailMode" :readonly="isDetailMode" popup-title="请选择处理方式"
  175. :map="dataOptionMap" :localdata="item_handling_method_options" v-model="formData.handlingMethod"
  176. @change="onMethodChange" />
  177. <uni-easyinput v-else :disabled="true" placeholder="请选择处理方式" v-model="formData.handlingMethodDesc" />
  178. </uni-forms-item>
  179. <uni-forms-item label="是否隐匿夹带" name="isActiveConcealment" required>
  180. <radio-group @change="bindConcealChange" class="radio-group"
  181. :class="{ 'disabled-group': isDetailMode }">
  182. <label class="radio-item" v-for="(item, index) in concealOptions" :key="index">
  183. <radio :value="item.value" :checked="formData.isActiveConcealment === item.value" color="#409EFF" />
  184. <text>{{ item.name }}</text>
  185. </label>
  186. </radio-group>
  187. </uni-forms-item>
  188. </uni-collapse-item>
  189. </uni-collapse>
  190. </view>
  191. <!-- 违禁品照片分组 -->
  192. <!-- <view class="card" v-if="!isDetailMode || isDetailMode && formData.images.length > 0">
  193. <uni-collapse class="collapse" :accordion="false" :value="['group4']">
  194. <uni-collapse-item class="collapse-item" title="违禁品照片 (可选)" name="group4" :show-animation="true">
  195. <view style="padding: 0 15px 15px 15px;margin-bottom: 150rpx;">
  196. <uni-file-picker :disabled="isDetailMode" v-model="formData.images" limit="8" title="最多上传8张"
  197. :image-styles="imageStyles" fileMediatype="image" mode="grid" @select="onSelect" />
  198. </view>
  199. </uni-collapse-item>
  200. </uni-collapse>
  201. </view> -->
  202. <!-- 5. 审批历史分组 -->
  203. <view class="card" v-if="type !== 'add'">
  204. <uni-collapse class="collapse" :accordion="false" :value="['group5']">
  205. <h-collapse-item title="审批历史" name="group5" :show-animation="true"
  206. :iconUrl="'../../static/images/icon/lishi.png'">
  207. <approve-history :history-list="approvalHistory" />
  208. </h-collapse-item>
  209. </uni-collapse>
  210. </view>
  211. <!-- 旅客信息分组 -->
  212. <!-- <view :is-shadow="true" :shadow="shadow">
  213. <uni-collapse :accordion="false" :value="['group5']">
  214. <uni-collapse-item title="旅客信息" name="group5" :show-animation="true">
  215. <template v-slot:title>
  216. <view class="collapse-title">
  217. <text>旅客信息</text>
  218. <text class="collapse-summary" v-if="formData.passengerName">{{ formData.passengerName }} ·
  219. {{ formData.flightNumber || '无航班号' }}</text>
  220. </view>
  221. </template>
  222. <uni-forms-item label="姓名" name="passengerName">
  223. <uni-easyinput :disabled="isDetailMode" v-model="formData.passengerName" placeholder="请输入旅客姓名" />
  224. </uni-forms-item>
  225. <uni-forms-item label="证件号" name="passengerId">
  226. <uni-easyinput :disabled="isDetailMode" v-model="formData.passengerId" placeholder="请输入证件号 (可选)" />
  227. </uni-forms-item>
  228. <uni-forms-item label="航班号" name="flightNumber">
  229. <uni-easyinput :disabled="isDetailMode" v-model="formData.flightNumber" placeholder="例如:CA1234 (可选)" />
  230. </uni-forms-item>
  231. </uni-collapse-item>
  232. </uni-collapse>
  233. </view> -->
  234. <!-- 提交按钮 -->
  235. <view class="button-group" v-if="type === 'approve' || type === 'add'">
  236. <view v-if="!isDetailMode" class="custom-btn-normal" @click="submitForm">提交上报</view>
  237. <template v-else>
  238. <view v-if="nodeCode != 'START'" class="custom-btn-white" @click="handleApproveReject"
  239. style="margin-right: 10px;">审批驳回</view>
  240. <view class="custom-btn-normal" @click="handleApprovePass">{{
  241. nodeCode == 'START' ? '提交' : '审批通过' }}</view>
  242. </template>
  243. </view>
  244. <!-- </scroll-view> -->
  245. </uni-forms>
  246. </view>
  247. </home-container>
  248. </template>
  249. <script>
  250. import HomeContainer from "@/components/HomeContainer.vue";
  251. import SearchView from "@/pages/attendance/components/SearchView.vue"
  252. import { treeSelectByType } from "@/api/system/common"
  253. import useDictMixin from '@/utils/dict'
  254. import FuzzySelect from "@/components/fuzzy-select/fuzzy-select.vue"
  255. import { addSeizureRecord, approvalStart, getInfo } from '@/api/seizure/seizureRecord.js'
  256. import { getLocationsbyTime, categoryInfo, categoryList } from '@/api/seizureRecord/seizureRecord.js'
  257. import config from '@/config'
  258. import { getToken } from '@/utils/auth'
  259. import { approvePass, approveReject, getApprovelHistory } from '@/api/approve/approve.js'
  260. import { getDeptList } from "@/api/system/dept/dept.js"
  261. import { formatTime } from '@/utils/formatUtils'
  262. import { getUserInfoById, getPostListsByUserId } from '@/api/system/user.js'
  263. import { getUserList } from '@/api/attendance/attendance'
  264. export default {
  265. components: { HomeContainer, SearchView, FuzzySelect },
  266. mixins: [useDictMixin],
  267. computed: {
  268. currentUser() {
  269. return this.$store.state.user;
  270. },
  271. userInfo() {
  272. return (this.$store.state.user && this.$store.state.user.userInfo) ? this.$store.state.user.userInfo : {}
  273. },
  274. // 判断是否为kezhang角色
  275. isKezhang() {
  276. return this.$store?.state?.user?.roles?.includes('banzuzhang')
  277. },
  278. // 将item_check_method_options转换为字符串数组供uni-combox使用
  279. checkMethodCandidates() {
  280. // console.log(this.item_check_method_options.map(item => item.postName || item.label || item.text || item.value),"this.item_check_method_options.map(item => item.postName || item.label || item.text || item.value)")
  281. return this.item_check_method_options.map(item => item.postName || item.label || item.text || item.value);
  282. },
  283. // 判断是否为开箱(包)检查岗位
  284. isPackageInspection() {
  285. return this.formData.checkMethodText === '开箱(包)检查岗位';
  286. },
  287. // 判断是否显示X光开机员选择(非指令时显示)
  288. showXrayOperator() {
  289. return this.isPackageInspection && this.formData.powerOnInstruction == '1';
  290. },
  291. // // 判断是新增模式还是详情模式
  292. isDetailMode() {
  293. return !!this.businessId; // 如果有id则为详情模式,否则为新增模式
  294. },
  295. // 动态验证规则
  296. rules() {
  297. return {
  298. seizureTime: {
  299. rules: [{ required: true, errorMessage: '请选择查获时间' }]
  300. },
  301. checkMethodText: {
  302. rules: [{ required: true, errorMessage: '请选择安检位置' }]
  303. },
  304. reportTeam: {
  305. rules: [{ required: true, errorMessage: '请选择上报班组' }]
  306. },
  307. powerOnInstruction: {
  308. rules: [{ required: true, errorMessage: '请选择开机指令' }]
  309. },
  310. xrayOperatorId: {
  311. rules: [{ required: true, errorMessage: '请选择X光开机员' }]
  312. },
  313. forbiddenCategory: {
  314. rules: [{ required: true, errorMessage: '请选择违禁品类别' }]
  315. },
  316. forbiddenType: {
  317. rules: [{ required: true, errorMessage: '请选择违禁品类型' }]
  318. },
  319. quantity: {
  320. rules: [
  321. { required: true, errorMessage: '请输入数量' },
  322. { format: 'number', errorMessage: '数量必须为数字' }
  323. ]
  324. },
  325. partCategory: {
  326. rules: [{ required: true, errorMessage: '请选择部位类别' }]
  327. },
  328. unit: {
  329. rules: [{ required: true, errorMessage: '请选择违禁品数量单位' }]
  330. },
  331. partType: {
  332. rules: [{ required: true, errorMessage: '请选择部位类型' }]
  333. },
  334. handlingMethod: {
  335. rules: [{ required: true, errorMessage: '请选择处理方式' }]
  336. },
  337. isActiveConcealment: {
  338. rules: [{ required: true, errorMessage: '请选择是否有意隐匿' }]
  339. },
  340. commonContraband: {
  341. rules: [{ required: true, errorMessage: '请选择是否常见违禁品' }]
  342. },
  343. contrabandDesc: {
  344. rules: [
  345. {
  346. required: this.formData.commonContraband == 0,
  347. errorMessage: '请填写违禁品描述'
  348. }
  349. ]
  350. }
  351. }
  352. }
  353. },
  354. data() {
  355. return {
  356. // 路由参数id,用于判断详情模式
  357. businessId: null,
  358. // 表单数据
  359. formData: {
  360. // 安检员信息
  361. inspectUserName: this.isKezhang ? '' : this.$store.state.user.name,
  362. inspectUserId: this.isKezhang ? '' : this.$store.state.user.id,
  363. seizureTime: this.formatDateTime(new Date()),
  364. securityLocation: '',
  365. securityLocationText: '',
  366. checkMethod: '', // 检查岗位
  367. checkMethodText: '',
  368. teamId: 1,
  369. team: '',
  370. teamName: '',
  371. reportTeam: '',
  372. reportTeamText: '',
  373. // 开机指令相关字段(开箱检查岗位使用)
  374. powerOnInstruction: '0', // 开机指令:'0'-指令, '1'-非指令
  375. powerOnInstructionText: '指令',
  376. xrayOperatorId: '', // X光开机员ID
  377. xrayOperatorName: '', // X光开机员姓名
  378. // 查获位置信息
  379. channelCode: '',
  380. channelName: '',
  381. // 违禁品信息
  382. forbiddenCategory: '',
  383. forbiddenCategoryText: '',
  384. forbiddenType: '',
  385. forbiddenTypeText: '',
  386. forbiddenName: '',
  387. quantity: '1',
  388. unit: '',
  389. unitText: '',
  390. commonContraband: 1, // 是否常见违禁品:1-是,0-否
  391. contrabandDesc: '', // 违禁品描述(选择否时必填)
  392. // 查获部位
  393. partCategory: '',
  394. partCategoryText: '',
  395. partType: '',
  396. partTypeText: '',
  397. location: '',
  398. locationText: '',
  399. customLocation: '',
  400. handlingMethod: 'ABANDON',
  401. handlingMethodDesc: '自弃',
  402. isActiveConcealment: '0',
  403. // 旅客信息
  404. passengerName: '',
  405. passengerId: '',
  406. flightNumber: '',
  407. // 照片
  408. images: [],
  409. //暂时不要
  410. attendanceId: '',
  411. attendanceTeamId: '',
  412. attendanceTeamName: '无',
  413. attendanceDepartmentId: '',
  414. attendanceDepartmentName: '无',
  415. attendanceStationId: '',
  416. attendanceStationName: '无',
  417. regionalCode: '',
  418. regionalName: '无',
  419. terminlCode: '',
  420. terminlName: '无',
  421. inspectTeamId: '',
  422. inspectTeamName: '无',
  423. inspectDepartmentId: '',
  424. inspectDepartmentName: '无',
  425. checkMethodDesc: '无',
  426. passengerCard: '',
  427. flightNumber: '',
  428. },
  429. // 数据选项
  430. item_check_method_options: [], // 检查岗位
  431. position_options: [], // 位置通道
  432. teams: [],
  433. item_category_options: [], // 物品分类
  434. departmentUserOptions: [], // 部门人员选项(kezhang角色使用)
  435. typeData: [],
  436. item_unit_options: [],
  437. check_point_options: [],
  438. partTypeData: [],
  439. locations: [
  440. ],
  441. item_handling_method_options: [], // 处理方式
  442. concealOptions: [
  443. { name: '是', value: '1' },
  444. { name: '否', value: '0' }
  445. ],
  446. // 开机指令选项
  447. powerOnInstructionOptions: [
  448. { text: '指令', value: '0' },
  449. { text: '非指令', value: '1' }
  450. ],
  451. // 是否常见违禁品选项
  452. commonForbiddenOptions: [
  453. { text: '是', value: 1 },
  454. { text: '否', value: 0 }
  455. ],
  456. // X光开机员选项
  457. xrayOperatorOptions: [],
  458. // 其他数据
  459. startDate: '2020-01-01',
  460. endDate: '2030-12-31',
  461. imageStyles: {
  462. width: 80,
  463. height: 80,
  464. border: {
  465. color: '#eee',
  466. width: '1px',
  467. style: 'solid'
  468. }
  469. },
  470. dataOptionMap1: { text: 'label', value: 'value' }, // 级联字段映射关系
  471. dataOptionMap: { text: 'label', value: 'value' }, // 级联字段映射关系
  472. dataTreeOptionMap: { text: 'label', value: 'id' }, // 级联字段映射关系树结构
  473. commonlyList: {
  474. forbidden: [],
  475. part: []
  476. },
  477. searchforbiddenName: '',
  478. forbiddenList: [],
  479. instanceId: '',
  480. nodeCode: '',
  481. id: '',
  482. type: '',
  483. approvalHistory: [],
  484. firstCollapsed: ["group1"],
  485. }
  486. },
  487. async onLoad(options) {
  488. // if (options && options?.params) {
  489. let params = {};
  490. if (options?.params) {
  491. params = JSON.parse(decodeURIComponent(options.params));
  492. }
  493. this.businessId = params?.businessId;
  494. this.instanceId = params?.instanceId;
  495. this.id = params?.id;
  496. this.nodeCode = params?.nodeCode;
  497. this.type = params?.type || 'add';
  498. // }
  499. await this.initPageData();
  500. // 如果是kezhang角色,加载部门人员
  501. if (this.isKezhang) {
  502. await this.loadDepartmentUsers();
  503. }
  504. if (this.type == 'add' && !this.isKezhang) {
  505. this.invokerGetLocationsbyTime()
  506. }
  507. this.invokerCategoryInfo()
  508. // 如果有路由ID,获取详情信息
  509. if (this.businessId) {
  510. this.getDetailInfo();
  511. }
  512. },
  513. mounted() {
  514. // this.$nextTick(() => {
  515. // this.isDetailMode = !!this.businessId
  516. // })
  517. },
  518. methods: {
  519. // 处理是否常见违禁品选择变化
  520. onCommonForbiddenChange(e) {
  521. this.formData.commonContraband = e.detail.value
  522. // 如果选择"是",清空违禁品描述
  523. if (e.detail.value === '1') {
  524. this.formData.contrabandDesc = ''
  525. }
  526. },
  527. // 处理驳回确认
  528. // handleRejectConfirm(rejectReason) {
  529. // this.formData.comment = rejectReason
  530. // this.handleApproveReject()
  531. // },
  532. changeCollapse(e) {
  533. this.firstCollapsed = e
  534. },
  535. //审批通过
  536. async handleApprovePass() {
  537. try {
  538. let payload = this.formatData()
  539. uni.showLoading({ title: '审批中...', mask: true });
  540. const res = await approvePass(this.id, { formData: payload, comment: '审批通过' });
  541. if (res.code === 200) {
  542. uni.hideLoading();
  543. uni.showToast({ title: '审批通过', icon: 'success' });
  544. } else {
  545. uni.hideLoading();
  546. uni.showToast({ title: '审批失败', icon: 'none' });
  547. }
  548. setTimeout(() => {
  549. uni.navigateBack()
  550. }, 500)
  551. } catch (err) {
  552. uni.hideLoading();
  553. uni.showToast({ title: '审批失败', icon: 'none' });
  554. console.error('审批失败:', err);
  555. }
  556. },
  557. //审批驳回
  558. async handleApproveReject() {
  559. try {
  560. let payload = this.formatData()
  561. uni.showLoading({ title: '审批中...', mask: true });
  562. const res = await approveReject(this.id, { formData: payload, comment: '审批驳回' });
  563. if (res.code === 200) {
  564. uni.hideLoading();
  565. uni.showToast({ title: '审批驳回', icon: 'success' });
  566. } else {
  567. uni.hideLoading();
  568. uni.showToast({ title: '审批失败', icon: 'none' });
  569. }
  570. setTimeout(() => {
  571. uni.navigateBack()
  572. }, 500)
  573. } catch (err) {
  574. uni.hideLoading();
  575. uni.showToast({ title: '审批失败', icon: 'none' });
  576. console.error('审批失败:', err);
  577. }
  578. },
  579. // 获取详情信息
  580. async getDetailInfo() {
  581. try {
  582. uni.showLoading({ title: '加载详情中...', mask: true });
  583. const res = await getInfo(this.businessId);
  584. let inspectUserInfo = await getUserInfoById(res.data.inspectUserId)
  585. res.data.inspectUserRoleName = inspectUserInfo?.data?.roles[0]?.roleName || ''
  586. if (res.code === 200 && res.data) {
  587. this.fillFormData(res.data);
  588. // 获取审批历史
  589. const historyRes = await getApprovelHistory(this.instanceId);
  590. if (historyRes.code === 200 && historyRes.rows) {
  591. this.approvalHistory = historyRes.rows;
  592. }
  593. uni.hideLoading();
  594. } else {
  595. uni.hideLoading();
  596. uni.showToast({ title: '获取详情失败', icon: 'none' });
  597. }
  598. } catch (err) {
  599. uni.hideLoading();
  600. uni.showToast({ title: '获取详情失败', icon: 'none' });
  601. console.error('获取详情失败:', err);
  602. }
  603. },
  604. // 填充表单数据
  605. fillFormData(detailData) {
  606. if (!detailData) return;
  607. let files = detailData?.itemSeizureItemsList[0].baseAttachmentList && detailData?.itemSeizureItemsList[0].baseAttachmentList.map(file => ({
  608. ...file,
  609. url: file.attachmentUrl || file.url,
  610. }))
  611. // 填充基础信息
  612. this.formData = {
  613. ...this.formData,
  614. ...detailData,
  615. // 处理下拉选择器数据格式 - 组成[{text: '', value: ''}]格式以支持回显
  616. // 处理图片数据
  617. // images: detailData.images ? detailData.images.map(img => ({
  618. // ...img,
  619. // url: img.attachmentUrl || img.url,
  620. // name: img.attachmentName || img.name,
  621. // extname: img.extname
  622. // })) : [],
  623. commonContraband: detailData?.itemSeizureItemsList[0].commonContraband,
  624. contrabandDesc: detailData?.itemSeizureItemsList[0].contrabandDesc,
  625. forbiddenCategory: detailData?.itemSeizureItemsList[0].categoryCodeOne,
  626. forbiddenCategoryText: detailData?.itemSeizureItemsList[0].categoryNameOne,
  627. forbiddenType: detailData?.itemSeizureItemsList[0].categoryCodeTwo,
  628. forbiddenTypeText: detailData?.itemSeizureItemsList[0].categoryNameTwo,
  629. partCategory: detailData?.itemSeizureItemsList[0].checkPositionCodeOne,
  630. partCategoryText: detailData?.itemSeizureItemsList[0].checkPositionNameOne,
  631. partType: detailData?.itemSeizureItemsList[0].checkPositionCodeTwo,
  632. partTypeText: detailData?.itemSeizureItemsList[0].checkPositionNameTwo,
  633. forbiddenName: detailData?.itemSeizureItemsList[0].itemName,
  634. quantity: detailData?.itemSeizureItemsList[0].quantity,
  635. images: files || [],
  636. location: detailData?.itemSeizureItemsList[0].location,
  637. isActiveConcealment: String(detailData?.itemSeizureItemsList[0].isActiveConcealment),
  638. handlingMethodDesc: detailData?.itemSeizureItemsList[0].handlingMethodDesc,
  639. handlingMethod: detailData?.itemSeizureItemsList[0].handlingMethod,
  640. // reportTeamText:`${detailData?.inspectStationName}/${detailData?.inspectBrigadeName}/${detailData?.inspectDepartmentName}/${detailData?.inspectTeamName}`,
  641. securityLocationText: `${detailData?.terminlName}/${detailData?.regionalName}/${detailData?.channelName}`
  642. };
  643. this.$nextTick(() => {
  644. // 处理所有下拉选择器字段的数组格式转换
  645. const dropdownFields = [
  646. { field: 'checkMethod', textField: 'checkMethodText', descField: 'checkMethodDesc' },
  647. { field: 'reportTeam', textField: 'reportTeamText' },
  648. { field: 'unit', textField: 'unitText' },
  649. ]
  650. dropdownFields.forEach(({ field, textField, descField }) => {
  651. if (detailData[field]) {
  652. // 对于checkMethod字段,保持字符串格式(uni-combox需要)
  653. if (field === 'checkMethod') {
  654. this.formData[field] = detailData[field];
  655. this.formData[textField] = detailData[descField] || detailData[textField] || detailData[field];
  656. } else {
  657. // 其他下拉字段保持数组格式
  658. this.formData[field] = [{
  659. value: detailData[field],
  660. text: detailData[descField] || detailData[textField] || detailData[field]
  661. }]
  662. this.formData[textField] = detailData[descField] || detailData[textField] || detailData[field]
  663. }
  664. }
  665. })
  666. // 处理powerOnInstruction字段,确保为字符串类型
  667. if (detailData.powerOnInstruction != null) {
  668. this.formData.powerOnInstruction = String(detailData.powerOnInstruction);
  669. this.formData.powerOnInstructionText = detailData.powerOnInstructionText || (detailData.powerOnInstruction == 1 ? '非指令' : '指令');
  670. } else {
  671. this.formData.powerOnInstruction = '0';
  672. this.formData.powerOnInstructionText = '指令';
  673. }
  674. })
  675. console.log('表单数据已回填:', this.formData);
  676. },
  677. searchLoadData(val) {
  678. return categoryList({ name: val, level: 2 }).then(res => {
  679. return res.data
  680. })
  681. },
  682. invokerGetLocationsbyTime() {
  683. return getLocationsbyTime({
  684. searchtime: formatTime(new Date())
  685. }).then(res => {
  686. const curUserInfo = (res.data || []).find(item => {
  687. return item.userId === this.currentUser.id && (!item.checkOutTime || item.checkOutTime === '2000-01-01 00:00:00')
  688. }) || {}
  689. this.formData.securityLocation = curUserInfo.channelCode || curUserInfo.regionalCode
  690. this.formData.securityLocationText = curUserInfo.channelName || curUserInfo.regionalName
  691. this.formData.team = curUserInfo.attendanceTeamId
  692. this.formData.reportTeam = curUserInfo.attendanceTeamId
  693. if (curUserInfo.attendanceStationName && curUserInfo.attendanceDepartmentName) {
  694. this.formData.teamName = `${curUserInfo.attendanceStationName} / ${curUserInfo.attendanceBrigadeName} / ${curUserInfo.attendanceDepartmentName} / ${curUserInfo.attendanceTeamName}`
  695. this.formData.reportTeamText = `${curUserInfo.attendanceStationName} / ${curUserInfo.attendanceBrigadeName} / ${curUserInfo.attendanceDepartmentName} / ${curUserInfo.attendanceTeamName}`
  696. }
  697. console.log(this.formData);
  698. const locationResult = this.getParentLocation(this.formData.securityLocation)
  699. console.log(locationResult);
  700. // 安全地处理可能为null的结果
  701. if (locationResult) {
  702. this.formData.terminlName = locationResult.grandParent?.text || '';
  703. this.formData.terminlCode = locationResult.grandParent?.value || '';
  704. this.formData.regionalName = locationResult.parent?.text || '';
  705. this.formData.regionalCode = locationResult.parent?.value || '';
  706. this.formData.channelName = locationResult.current?.text || '';
  707. this.formData.channelCode = locationResult.current?.value || '';
  708. } else {
  709. // 如果找不到位置信息,清空相关字段
  710. this.formData.terminlName = '';
  711. this.formData.terminlCode = '';
  712. this.formData.regionalName = '';
  713. this.formData.regionalCode = '';
  714. this.formData.channelName = '';
  715. this.formData.channelCode = '';
  716. }
  717. })
  718. },
  719. //根据securityLocation,从this.position_options中向上找到前两级别的父级对象和当前级别对象
  720. getParentLocation(securityLocation) {
  721. if (!securityLocation || !this.position_options || !this.position_options.length) {
  722. return null;
  723. }
  724. // 递归查找节点及其父级
  725. const findNodeAndParents = (nodes, targetValue, parents = []) => {
  726. for (const node of nodes) {
  727. if (node.value === targetValue) {
  728. return { node, parents };
  729. }
  730. if (node.children && node.children.length) {
  731. const result = findNodeAndParents(node.children, targetValue, [...parents, node]);
  732. if (result) {
  733. return result;
  734. }
  735. }
  736. }
  737. return null;
  738. };
  739. const result = findNodeAndParents(this.position_options, securityLocation);
  740. if (!result) {
  741. return null;
  742. }
  743. const { node, parents } = result;
  744. // 返回当前级别对象和前两级的父级对象(如果存在)
  745. if (parents.length >= 2) {
  746. return {
  747. current: node, // 当前级别对象
  748. grandParent: parents[parents.length - 2], // 祖父级
  749. parent: parents[parents.length - 1] // 父级
  750. };
  751. } else if (parents.length === 1) {
  752. return {
  753. current: node, // 当前级别对象
  754. grandParent: null, // 没有祖父级
  755. parent: parents[0] // 只有父级
  756. };
  757. } else {
  758. return {
  759. current: node, // 当前级别对象
  760. grandParent: null, // 没有祖父级
  761. parent: null // 没有父级
  762. };
  763. }
  764. },
  765. invokerCategoryInfo() {
  766. categoryInfo(1).then(res => {
  767. this.commonlyList.forbidden = res.data || []
  768. })
  769. categoryInfo(2).then(res => {
  770. this.commonlyList.part = res.data || []
  771. })
  772. },
  773. async initPageData() {
  774. try {
  775. uni.showLoading({ title: '加载中...', mask: true });
  776. // 查询基础数据
  777. // 位置 航站楼 区域 通道 locationData 树结构 POSITION
  778. // 物品类型 categoryData 树结构 ITEM_CATEGORY
  779. // 身体部位类型 partCategoryData 树结构 CHECK_POINT
  780. const deptTree = await getDeptList();
  781. this.teams = this.buildTeamOptions(deptTree.data || []);
  782. const [positionRes, itemCategoryRes, checkPointRes] = await Promise.all([
  783. treeSelectByType("POSITION", 3),
  784. treeSelectByType("ITEM_CATEGORY", 3),
  785. treeSelectByType("CHECK_POINT", 3)
  786. ]);
  787. // 初始化岗位选项数据
  788. await this.initPositionAndOptions();
  789. const convertTree = (list = []) =>
  790. list.map(node => ({
  791. text: node.label,
  792. value: node.code,
  793. children: node.children ? convertTree(node.children) : null
  794. }))
  795. this.position_options = convertTree(positionRes.data || []);
  796. this.item_category_options = itemCategoryRes.data || [];
  797. this.forbiddenList = itemCategoryRes.data || [];
  798. this.check_point_options = checkPointRes.data || [];
  799. // 处理方式 item_handling_method_options 字典 item_handling_method
  800. // 单位 units 字典 item_unit
  801. const dict = await this.useDict(
  802. 'item_handling_method',
  803. 'item_unit'
  804. )
  805. this.item_handling_method_options = dict.item_handling_method || [];
  806. // console.log(this.item_handling_method_options,"this.item_handling_method_options")
  807. this.item_unit_options = dict.item_unit || [];
  808. uni.hideLoading();
  809. } catch (err) {
  810. uni.hideLoading();
  811. uni.showToast({ title: '加载失败', icon: 'none' });
  812. console.error('初始化数据失败:', err);
  813. }
  814. },
  815. buildTeamOptions(tree = []) {
  816. const result = [];
  817. function dfs(node, path = []) {
  818. const currentPath = [...path, node.label];
  819. // 如果是 TEAMS 叶子节点
  820. if (node.deptType === 'TEAMS') {
  821. result.push({
  822. text: currentPath.join(' / '),
  823. value: node.id
  824. });
  825. }
  826. // 继续递归子节点
  827. if (node.children && Array.isArray(node.children)) {
  828. node.children.forEach(child => dfs(child, currentPath));
  829. }
  830. }
  831. tree.forEach(root => dfs(root));
  832. return result;
  833. },
  834. // 初始化岗位和选项数据
  835. async initPositionAndOptions() {
  836. try {
  837. // 使用当前选择的inspectUserId查询岗位列表
  838. const userId = this.formData.inspectUserId || this.currentUser.id;
  839. const postListsRes = await getPostListsByUserId(userId);
  840. // 更新岗位选项
  841. this.item_check_method_options = postListsRes.data || [];
  842. console.log("岗位和选项数据已更新,用户ID:", userId);
  843. } catch (error) {
  844. console.error("初始化岗位和选项数据失败:", error);
  845. }
  846. },
  847. // 加载部门人员(kezhang角色使用)
  848. async loadDepartmentUsers() {
  849. if (!this.isKezhang) return;
  850. try {
  851. const currentUserInfo = this.userInfo || {};
  852. const currentUserDeptId = currentUserInfo.departmentId || currentUserInfo.deptId;
  853. if (!currentUserDeptId) {
  854. console.warn('无法获取当前用户的部门ID');
  855. return;
  856. }
  857. const response = await getUserList({
  858. deptId: currentUserDeptId,
  859. status: '0',
  860. pageSize: 1000
  861. });
  862. if (response && response.code === 200) {
  863. this.departmentUserOptions = (response.rows || []).map(user => ({
  864. ...user,
  865. value: user.userId,
  866. text: user.nickName || user.userName,
  867. }));
  868. }
  869. } catch (error) {
  870. console.error('获取部门人员失败:', error);
  871. uni.showToast({
  872. title: '获取部门人员失败',
  873. icon: 'none',
  874. duration: 2000
  875. });
  876. }
  877. },
  878. // 选择文件后手动上传
  879. async onSelect(event) {
  880. // 由于限制只能上传1个文件,直接取第一个文件进行上传
  881. const files = await this.uploadFile(event);
  882. console.log("上传成功====", files);
  883. let fileArr = files.map(file => ({
  884. url: file.url,
  885. name: file.newFileName,
  886. attachmentName: file.newFileName,
  887. attachmentUrl: file.url,
  888. extname: file.newFileName.split('.').pop()
  889. }))
  890. // 直接替换而不是追加,因为限制只能上传1张
  891. this.formData.images = [
  892. ...this.formData.images,
  893. ...fileArr
  894. ];
  895. },
  896. // 封装上传
  897. uploadFile(event) {
  898. return Promise.all(event.tempFilePaths.map(filePath => {
  899. return new Promise((resolve, reject) => {
  900. uni.uploadFile({
  901. url: `${config.baseUrl}/common/upload`,
  902. filePath: filePath,
  903. name: 'file',
  904. header: { Authorization: 'Bearer ' + getToken() },
  905. formData: {
  906. // 可添加其他参数
  907. },
  908. success: (res) => resolve(JSON.parse(res.data)),
  909. fail: reject
  910. });
  911. });
  912. }));
  913. },
  914. formatDateTime(date) {
  915. const y = date.getFullYear();
  916. const m = String(date.getMonth() + 1).padStart(2, '0');
  917. const d = String(date.getDate()).padStart(2, '0');
  918. const h = String(date.getHours()).padStart(2, '0');
  919. const mm = String(date.getMinutes()).padStart(2, '0');
  920. const s = String(date.getSeconds()).padStart(2, '0');
  921. return `${y}-${m}-${d} ${h}:${mm}:${s}`;
  922. },
  923. // 安检位置变化
  924. onLocationChange(e) {
  925. const arr = e.detail.value || [];
  926. this.formData.securityLocation = arr[arr.length - 1]?.value || '';
  927. this.formData.securityLocationText = arr.map(item => item.text).join('/');
  928. const locationResult = this.getParentLocation(this.formData.securityLocation)
  929. console.log(locationResult);
  930. // 安全地处理可能为null的结果
  931. if (locationResult) {
  932. this.formData.terminlName = locationResult.grandParent?.text || '';
  933. this.formData.terminlCode = locationResult.grandParent?.value || '';
  934. this.formData.regionalName = locationResult.parent?.text || '';
  935. this.formData.regionalCode = locationResult.parent?.value || '';
  936. this.formData.channelName = locationResult.current?.text || '';
  937. this.formData.channelCode = locationResult.current?.value || '';
  938. } else {
  939. // 如果找不到位置信息,清空相关字段
  940. this.formData.terminlName = '';
  941. this.formData.terminlCode = '';
  942. this.formData.regionalName = '';
  943. this.formData.regionalCode = '';
  944. this.formData.channelName = '';
  945. this.formData.channelCode = '';
  946. }
  947. },
  948. // 通用取值:只拿最后一级
  949. lastValue(e) {
  950. const val = e.detail.value;
  951. if (Array.isArray(val)) return val[val.length - 1] || '';
  952. if (val && typeof val === 'object') return val.value || '';
  953. return String(val || '');
  954. },
  955. // 安检岗位 - combox版本
  956. onCheckMethodComboxChange(text) {
  957. // 根据选中的文本找到对应的原始对象
  958. const selectedItem = this.item_check_method_options.find(item =>
  959. item.postName === text || item.label === text || item.text === text || item.value === text
  960. );
  961. if (!selectedItem) {
  962. this.formData.checkMethod = '';
  963. this.formData.checkMethodText = '';
  964. return
  965. }
  966. // 如果切换了岗位,重置开机指令相关字段
  967. if (this.formData.checkMethodText !== text) {
  968. this.formData.powerOnInstruction = '';
  969. this.formData.powerOnInstructionText = '';
  970. this.formData.xrayOperatorId = '';
  971. this.formData.xrayOperatorName = '';
  972. }
  973. this.formData.checkMethod = selectedItem?.postCode || text;
  974. this.formData.checkMethodText = selectedItem?.postName || selectedItem?.label || selectedItem?.text || text;
  975. // 如果是开箱(包)检查岗位,加载X光开机员列表
  976. if (text === '开箱(包)检查岗位') {
  977. this.loadXrayOperators();
  978. }
  979. },
  980. // 开机指令变化
  981. onpowerOnInstructionChange(e) {
  982. const selectedValue = e.detail.value;
  983. this.formData.powerOnInstruction = selectedValue;
  984. this.formData.powerOnInstructionText = selectedValue === '1' ? '非指令' : '指令';
  985. this.formData.xrayOperatorId = '';
  986. this.formData.xrayOperatorName = '';
  987. // 如果选择了指令,清空X光开机员
  988. if (this.formData.powerOnInstruction === '0') {
  989. this.loadXrayOperators();
  990. }
  991. },
  992. // 加载X光开机员列表
  993. async loadXrayOperators() {
  994. try {
  995. // 使用现有的用户列表接口,可以根据需要调整参数
  996. const { listAllUser } = await import('@/api/system/user.js');
  997. const res = await listAllUser();
  998. if (res && res.data) {
  999. this.xrayOperatorOptions = res.data.map(item => ({
  1000. ...item,
  1001. nickName: `${item.nickName}(${item.userName})`,
  1002. })) || [];
  1003. }
  1004. } catch (error) {
  1005. console.error('加载X光开机员列表失败:', error);
  1006. }
  1007. },
  1008. // X光开机员选择
  1009. handleXrayOperatorSelect(value) {
  1010. const selectedUser = this.xrayOperatorOptions.find(user => user.userId === value);
  1011. if (selectedUser) {
  1012. this.formData.xrayOperatorId = selectedUser.userId;
  1013. this.formData.xrayOperatorName = selectedUser.nickName;
  1014. }
  1015. },
  1016. // 安检岗位 - 原data-picker版本(已弃用)
  1017. onItemCheckMethodChange(e) {
  1018. this.formData.checkMethod = e.detail.value[0]?.value || '';
  1019. this.formData.checkMethodText = e.detail.value[0]?.text || e.detail.value[0]?.text || '';
  1020. },
  1021. // 查获班组变化
  1022. onTeamChange(e) {
  1023. this.formData.team = e.detail.value[0].value;
  1024. this.formData.teamName = e.detail.value[1]?.text || e.detail.value[0]?.text || '';
  1025. },
  1026. // 上报班组变化
  1027. onReportTeamChange(e) {
  1028. console.log("e.detail.value", e.detail.value)
  1029. this.formData.reportTeam = e.detail.value[0].value;
  1030. this.formData.reportTeamText = e.detail.value[1]?.text || e.detail.value[0]?.text || '';
  1031. },
  1032. // 快捷选中违禁品
  1033. selectCategory(item) {
  1034. const createEventInfo = {
  1035. detail: {
  1036. value: [
  1037. { value: item.parentId, text: item.parentName },
  1038. { value: item.categoryId, text: item.categoryName },
  1039. ]
  1040. }
  1041. }
  1042. this.onCategoryChange(createEventInfo)
  1043. },
  1044. // 搜索违禁品 选中
  1045. searchSelectChange(selectItem) {
  1046. const curParent = this.item_category_options.find(item => item.id === selectItem.parentId)
  1047. const createEventInfo = {
  1048. detail: {
  1049. value: [
  1050. { value: selectItem.parentId, text: selectItem.parentName || curParent?.label },
  1051. { value: selectItem.id, text: selectItem.name },
  1052. ]
  1053. }
  1054. }
  1055. this.onCategoryChange(createEventInfo)
  1056. },
  1057. // 违禁品类别变化
  1058. onCategoryChange(e) {
  1059. if (!e.detail.value || !e.detail.value.length) {
  1060. this.formData.forbiddenCategory = ''
  1061. this.formData.forbiddenCategoryText = ''
  1062. this.formData.forbiddenType = ''
  1063. this.formData.forbiddenTypeText = ''
  1064. return
  1065. }
  1066. this.formData.forbiddenCategory = e.detail.value[0].value;
  1067. this.formData.forbiddenCategoryText = e.detail.value[0].text;
  1068. this.formData.forbiddenType = e.detail.value[1].value;
  1069. this.formData.forbiddenTypeText = e.detail.value[1].text;
  1070. },
  1071. // 单位变化
  1072. onUnitChange(e) {
  1073. this.formData.unit = e.detail.value;
  1074. this.formData.unitText =
  1075. this.item_unit_options.find(item => item.value === e.detail.value)?.label || '件';
  1076. },
  1077. // 快捷选中违禁品
  1078. selectPart(item) {
  1079. const createEventInfo = {
  1080. detail: {
  1081. value: [
  1082. { value: item.parentId, text: item.parentName },
  1083. { value: item.categoryId, text: item.categoryName },
  1084. ]
  1085. }
  1086. }
  1087. this.onPartCategoryChange(createEventInfo)
  1088. },
  1089. // 部位类别变化
  1090. onPartCategoryChange(e) {
  1091. if (!e.detail.value || !e.detail.value.length) {
  1092. this.formData.partCategory = ''
  1093. this.formData.partCategoryText = ''
  1094. this.formData.partType = ''
  1095. this.formData.partTypeText = ''
  1096. return
  1097. }
  1098. this.formData.partCategory = e.detail.value[0].value;
  1099. this.formData.partCategoryText = e.detail.value[0].text;
  1100. this.formData.partType = e.detail.value[1].value;
  1101. this.formData.partTypeText = e.detail.value[1].text;
  1102. },
  1103. // 安检员选择变化(kezhang角色使用)
  1104. async onInspectUserChange(e) {
  1105. console.log("查获人员选择变化", e.detail.value)
  1106. const arr = e.detail.value || [];
  1107. this.formData.inspectUserId = arr[arr.length - 1]?.value || '';
  1108. this.formData.inspectUserName = arr.map(item => item.text).join('/');
  1109. this.formData.reportTeam = this.departmentUserOptions.find(item => item.userId === this.formData.inspectUserId)?.deptId;
  1110. this.formData.reportTeamText = this.teams.find(item => item.value === this.formData.reportTeam)?.text;
  1111. // 切换查获人员后,重新初始化岗位和选项数据
  1112. if (this.formData.inspectUserId) {
  1113. await this.initPositionAndOptions();
  1114. }
  1115. },
  1116. // 部位类型变化
  1117. onPartTypeChange(e) {
  1118. this.formData.partType = e.detail.value[0].value;
  1119. this.formData.partTypeText = e.detail.value[0].text;
  1120. },
  1121. // 具体位置选择
  1122. onLocationSelectChange(e) {
  1123. this.formData.location = e.detail.value;
  1124. this.formData.locationText = this.locations.find(item => item.value === e.detail.value)?.text || '';
  1125. this.formData.customLocation = this.formData.locationText;
  1126. },
  1127. // 处理方式变化
  1128. onMethodChange(e) {
  1129. this.formData.handlingMethod = e.detail.value[0].value;
  1130. this.formData.handlingMethodDesc = e.detail.value[0].text;
  1131. },
  1132. // 是否有意隐匿选择
  1133. bindConcealChange(e) {
  1134. if (this.isDetailMode) {
  1135. return; // 详情模式下不处理change事件
  1136. }
  1137. this.formData.isActiveConcealment = e.detail.value;
  1138. },
  1139. generateNumericID() {
  1140. // 使用更安全的ID生成方式,避免重复
  1141. const timestamp = Date.now();
  1142. const random = Math.floor(Math.random() * 1e9); // 9位随机数
  1143. return parseInt(`${timestamp}${random}`.slice(-15)); // 确保总长度不超过15位
  1144. },
  1145. formatData() {
  1146. // this.formData.regionalCode = this.formData.securityLocation
  1147. // this.formData.regionalName = this.formData.securityLocationText
  1148. this.formData.channelCode =
  1149. this.formData.channelCode || this.formData.securityLocation || '无'
  1150. this.formData.channelName =
  1151. this.formData.channelName || this.formData.securityLocationText || '无'
  1152. this.formData.inspectTeamId = this.formData.team
  1153. this.formData.inspectTeamName = this.formData.teamName
  1154. this.formData.attendanceTeamId = this.formData.reportTeam
  1155. this.formData.attendanceTeamName = this.formData.reportTeamText
  1156. this.formData.passengerCard = this.formData.passengerId
  1157. this.formData.passengerFlight = this.formData.flightNumber
  1158. this.formData.checkMethodDesc = this.formData.checkMethodText
  1159. // if (this.formData.isActiveConcealment === 'yes') {
  1160. // this.formData.isActiveConcealment = 1
  1161. // } else {
  1162. // this.formData.isActiveConcealment = 0
  1163. // }
  1164. const item = {
  1165. // 违禁品信息
  1166. forbiddenType: this.formData.forbiddenType,
  1167. forbiddenTypeText: this.formData.forbiddenTypeText,
  1168. itemName: this.formData.forbiddenName,
  1169. quantity: this.formData.quantity,
  1170. unit: this.formData.unit[0]?.value || '',
  1171. unitDesc: this.formData.unitText,
  1172. checkPositionCodeOne: this.formData.partCategory,
  1173. checkPositionNameOne: this.formData.partCategoryText,
  1174. checkPositionCodeTwo: this.formData.partType,
  1175. checkPositionNameTwo: this.formData.partTypeText,
  1176. checkPositionSpecific: this.formData.customLocation,
  1177. //附件
  1178. baseAttachmentList: this.formData.images,
  1179. //暂时不要
  1180. itemCode: '无',
  1181. commonContraband: Number(this.formData.commonContraband),
  1182. contrabandDesc: this.formData.contrabandDesc,
  1183. isActiveConcealment: this.formData.isActiveConcealment,
  1184. categoryCodeOne: this.formData.forbiddenCategory,
  1185. categoryNameOne: this.formData.forbiddenCategoryText,
  1186. categoryCodeTwo: this.formData.forbiddenType,
  1187. categoryNameTwo: this.formData.forbiddenTypeText,
  1188. handlingMethod: this.formData.handlingMethod,
  1189. handlingMethodDesc: this.formData.handlingMethodDesc,
  1190. location: this.formData.location,
  1191. id: this.generateNumericID(),
  1192. }
  1193. const payload = {
  1194. ...this.formData,
  1195. itemSeizureItemsList: [item],
  1196. };
  1197. return payload
  1198. },
  1199. // 提交表单
  1200. submitForm() {
  1201. this.$refs.form.validate().then(res => {
  1202. uni.showLoading({ title: '提交中...', mask: true });
  1203. let payload = this.formatData()
  1204. payload.inspectUserName = this.userInfo.nickName
  1205. let params = {
  1206. businessType: 'SEIZURE_REPORT',
  1207. title: '查获物品上报审批流程',
  1208. formData: payload,
  1209. submitterId: this.currentUser.id,
  1210. submitterName: this.currentUser.name,
  1211. submitterRole: 'SEIZURE_REPORT_DEFAULT',
  1212. }
  1213. addSeizureRecord(payload)
  1214. .then((res) => {
  1215. uni.showToast({ title: '提交成功', icon: 'success' });
  1216. //开始流程
  1217. console.log("res0", res)
  1218. approvalStart({ ...params, businessId: res.data }).then(res => {
  1219. setTimeout(() => uni.navigateBack(), 1500); // 提交成功后跳转
  1220. })
  1221. })
  1222. .catch((error) => {
  1223. uni.showToast({ title: '操作失败,请稍后重试!', icon: 'none' }); // 提交失败提示
  1224. console.error('提交失败:', error);
  1225. });
  1226. }).catch(err => {
  1227. console.log('表单验证失败:', err);
  1228. });
  1229. }
  1230. }
  1231. }
  1232. </script>
  1233. <style lang="scss" scoped>
  1234. .report-container {
  1235. // background-color: #f5f5f5;
  1236. min-height: 100vh;
  1237. padding-top: 35px;
  1238. .button-group {
  1239. display: flex;
  1240. justify-content: space-between;
  1241. padding: 15px;
  1242. }
  1243. .collapse-card {
  1244. border-radius: 12px;
  1245. margin: 15px 0;
  1246. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1247. ::v-deep .uni-collapse-item__wrap {
  1248. overflow: visible !important;
  1249. border-radius: 12px;
  1250. }
  1251. }
  1252. .collapse-card-hidden {
  1253. border-radius: 12px;
  1254. margin: 15px 0;
  1255. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1256. ::v-deep .uni-collapse-item__wrap {
  1257. overflow: hidden !important;
  1258. border-radius: 12px;
  1259. }
  1260. }
  1261. .card {
  1262. border-radius: 12px;
  1263. overflow: hidden;
  1264. margin: 15px 0;
  1265. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1266. .gridWrap {
  1267. display: flex;
  1268. column-gap: 8px;
  1269. row-gap: 8px;
  1270. flex-wrap: wrap;
  1271. }
  1272. ::v-deep .collapse {
  1273. border-radius: 16px;
  1274. }
  1275. }
  1276. .userInfo {
  1277. display: flex;
  1278. flex-direction: column;
  1279. row-gap: 10px;
  1280. .userName {
  1281. font-size: 18px;
  1282. font-weight: 500;
  1283. }
  1284. .teamInfo {
  1285. display: flex;
  1286. column-gap: 10px;
  1287. font-size: 14px;
  1288. color: #666;
  1289. .team {
  1290. display: flex;
  1291. }
  1292. }
  1293. }
  1294. }
  1295. .form-scroll {
  1296. height: calc(100vh - 50px);
  1297. padding: 1px;
  1298. box-sizing: border-box;
  1299. }
  1300. /* 折叠面板标题 */
  1301. .collapse-title {
  1302. display: flex;
  1303. flex-direction: column;
  1304. padding: 12px 15px;
  1305. .collapse-summary {
  1306. font-size: 12px;
  1307. color: #999;
  1308. margin-top: 4px;
  1309. }
  1310. }
  1311. /* 表单项样式 */
  1312. ::v-deep .uni-forms-item {
  1313. margin-bottom: 0;
  1314. padding: 0 15px;
  1315. .uni-forms-item__label {
  1316. padding: 12px 0 8px;
  1317. font-size: 14px;
  1318. color: #666;
  1319. width: auto !important;
  1320. }
  1321. .uni-forms-item__content {
  1322. padding: 0 0 12px;
  1323. border-bottom: 1px solid #f0f0f0;
  1324. }
  1325. &:last-child .uni-forms-item__content {
  1326. border-bottom: none;
  1327. }
  1328. }
  1329. .picker-box {
  1330. display: flex;
  1331. align-items: center;
  1332. justify-content: space-between;
  1333. height: 44px;
  1334. .picker-value {
  1335. font-size: 15px;
  1336. color: #333;
  1337. &:empty::after {
  1338. content: attr(placeholder);
  1339. color: #999;
  1340. }
  1341. }
  1342. &.disabled {
  1343. opacity: 0.5;
  1344. }
  1345. }
  1346. .form-value {
  1347. font-size: 15px;
  1348. color: #333;
  1349. height: 44px;
  1350. line-height: 44px;
  1351. }
  1352. .number-input {
  1353. display: flex;
  1354. align-items: center;
  1355. height: 44px;
  1356. .input-number {
  1357. flex: 1;
  1358. }
  1359. .unit-picker {
  1360. width: 80px;
  1361. margin-left: 10px;
  1362. }
  1363. }
  1364. .location-input {
  1365. display: flex;
  1366. height: 44px;
  1367. .picker-box {
  1368. width: 120px;
  1369. }
  1370. .custom-location {
  1371. flex: 1;
  1372. margin-left: 0px;
  1373. }
  1374. }
  1375. // .radio-group {
  1376. // display: flex;
  1377. // padding: 8px 0;
  1378. // .radio-item {
  1379. // display: flex;
  1380. // align-items: center;
  1381. // margin-right: 30px;
  1382. // text {
  1383. // font-size: 15px;
  1384. // color: #333;
  1385. // margin-left: 5px;
  1386. // }
  1387. // }
  1388. // &.disabled-group {
  1389. // opacity: 0.5;
  1390. // pointer-events: none;
  1391. // }
  1392. // }
  1393. .submit-btn {
  1394. margin-top: 20px;
  1395. width: calc(100% - 30px);
  1396. margin-left: 15px;
  1397. }
  1398. /* 底部弹窗样式调整 */
  1399. ::v-deep .uni-popup__wrapper {
  1400. border-radius: 16px;
  1401. .uni-popup__wrapper-box {
  1402. max-height: 70vh;
  1403. overflow-y: auto;
  1404. }
  1405. .uni-data-pickerview {
  1406. padding-bottom: 20px;
  1407. }
  1408. }
  1409. </style>