selectLab.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. <!-- 选择实验室 -->
  2. <template>
  3. <view id="gasCylinderSelectLab">
  4. <view class="top-input-max-box">
  5. <view class="input-box">
  6. <uni-icons type="search" class="icon-box" color="#7C7C7C" size="25"></uni-icons>
  7. <input class="uni-input input-min" confirm-type="search" @confirm="getList()" v-model="inputData" maxlength="20"
  8. placeholder="搜索实验室" />
  9. <view class="button-p" @click="resetButton()">重置</view>
  10. </view>
  11. <view class="picker-box">
  12. <picker @change="bindPickerChangeA" :value="indexA" :range="arrayA">
  13. <view class="picker-min-box">
  14. <view>{{indexA==null?'学院':arrayA[indexA]}}</view>
  15. <uni-icons type="down" class="icon-box" size="15"></uni-icons>
  16. </view>
  17. </picker>
  18. <picker mode="multiSelector" @change="bindPickerChangeB" @columnchange="bindColumnChangeB" :value="multiIndexB"
  19. :range="multiArrayB" range-key="name"> <!-- ⚠️ 请替换为你接口中实际用于展示的字段名 -->
  20. <view class="picker-min-box">
  21. <!-- 展示当前选中的 校区-楼栋-楼层 -->
  22. <view v-if="multiIndexB[0]==null && multiIndexB[1]==null && multiIndexB[2]==null">请选择楼层</view>
  23. <!-- <view v-else>
  24. {{ multiArrayB[0][multiIndexB[0]].name }} -
  25. {{ multiArrayB[1][multiIndexB[1]].name }} -
  26. {{ multiArrayB[2][multiIndexB[2]].name }}
  27. </view> -->
  28. <view v-else>
  29. {{ multiArrayB[2][multiIndexB[2]].name }}
  30. </view>
  31. <uni-icons type="down" class="icon-box" size="15"></uni-icons>
  32. </view>
  33. </picker>
  34. <!-- <picker @change="bindPickerChangeB" :value="indexB" :range="arrayB" mode="multiSelector"
  35. range-key="buildFloorVoList">
  36. <view class="picker-min-box">
  37. <view>{{indexB==null?'楼栋':arrayB[indexB]}}</view>
  38. <uni-icons type="down" class="icon-box" size="15"></uni-icons>
  39. </view>
  40. </picker> -->
  41. <!-- <picker @change="bindPickerChangeC" :value="indexC" :range="arrayC">
  42. <view class="picker-min-box">
  43. <view>{{indexC==null?'楼层':arrayC[indexC]}}</view>
  44. <uni-icons type="down" class="icon-box" size="15"></uni-icons>
  45. </view>
  46. </picker> -->
  47. </view>
  48. </view>
  49. <scroll-view scroll-y @scrolltolower="scrollGet" class="content-box">
  50. <view class="null-p" v-if="!dataList[0]">暂无数据</view>
  51. <view class="for-max-big-box" @click="checkButton(item)" v-for="(item,index) in dataList" :key="index">
  52. <view class="for-title-box">
  53. <view>实验室名称:</view>
  54. <view>{{item.subName}}</view>
  55. </view>
  56. <view class="for-text-box">
  57. <view>楼栋:</view>
  58. <view>{{item.buildName}}</view>
  59. </view>
  60. <view class="for-text-box">
  61. <view>楼层:</view>
  62. <view>{{item.floorName}}</view>
  63. </view>
  64. <view class="for-text-box">
  65. <view>房间号:</view>
  66. <view>{{item.roomNum}}</view>
  67. </view>
  68. </view>
  69. </scroll-view>
  70. <uni-icons class="sao-code-box" type="scan" color="#fff" size="25" @click="saoCode()"></uni-icons>
  71. </view>
  72. </template>
  73. <script>
  74. import {
  75. getDeptDropList,
  76. systemBuildingGetTreeList,
  77. airbottleNewQpAppletBottleSubjectsPage,
  78. airBottleNewQpAppletBottleSubjectsInfo,
  79. } from '@/pages_supplierCylinderManagement/api/index.js'
  80. export default {
  81. data() {
  82. return {
  83. fromPage: '',
  84. inputData: '',
  85. listA: [],
  86. arrayA: [],
  87. indexA: null,
  88. // 三维数组:[ [所有校区], [当前选中校区下的楼栋], [当前选中楼栋下的楼层] ]
  89. multiArrayB: [
  90. [],
  91. [],
  92. []
  93. ],
  94. // 当前选中的索引,初始为 null 表示未选择
  95. multiIndexB: [null, null, null],
  96. // 存储完整的原始树形数据
  97. optionListB: [],
  98. dataList: [],
  99. // 查询参数
  100. getDataType: false,
  101. queryParams: {
  102. page: 1,
  103. pageSize: 10,
  104. },
  105. total: 0,
  106. }
  107. },
  108. onLoad(options) {
  109. this.fromPage = options.from;
  110. },
  111. onShow() {
  112. this.getDeptDropList();
  113. this.systemBuildingGetTreeList();
  114. this.getList();
  115. },
  116. methods: {
  117. bindPickerChangeA(e) {
  118. this.indexA = e.detail.value
  119. this.$set(this.queryParams, 'page', 1);
  120. this.getList();
  121. },
  122. //滚动加载事件
  123. scrollGet() {
  124. let self = this;
  125. if (self.total / self.queryParams.pageSize <= self.queryParams.page) {
  126. this.$set(this, 'getDataType', true);
  127. } else {
  128. this.queryParams.page += 1;
  129. this.$nextTick(() => {
  130. this.getList();
  131. })
  132. }
  133. },
  134. //搜索用户
  135. async getList() {
  136. let self = this;
  137. let obj = {
  138. page: this.queryParams.page,
  139. pageSize: this.queryParams.pageSize,
  140. searchValue: this.inputData,
  141. deptId: this.indexA == null ? '' : this.listA[this.indexA].deptId,
  142. buildId: this.multiIndexB[1] == null ? '' : this.multiArrayB[1][this.multiIndexB[1]].id,
  143. floorId: this.multiIndexB[2] == null ? '' : this.multiArrayB[2][this.multiIndexB[2]].id,
  144. };
  145. const {
  146. data
  147. } = await airbottleNewQpAppletBottleSubjectsPage(obj);
  148. if (data.code == 200) {
  149. if (self.queryParams.page == 1) {
  150. this.dataList = data.data.records;
  151. this.total = data.data.total;
  152. if (data.data.total / self.queryParams.pageSize <= self.queryParams.page) {
  153. this.$set(this, 'getDataType', true);
  154. }
  155. } else {
  156. this.dataList = [...this.dataList, ...data.data.records]
  157. this.total = data.data.total;
  158. if (data.data.total / self.queryParams.pageSize <= self.queryParams.page) {
  159. this.$set(this, 'getDataType', true);
  160. }
  161. }
  162. }
  163. },
  164. async getDeptDropList() {
  165. const {
  166. data
  167. } = await getDeptDropList({
  168. deptName: '',
  169. level: 2,
  170. deptType: 1
  171. });
  172. if (data.code == 200) {
  173. let list = [];
  174. for (let i = 0; i < data.data.length; i++) {
  175. list.push(data.data[i].deptName);
  176. }
  177. this.$set(this, 'listA', data.data);
  178. this.$set(this, 'arrayA', list);
  179. }
  180. },
  181. async systemBuildingGetTreeList() {
  182. const {
  183. data
  184. } = await systemBuildingGetTreeList({});
  185. if (data.code == 200) {
  186. let list = JSON.parse(JSON.stringify(data.data));
  187. // 执行你原有的过滤逻辑
  188. this.pushNode(list);
  189. this.optionListB = list;
  190. // ✅ 核心:将树形结构转换为 multiSelector 需要的三维数组
  191. if (list.length > 0) {
  192. // 第一列:提取所有校区
  193. const campuses = list.map(item => item);
  194. // 第二列:默认取第一个校区下的楼栋列表
  195. const buildings = list[0].buildFloorVoList || [];
  196. // 第三列:默认取第一个楼栋下的楼层列表
  197. const floors = (buildings.length > 0) ? buildings[0].buildFloorVoList || [] : [];
  198. this.multiArrayB = [campuses, buildings, floors];
  199. // 重置选中索引为 null,实现默认不选中
  200. this.multiIndexB = [null, null, null];
  201. }
  202. }
  203. },
  204. // 辅助方法:你原有的树形节点过滤逻辑
  205. pushNode(list) {
  206. for (let i = 0; i < list.length; i++) {
  207. if (list[i].type != 3 && (!list[i].buildFloorVoList || list[i].buildFloorVoList.length === 0)) {
  208. list.splice(i, 1);
  209. i--;
  210. } else if (list[i].type == 3) {
  211. delete list[i].buildFloorVoList;
  212. } else {
  213. this.pushNode(list[i].buildFloorVoList);
  214. }
  215. }
  216. },
  217. // 2. 监听列变化(联动核心)
  218. bindColumnChangeB(e) {
  219. const column = e.detail.column; // 改变的列号 (0:校区, 1:楼栋, 2:楼层)
  220. const value = e.detail.value; // 改变后的索引
  221. // 更新当前列的索引
  222. this.multiIndexB[column] = value;
  223. if (column === 0) {
  224. // --- 第一列(校区)变化 ---
  225. // 1. 更新第二列(楼栋)的数据
  226. const currentCampus = this.optionListB[value];
  227. this.$set(this.multiArrayB, 1, currentCampus.buildFloorVoList || []);
  228. // 2. 更新第三列(楼层)的数据(基于新的楼栋列表的第一个)
  229. const newBuildings = this.multiArrayB[1];
  230. const newFloors = (newBuildings.length > 0) ? newBuildings[0].buildFloorVoList || [] : [];
  231. this.$set(this.multiArrayB, 2, newFloors);
  232. // 3. 重置后续列的索引
  233. this.multiIndexB[1] = 0;
  234. this.multiIndexB[2] = 0;
  235. } else if (column === 1) {
  236. // --- 第二列(楼栋)变化 ---
  237. // 1. 更新第三列(楼层)的数据
  238. const currentBuilding = this.multiArrayB[1][value];
  239. this.$set(this.multiArrayB, 2, currentBuilding.buildFloorVoList || []);
  240. // 2. 重置后续列的索引
  241. this.multiIndexB[2] = 0;
  242. }
  243. // 如果是第三列(楼层)变化,则无需更新其他列
  244. },
  245. // 3. 确认选择
  246. bindPickerChangeB(e) {
  247. this.multiIndexB = e.detail.value;
  248. // 获取最终选中的完整对象
  249. const selectedCampus = this.multiArrayB[0][this.multiIndexB[0]];
  250. const selectedBuilding = this.multiArrayB[1][this.multiIndexB[1]];
  251. const selectedFloor = this.multiArrayB[2][this.multiIndexB[2]];
  252. this.$set(this.queryParams, 'page', 1);
  253. this.getList();
  254. // 在这里将值赋值给表单字段
  255. // this.newData.campusId = selectedCampus.id;
  256. // this.newData.buildingId = selectedBuilding.id;
  257. // this.newData.floorId = selectedFloor.id;
  258. },
  259. //重置
  260. resetButton() {
  261. this.$set(this, 'inputData', '');
  262. this.$set(this, 'indexA', null);
  263. this.$set(this, 'multiIndexB', [null, null, null]);
  264. this.$set(this, 'dataList', []);
  265. this.$set(this, 'getDataType', false);
  266. this.$set(this, 'queryParams', {
  267. page: 1,
  268. pageSize: 10,
  269. });
  270. this.$set(this, 'total', 0);
  271. this.getList();
  272. },
  273. checkButton(item) {
  274. let obj = {
  275. pageType:2,
  276. subId:item.subId,
  277. deptId:item.deptId,
  278. subName:item.subName,
  279. buildName:item.buildName,
  280. floorName:item.floorName,
  281. roomNum:item.roomNum,
  282. }
  283. uni.$emit('refreshBPageData', obj);
  284. uni.navigateBack({ delta: 1 });
  285. },
  286. /* 扫一扫*/
  287. saoCode() {
  288. let self = this;
  289. uni.scanCode({
  290. onlyFromCamera: true,
  291. success: function(res) {
  292. if(res.result.indexOf('type') != -1){
  293. let list = res.result.split("?")[1].split("&");
  294. let codeData = {};
  295. list.forEach((item) => {
  296. codeData[item.split("=")[0]] = item.split("=")[1];
  297. })
  298. if (codeData.type == '5' && codeData.subId) {
  299. self.airBottleNewQpAppletBottleSubjectsInfo(codeData.subId);
  300. }else{
  301. uni.showToast({
  302. title: '请扫描正确的二维码',
  303. icon: "error",
  304. mask: true,
  305. duration: 2000
  306. });
  307. }
  308. }else{
  309. uni.showToast({
  310. title: '请扫描正确的二维码',
  311. icon: "error",
  312. mask: true,
  313. duration: 2000
  314. });
  315. }
  316. }
  317. });
  318. },
  319. async airBottleNewQpAppletBottleSubjectsInfo(subId) {
  320. const {
  321. data
  322. } = await airBottleNewQpAppletBottleSubjectsInfo({subId:subId});
  323. if (data.code == 200) {
  324. let obj = {
  325. pageType:2,
  326. subId:data.data.subId,
  327. deptId:data.data.deptId,
  328. subName:data.data.subName,
  329. buildName:data.data.buildName,
  330. floorName:data.data.floorName,
  331. roomNum:data.data.roomNum,
  332. }
  333. uni.$emit('refreshBPageData', obj);
  334. uni.navigateBack({ delta: 1 });
  335. }
  336. },
  337. }
  338. }
  339. </script>
  340. <style lang="stylus" scoped>
  341. #gasCylinderSelectLab {
  342. height: 100%;
  343. width: 100%;
  344. display flex;
  345. flex-direction column;
  346. overflow: hidden;
  347. position: relative;
  348. .top-input-max-box {
  349. background-color: #fff;
  350. .input-box {
  351. display: flex;
  352. border-radius: 40rpx;
  353. background-color: #eeeeee;
  354. margin: 20rpx 20rpx 0 20rpx;
  355. color: #7C7C7C;
  356. .icon-box {
  357. margin: 15rpx;
  358. }
  359. .input-min {
  360. height: 80rpx;
  361. line-height: 80rpx;
  362. flex: 1;
  363. }
  364. .button-p {
  365. line-height: 80rpx;
  366. width: 120rpx;
  367. text-align: center;
  368. color: #333;
  369. font-size: 28rpx;
  370. background-color: #D4D4D4;
  371. border-top-right-radius: 40rpx;
  372. border-bottom-right-radius: 40rpx;
  373. }
  374. }
  375. .picker-box {
  376. display: flex;
  377. .picker-min-box {
  378. height: 80rpx;
  379. line-height: 80rpx;
  380. display: flex;
  381. padding: 0 30rpx;
  382. .icon-box {
  383. margin-left: 10rpx;
  384. }
  385. }
  386. }
  387. }
  388. .content-box {
  389. flex: 1;
  390. display flex;
  391. flex-direction column;
  392. overflow: scroll;
  393. padding-bottom: 40rpx;
  394. .null-p {
  395. text-align: center;
  396. line-height: 300rpx;
  397. color: #999;
  398. }
  399. .for-max-big-box {
  400. padding: 20rpx 30rpx;
  401. background-color: #fff;
  402. border-radius: 10rpx;
  403. margin: 25rpx 25rpx 0;
  404. .for-title-box {
  405. display: flex;
  406. margin-bottom: 20rpx;
  407. view {
  408. padding:15rpx 0 35rpx 0;
  409. // padding-bottom: 20rpx;
  410. line-height: 30rpx;
  411. border-bottom: 1rpx solid #dedede;
  412. font-weight: 700;
  413. }
  414. view:nth-child(1) {
  415. min-width:200rpx;
  416. color: #666666;
  417. flex: 1;
  418. }
  419. view:nth-child(2) {
  420. text-align: left;
  421. }
  422. }
  423. .for-text-box {
  424. display: flex;
  425. view {
  426. line-height: 60rpx;
  427. font-weight: 700;
  428. }
  429. view:nth-child(1) {
  430. color: #666666;
  431. }
  432. view:nth-child(2) {
  433. flex: 1;
  434. text-align: right;
  435. }
  436. }
  437. }
  438. }
  439. .sao-code-box {
  440. width: 100rpx;
  441. height: 100rpx;
  442. line-height: 100rpx;
  443. text-align: center;
  444. background-color: #266FFF;
  445. border-radius: 50%;
  446. position: absolute;
  447. bottom: 60rpx;
  448. left: 50%;
  449. margin-left: -50rpx;
  450. }
  451. }
  452. </style>