deviceExam.vue 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <route lang="json5" type="page">
  2. {
  3. layout: 'default',
  4. style: {
  5. navigationBarTitleText: '设备查询',
  6. navigationStyle: 'custom',
  7. disableScroll: true,
  8. 'app-plus': {
  9. bounce: 'none',
  10. },
  11. },
  12. }
  13. </route>
  14. <template>
  15. <view class="device-container">
  16. <!-- 导航栏 -->
  17. <NavBar title="设备查询" />
  18. <!-- 查询表单 -->
  19. <view class="query-form-header" @click="controlQueryVisible = !controlQueryVisible">
  20. <text class="query-title">查询条件</text>
  21. <text class="query-arrow">{{ controlQueryVisible ? '▲' : '▼' }}</text>
  22. </view>
  23. <transition name="query-form">
  24. <view v-if="controlQueryVisible" class="query-form">
  25. <view class="form-item">
  26. <text class="form-label">设备类别</text>
  27. <wd-picker
  28. v-model="selectedTypeValue"
  29. :columns="equipmentTypesColumn"
  30. @change="onTypeChange"
  31. />
  32. </view>
  33. <view class="form-item">
  34. <text class="form-label">设备名称</text>
  35. <input class="form-input" v-model="formData.equipName" placeholder="请输入设备名称" />
  36. </view>
  37. <view class="form-item">
  38. <text class="form-label">设备注册代码</text>
  39. <input class="form-input" v-model="formData.equipCode" placeholder="请输入设备注册代码" />
  40. </view>
  41. <view class="form-item">
  42. <text class="form-label">出厂编号</text>
  43. <input class="form-input" v-model="formData.productNo" placeholder="请输入出厂编号" />
  44. </view>
  45. <view class="form-item">
  46. <text class="form-label">使用单位</text>
  47. <input class="form-input" v-model="formData.unitName" placeholder="请输入使用单位" />
  48. </view>
  49. <view class="form-item">
  50. <text class="form-label">单位内编号</text>
  51. <input class="form-input" v-model="formData.unitInnerNo" placeholder="请输入单位内编号" />
  52. </view>
  53. <view class="form-item">
  54. <text class="form-label">使用证编号</text>
  55. <input class="form-input" v-model="formData.useRegisterNo" placeholder="请输入使用证编号" />
  56. </view>
  57. <view class="form-actions">
  58. <button class="action-btn reset-btn" @click="handleReset">重置</button>
  59. <button class="action-btn query-btn" @click="handleQuery">查询</button>
  60. </view>
  61. </view>
  62. </transition>
  63. <!-- 列表 -->
  64. <scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
  65. <view v-for="item in listData" :key="item.id" class="item-box" @click="handleItemClick(item)">
  66. <view class="item-header">
  67. <text class="item-title">设备注册代码:{{ item.equipCode }}</text>
  68. </view>
  69. <view class="item-content">
  70. <view class="info-item">
  71. <text class="info-label">设备名称:</text>
  72. <text class="info-value">{{ item.equipName }}</text>
  73. </view>
  74. <view class="info-item">
  75. <text class="info-label">出厂编号:</text>
  76. <text class="info-value">{{ item.productNo || '--' }}</text>
  77. </view>
  78. <view class="info-item">
  79. <text class="info-label">使用单位:</text>
  80. <text class="info-value">{{ item.unitName }}</text>
  81. </view>
  82. </view>
  83. </view>
  84. <view v-if="loading" class="loading-text">加载中...</view>
  85. <view v-if="!hasMore && listData.length > 0" class="no-more-text">没有更多了</view>
  86. <view v-if="!loading && listData.length === 0" class="empty-view">
  87. <text class="empty-text">暂无数据</text>
  88. </view>
  89. </scroll-view>
  90. </view>
  91. </template>
  92. <script lang="ts" setup>
  93. import { ref, reactive, computed } from 'vue'
  94. import { useConfigStore } from '@/store/config'
  95. import { EquipFuncName, requestFunc } from '@/api/ApiRouter/equipment'
  96. import NavBar from '@/components/NavBar/NavBar.vue'
  97. import { onShow } from '@dcloudio/uni-app'
  98. defineOptions({
  99. name: 'deviceExam',
  100. })
  101. const equipType = useConfigStore().getEquipType()
  102. const listData = ref<any[]>([])
  103. const loading = ref(false)
  104. const hasMore = ref(true)
  105. const controlQueryVisible = ref(true)
  106. const params = reactive({
  107. pageNo: 1,
  108. pageSize: 10,
  109. })
  110. const formData = reactive({
  111. type: '',
  112. equipName: '',
  113. equipCode: '',
  114. productNo: '',
  115. unitName: '',
  116. unitInnerNo: '',
  117. useRegisterNo: '',
  118. })
  119. const selectedType = ref<any>(null)
  120. const selectedTypeValue = ref('')
  121. const equipmentTypes = ref([
  122. { label: '全部', value: '' },
  123. { label: '压力容器', value: '1' },
  124. { label: '锅炉', value: '2' },
  125. { label: '管道', value: '3' },
  126. ])
  127. const equipmentTypesColumn = computed(() => [
  128. equipmentTypes.value.map((item) => ({ label: item.label, value: item.value })),
  129. ])
  130. // 获取列表数据
  131. const fetchList = async (refresh = false) => {
  132. if (loading.value) return
  133. params.pageNo = refresh ? 1 : params.pageNo + 1
  134. loading.value = true
  135. try {
  136. const queryData = {
  137. ...params,
  138. ...formData,
  139. }
  140. const result: any = await requestFunc(EquipFuncName.EquipPage, equipType, queryData)
  141. const newList = result?.data?.list || []
  142. if (refresh) {
  143. listData.value = newList
  144. } else {
  145. listData.value = [...listData.value, ...newList]
  146. }
  147. hasMore.value = newList.length >= params.pageSize
  148. } catch (error) {
  149. console.error('获取设备列表失败:', error)
  150. } finally {
  151. loading.value = false
  152. }
  153. }
  154. // 加载更多
  155. const loadMore = () => {
  156. if (!loading.value && hasMore.value) {
  157. fetchList(false)
  158. }
  159. }
  160. // 刷新列表
  161. const refreshList = () => {
  162. params.pageNo = 1
  163. fetchList(true)
  164. }
  165. // 选择设备类别
  166. const onTypeChange = ({ selected }) => {
  167. const index = selected[0]
  168. selectedType.value = equipmentTypes.value[index]
  169. formData.type = selectedType.value?.value || ''
  170. selectedTypeValue.value = selectedType.value?.value || ''
  171. }
  172. // 重置
  173. const handleReset = () => {
  174. formData.type = ''
  175. formData.equipName = ''
  176. formData.equipCode = ''
  177. formData.productNo = ''
  178. formData.unitName = ''
  179. formData.unitInnerNo = ''
  180. formData.useRegisterNo = ''
  181. selectedType.value = null
  182. refreshList()
  183. }
  184. // 查询
  185. const handleQuery = () => {
  186. refreshList()
  187. }
  188. // 点击 item
  189. const handleItemClick = (item: any) => {
  190. uni.navigateTo({
  191. url: `/pages/deviceExam/deviceExamDetail?id=${item.id}`,
  192. })
  193. }
  194. onShow(() => {
  195. refreshList()
  196. })
  197. </script>
  198. <style lang="scss" scoped>
  199. .device-container {
  200. display: flex;
  201. flex-direction: column;
  202. height: 100vh;
  203. background-color: #f5f5f5;
  204. }
  205. .navigate-view {
  206. display: flex;
  207. align-items: center;
  208. justify-content: center;
  209. height: 44px;
  210. background-color: #fff;
  211. border-bottom: 1px solid #eee;
  212. }
  213. .navigate-title {
  214. font-size: 17px;
  215. font-weight: 500;
  216. color: #333;
  217. }
  218. .query-form-header {
  219. display: flex;
  220. flex-direction: row;
  221. align-items: center;
  222. justify-content: space-between;
  223. padding: 12px 15px;
  224. background-color: #fff;
  225. border-bottom: 1px solid #eee;
  226. }
  227. .query-title {
  228. font-size: 14px;
  229. color: #333;
  230. }
  231. .query-arrow {
  232. font-size: 12px;
  233. color: #999;
  234. }
  235. .query-form {
  236. padding: 15px;
  237. background-color: #fff;
  238. border-bottom: 1px solid #eee;
  239. }
  240. .form-item {
  241. display: flex;
  242. flex-direction: row;
  243. align-items: center;
  244. margin-bottom: 12px;
  245. }
  246. .form-label {
  247. width: 100px;
  248. font-size: 14px;
  249. color: #666;
  250. }
  251. .form-input {
  252. flex: 1;
  253. height: 36px;
  254. padding: 0 10px;
  255. font-size: 14px;
  256. border: 1px solid #ddd;
  257. border-radius: 4px;
  258. }
  259. .form-picker {
  260. flex: 1;
  261. height: 36px;
  262. padding: 0;
  263. font-size: 14px;
  264. border: 1px solid #ddd;
  265. border-radius: 4px;
  266. }
  267. .picker-value {
  268. display: flex;
  269. flex: 1;
  270. flex-direction: row;
  271. align-items: center;
  272. justify-content: space-between;
  273. height: 36px;
  274. padding: 0 10px;
  275. font-size: 14px;
  276. border: 1px solid #ddd;
  277. border-radius: 4px;
  278. }
  279. .picker-arrow {
  280. font-size: 12px;
  281. color: #999;
  282. }
  283. .form-actions {
  284. display: flex;
  285. flex-direction: row;
  286. gap: 10%;
  287. justify-content: flex-end;
  288. padding: 0 10%;
  289. margin-top: 10px;
  290. }
  291. .action-btn {
  292. flex: 1;
  293. padding: 0 20px;
  294. font-size: 14px;
  295. border: none;
  296. border-radius: 4px;
  297. }
  298. .reset-btn {
  299. color: #2f8eff;
  300. background-color: #fff;
  301. border: 1px solid #2f8eff;
  302. }
  303. .query-btn {
  304. color: #fff;
  305. background-color: #2f8eff;
  306. }
  307. .list-scroll {
  308. flex: 1;
  309. overflow: hidden;
  310. }
  311. .loading-text,
  312. .no-more-text {
  313. padding: 15px;
  314. font-size: 14px;
  315. color: #999;
  316. text-align: center;
  317. }
  318. .empty-view {
  319. display: flex;
  320. align-items: center;
  321. justify-content: center;
  322. padding: 40px;
  323. }
  324. .item-box {
  325. padding: 10px;
  326. margin: 10px;
  327. background-color: #fff;
  328. border-radius: 5px;
  329. }
  330. .item-header {
  331. display: flex;
  332. flex-direction: row;
  333. justify-content: space-between;
  334. padding-bottom: 10px;
  335. border-bottom: 1px solid #eee;
  336. }
  337. .item-title {
  338. font-size: 16px;
  339. font-weight: 600;
  340. color: #333;
  341. }
  342. .item-content {
  343. display: flex;
  344. flex-direction: column;
  345. gap: 8px;
  346. padding: 10px;
  347. margin-top: 10px;
  348. background-color: #f2f2f2;
  349. border-radius: 5px;
  350. }
  351. .info-item {
  352. display: flex;
  353. flex-direction: row;
  354. }
  355. .info-label {
  356. font-size: 14px;
  357. color: #666;
  358. }
  359. .info-value {
  360. flex: 1;
  361. font-size: 14px;
  362. color: #333;
  363. }
  364. </style>