index.vue 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599
  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('kezhang')
  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.attendanceDepartmentName} / ${curUserInfo.attendanceTeamName}`
  695. this.formData.reportTeamText = `${curUserInfo.attendanceStationName} / ${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. let params = {
  1205. businessType: 'SEIZURE_REPORT',
  1206. title: '查获物品上报审批流程',
  1207. formData: payload,
  1208. submitterId: this.currentUser.id,
  1209. submitterName: this.currentUser.name,
  1210. submitterRole: 'SEIZURE_REPORT_DEFAULT',
  1211. }
  1212. addSeizureRecord(payload)
  1213. .then((res) => {
  1214. uni.showToast({ title: '提交成功', icon: 'success' });
  1215. //开始流程
  1216. console.log("res0", res)
  1217. approvalStart({ ...params, businessId: res.data }).then(res => {
  1218. setTimeout(() => uni.navigateBack(), 1500); // 提交成功后跳转
  1219. })
  1220. })
  1221. .catch((error) => {
  1222. uni.showToast({ title: '操作失败,请稍后重试!', icon: 'none' }); // 提交失败提示
  1223. console.error('提交失败:', error);
  1224. });
  1225. }).catch(err => {
  1226. console.log('表单验证失败:', err);
  1227. });
  1228. }
  1229. }
  1230. }
  1231. </script>
  1232. <style lang="scss" scoped>
  1233. .report-container {
  1234. // background-color: #f5f5f5;
  1235. min-height: 100vh;
  1236. padding-top: 35px;
  1237. .button-group {
  1238. display: flex;
  1239. justify-content: space-between;
  1240. padding: 15px;
  1241. }
  1242. .collapse-card {
  1243. border-radius: 12px;
  1244. margin: 15px 0;
  1245. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1246. ::v-deep .uni-collapse-item__wrap {
  1247. overflow: visible !important;
  1248. border-radius: 12px;
  1249. }
  1250. }
  1251. .collapse-card-hidden {
  1252. border-radius: 12px;
  1253. margin: 15px 0;
  1254. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1255. ::v-deep .uni-collapse-item__wrap {
  1256. overflow: hidden !important;
  1257. border-radius: 12px;
  1258. }
  1259. }
  1260. .card {
  1261. border-radius: 12px;
  1262. overflow: hidden;
  1263. margin: 15px 0;
  1264. box-shadow: rgba(0, 0, 0, 0.08) 0px 0px 3px 1px;
  1265. .gridWrap {
  1266. display: flex;
  1267. column-gap: 8px;
  1268. row-gap: 8px;
  1269. flex-wrap: wrap;
  1270. }
  1271. ::v-deep .collapse {
  1272. border-radius: 16px;
  1273. }
  1274. }
  1275. .userInfo {
  1276. display: flex;
  1277. flex-direction: column;
  1278. row-gap: 10px;
  1279. .userName {
  1280. font-size: 18px;
  1281. font-weight: 500;
  1282. }
  1283. .teamInfo {
  1284. display: flex;
  1285. column-gap: 10px;
  1286. font-size: 14px;
  1287. color: #666;
  1288. .team {
  1289. display: flex;
  1290. }
  1291. }
  1292. }
  1293. }
  1294. .form-scroll {
  1295. height: calc(100vh - 50px);
  1296. padding: 1px;
  1297. box-sizing: border-box;
  1298. }
  1299. /* 折叠面板标题 */
  1300. .collapse-title {
  1301. display: flex;
  1302. flex-direction: column;
  1303. padding: 12px 15px;
  1304. .collapse-summary {
  1305. font-size: 12px;
  1306. color: #999;
  1307. margin-top: 4px;
  1308. }
  1309. }
  1310. /* 表单项样式 */
  1311. ::v-deep .uni-forms-item {
  1312. margin-bottom: 0;
  1313. padding: 0 15px;
  1314. .uni-forms-item__label {
  1315. padding: 12px 0 8px;
  1316. font-size: 14px;
  1317. color: #666;
  1318. width: auto !important;
  1319. }
  1320. .uni-forms-item__content {
  1321. padding: 0 0 12px;
  1322. border-bottom: 1px solid #f0f0f0;
  1323. }
  1324. &:last-child .uni-forms-item__content {
  1325. border-bottom: none;
  1326. }
  1327. }
  1328. .picker-box {
  1329. display: flex;
  1330. align-items: center;
  1331. justify-content: space-between;
  1332. height: 44px;
  1333. .picker-value {
  1334. font-size: 15px;
  1335. color: #333;
  1336. &:empty::after {
  1337. content: attr(placeholder);
  1338. color: #999;
  1339. }
  1340. }
  1341. &.disabled {
  1342. opacity: 0.5;
  1343. }
  1344. }
  1345. .form-value {
  1346. font-size: 15px;
  1347. color: #333;
  1348. height: 44px;
  1349. line-height: 44px;
  1350. }
  1351. .number-input {
  1352. display: flex;
  1353. align-items: center;
  1354. height: 44px;
  1355. .input-number {
  1356. flex: 1;
  1357. }
  1358. .unit-picker {
  1359. width: 80px;
  1360. margin-left: 10px;
  1361. }
  1362. }
  1363. .location-input {
  1364. display: flex;
  1365. height: 44px;
  1366. .picker-box {
  1367. width: 120px;
  1368. }
  1369. .custom-location {
  1370. flex: 1;
  1371. margin-left: 0px;
  1372. }
  1373. }
  1374. // .radio-group {
  1375. // display: flex;
  1376. // padding: 8px 0;
  1377. // .radio-item {
  1378. // display: flex;
  1379. // align-items: center;
  1380. // margin-right: 30px;
  1381. // text {
  1382. // font-size: 15px;
  1383. // color: #333;
  1384. // margin-left: 5px;
  1385. // }
  1386. // }
  1387. // &.disabled-group {
  1388. // opacity: 0.5;
  1389. // pointer-events: none;
  1390. // }
  1391. // }
  1392. .submit-btn {
  1393. margin-top: 20px;
  1394. width: calc(100% - 30px);
  1395. margin-left: 15px;
  1396. }
  1397. /* 底部弹窗样式调整 */
  1398. ::v-deep .uni-popup__wrapper {
  1399. border-radius: 16px;
  1400. .uni-popup__wrapper-box {
  1401. max-height: 70vh;
  1402. overflow-y: auto;
  1403. }
  1404. .uni-data-pickerview {
  1405. padding-bottom: 20px;
  1406. }
  1407. }
  1408. </style>