index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. <template>
  2. <view class="page detail">
  3. <uni-card>
  4. <view class="form-content">
  5. <uni-forms ref="formRef" :model-value="form" :rules="rules" err-show-type="toast" labelWidth="140px">
  6. <!-- 设备 -->
  7. <uni-forms-item
  8. class="form-item align-center"
  9. name="deviceName"
  10. :label="$t('statusChange.form.device')"
  11. required
  12. @click="selectDevice"
  13. >
  14. <uni-easyinput
  15. class="input-readonly"
  16. v-model="form.deviceName"
  17. :inputBorder="false"
  18. :clearable="false"
  19. :styles="{disableColor:'#fff'}"
  20. :placeholder="$t('statusChange.form.deviceHint')"
  21. style="text-align: right"
  22. @click.prevent="selectDevice"
  23. />
  24. </uni-forms-item>
  25. <!-- 责任人 -->
  26. <uni-forms-item
  27. class="form-item align-center"
  28. name="userNames"
  29. :label="$t('deviceUser.form.user')"
  30. required
  31. @click="showLeaderPopup"
  32. >
  33. <uni-easyinput
  34. class="input-readonly"
  35. v-model="form.userNames"
  36. :inputBorder="false"
  37. :clearable="false"
  38. :styles="{disableColor:'#fff'}"
  39. :placeholder="$t('deviceUser.form.userHint')"
  40. style="text-align: right"
  41. @click.prevent="showLeaderPopup"
  42. />
  43. </uni-forms-item>
  44. <!-- 调整原因 -->
  45. <uni-forms-item class="form-item align-center" name="reason" :label="$t('statusChange.form.reason')" required>
  46. <uni-easyinput style="text-align: right" :autoHeight="true" :inputBorder="false"
  47. :clearable="false" :styles="{ disableColor:'#fff' }"
  48. :placeholder="$t('statusChange.form.reasonHint')" v-model="form.reason" />
  49. </uni-forms-item>
  50. </uni-forms>
  51. </view>
  52. </uni-card>
  53. <button class="submit-btn" type="primary" @click="submit">{{ $t('operation.submit') }}</button>
  54. <uni-popup ref="popup" type="bottom">
  55. <z-paging class="z-page-popup" style="top: 200px">
  56. <template #top>
  57. <view>
  58. <uni-row class="flex-row justify-center" style="margin-top: 30px">
  59. <text>{{ $t('statusChange.form.selectDevice') }}</text>
  60. </uni-row>
  61. <view style="margin-top: 18px; padding-left: 30px; padding-right: 30px">
  62. <uni-easyinput v-model="keywords" :styles="inputStyles" :placeholderStyle="placeholderStyle"
  63. :placeholder="$t('statusChange.form.searchHint')" :input-border="false"
  64. @input="onKeywordsChanged" />
  65. </view>
  66. <view class="choice-row flex-row flex-wrap align-center justify-start" style="margin: 0 28px">
  67. <view class="choice-item align-center justify-center" v-for="item in selectedList"
  68. @click="onItemDelete(item)">
  69. {{item.deviceName}}
  70. <uni-icons class="choice-close-icon" type="closeempty" color="#fff"></uni-icons>
  71. </view>
  72. </view>
  73. </view>
  74. </template>
  75. <template #bottom>
  76. <button class="submit-btn" type="primary" @click="confirmDevice">
  77. {{ $t('operation.confirm') }}
  78. </button>
  79. </template>
  80. <view v-for="item of filterList" :key="item.id">
  81. <view class="device-item" :class="item.selected ? 'selected' : undefined"
  82. @click="onSelectedItem(item)">
  83. {{ `${item.deviceCode} (${item.deviceName})` }}
  84. </view>
  85. <view class="divider" />
  86. </view>
  87. </z-paging>
  88. </uni-popup>
  89. <!-- 责任人 -->
  90. <uni-popup ref="leaderPopup" type="bottom">
  91. <z-paging class="z-page-popup" style="top: 200px">
  92. <template #top>
  93. <view>
  94. <uni-row class="flex-row justify-center" style="margin-top: 30px">
  95. <text>{{ $t('deviceUser.form.selectUser') }}</text>
  96. </uni-row>
  97. <view style="margin-top: 18px; padding-left: 30px; padding-right: 30px">
  98. <uni-easyinput
  99. v-model="userKeywords"
  100. :styles="inputStyles"
  101. :placeholderStyle="placeholderStyle"
  102. :placeholder="$t('deviceUser.form.userPlaceholder')"
  103. :input-border="false"
  104. @input="onUserChanged"
  105. />
  106. </view>
  107. <view class="choice-row flex-row flex-wrap align-center justify-start" style="margin: 0 28px">
  108. <view class="choice-item align-center justify-center" v-for="item in selectUserList"
  109. @click="onUserItemDelete(item)">
  110. {{item.nickname}}
  111. <uni-icons class="choice-close-icon" type="closeempty" color="#fff"></uni-icons>
  112. </view>
  113. </view>
  114. </view>
  115. </template>
  116. <template #bottom>
  117. <button class="submit-btn" type="primary" @click="confirmUser">
  118. {{ $t('operation.confirm') }}
  119. </button>
  120. </template>
  121. <view v-for="item of filterUserList" :key="item.id">
  122. <view class="device-item" :class="item.selected ? 'selected' : undefined" @click="onSelectUser(item)">
  123. {{ item.nickname }}
  124. </view>
  125. <view class="divider" />
  126. </view>
  127. </z-paging>
  128. </uni-popup>
  129. </view>
  130. </template>
  131. <script setup>
  132. import { reactive, ref, onMounted, nextTick, getCurrentInstance } from 'vue'
  133. import { useDataDictStore } from "@/store/modules/dataDict"
  134. import { getAllDeviceList, getUserListByDeptId } from "@/api"
  135. import { getDeptId } from '@/utils/auth';
  136. import { submitDeviceUser } from "@/api/deviceUser";
  137. const { appContext } = getCurrentInstance()
  138. const t = appContext.config.globalProperties.$t
  139. const { getDataDictList } = useDataDictStore()
  140. const statusList = ref([])
  141. const formRef = ref()
  142. const form = reactive({
  143. deviceName: '',
  144. deviceId: '',
  145. userIds: '',
  146. userNames: '',
  147. reason: '',
  148. })
  149. const rules = reactive({
  150. deviceName: { rules: [{ required: true, errorMessage: t('statusChange.form.deviceError') }] },
  151. userNames: { rules: [{ required: true, errorMessage: t('deviceUser.form.userHint') }] },
  152. reason: { rules: [{ required: true, errorMessage: t('statusChange.form.reasonError') }] },
  153. })
  154. const popup = ref()
  155. const selectDevice = () => {
  156. popup.value.open('bottom')
  157. }
  158. const placeholderStyle = ref('color: #ADADAD; font-weight: 500; font-size: 12px')
  159. const inputStyles = reactive({
  160. backgroundColor: '#F5F5F5',
  161. borderRadius: '4px',
  162. color: '#797979',
  163. fontSize: '12px',
  164. })
  165. const keywords = ref('')
  166. const onKeywordsChanged = (text) => {
  167. filterList.value = deviceList.value.filter(item => item.deviceCode.includes(text) || item.deviceName.includes(text))
  168. }
  169. const selectedList = ref([])
  170. const onSelectedItem = (row) => {
  171. row.selected = !row.selected
  172. if (row.selected) {
  173. selectedList.value.push(row)
  174. } else {
  175. selectedList.value = selectedList.value.filter(item => item.id !== row.id)
  176. }
  177. }
  178. const onItemDelete = (item) => {
  179. const index = selectedList.value.findIndex((v) => v.id === item.id)
  180. item.selected = !item.selected
  181. if (index > -1) {
  182. selectedList.value.splice(index, 1)
  183. }
  184. }
  185. const confirmDevice = () => {
  186. form.deviceName = selectedList.value.map(item => item.deviceName).join(',')
  187. popup.value.close('bottom')
  188. }
  189. const leaderPopup = ref() // 责任人弹窗
  190. const selectUserList = ref([]) // 已选责任人
  191. // 弹出责任人弹窗
  192. const showLeaderPopup = () => {
  193. leaderPopup.value.open('bottom')
  194. }
  195. // 选择责任人
  196. const onSelectUser = (user) => {
  197. user.selected = !user.selected
  198. if (user.selected) {
  199. selectUserList.value.push(user)
  200. } else {
  201. selectUserList.value = selectUserList.value.filter(item => item.id !== user.id)
  202. }
  203. }
  204. // 确认责任人
  205. const confirmUser = () => {
  206. form.userNames = selectUserList.value.map(item => item.nickname).join(',')
  207. leaderPopup.value.close('bottom')
  208. }
  209. // 删除责任人
  210. const onUserItemDelete = (item) => {
  211. const index = selectUserList.value.findIndex((v) => v.id === item.id)
  212. item.selected = !item.selected
  213. if (index > -1) {
  214. selectUserList.value.splice(index, 1)
  215. }
  216. }
  217. const userKeywords = ref('') // 责任人搜索关键字
  218. // 搜索责任人监听
  219. const onUserChanged = (text) => {
  220. filterUserList.value = text ? userList.value.filter(item => item.nickname.includes(text)) : userList.value
  221. }
  222. const submit = async () => {
  223. try {
  224. const valid = await formRef.value.validate()
  225. if (!valid) return
  226. const list = []
  227. for (const item of selectedList.value) {
  228. list.push({
  229. deviceId: item.id,
  230. reason: form.reason,
  231. userIds: selectUserList.value.map(item => item.id),
  232. })
  233. }
  234. const response = await submitDeviceUser(list)
  235. if (response.code === 0) {
  236. uni.showToast({ title: t('statusChange.form.success'), icon: 'none' })
  237. uni.navigateBack()
  238. uni.$emit('update')
  239. }
  240. } catch (e) {
  241. console.log(e)
  242. }
  243. }
  244. const userList = ref([]) // 待选责任人列表
  245. const filterUserList = ref([]) // 筛选后列表
  246. const deviceList = ref([]) // 待选设备列表
  247. const filterList = ref([]) // 筛选后列表
  248. onMounted(async () => {
  249. statusList.value = getDataDictList('pms_device_status')
  250. const locale = uni.getLocale()
  251. // deviceList.value = (await getAllDeviceList(getDeptId())).data.map((item) => {
  252. // if (item.deviceName.includes('~~') && item.deviceName.includes('**')) {
  253. // const s = item.deviceName.split('~~')
  254. // if (locale.startsWith('zh')) {
  255. // item.deviceName = s[0]
  256. // } else if (locale.startsWith('ru')) {
  257. // const s2 = s[2].split('**')
  258. // item.deviceName = s2[1]
  259. // } else {
  260. // const s1 = s[1].split('**')
  261. // item.deviceName = s1[1]
  262. // }
  263. // }
  264. // return JSON.parse(JSON.stringify(item))
  265. // })
  266. deviceList.value = (await getAllDeviceList(getDeptId())).data
  267. filterList.value = deviceList.value
  268. userList.value = (await getUserListByDeptId(getDeptId())).data
  269. filterUserList.value = userList.value
  270. await nextTick(() => {
  271. const inputViews = document.getElementsByClassName('input-readonly');
  272. for (const view of inputViews) {
  273. view.readOnly = true
  274. }
  275. })
  276. })
  277. </script>
  278. <style lang="scss" scoped>
  279. @import "@/style/choose-device.scss";
  280. .form-item{
  281. min-height: 45px;
  282. }
  283. .segmented-control {
  284. margin-bottom: 15px;
  285. }
  286. .button-group {
  287. margin-top: 15px;
  288. display: flex;
  289. justify-content: space-around;
  290. }
  291. .button {
  292. display: flex;
  293. align-items: center;
  294. height: 35px;
  295. line-height: 35px;
  296. margin-left: 10px;
  297. }
  298. :deep(.input-value-border) {
  299. border: 0 !important;
  300. }
  301. :deep(.input-value) {
  302. text-align: end;
  303. }
  304. :deep(.selected-list) {
  305. display: block;
  306. }
  307. :deep(.selected-area) {
  308. display: block;
  309. margin-right: 5px;
  310. }
  311. :deep(.uni-data-pickerview .selected-area) {
  312. display: none;
  313. }
  314. :deep(.tab-c) {
  315. margin-left: 30px;
  316. margin-right: 30px;
  317. border-top: 1px dashed #CACCCF;
  318. .item {
  319. border-bottom: 1px dashed #CACCCF;
  320. }
  321. }
  322. :deep(.uni-forms-item) {
  323. margin-bottom: 0;
  324. border-bottom: 1px dashed #CACCCF;
  325. }
  326. :deep(.uni-card) {
  327. padding: 0 !important;
  328. margin: 0 0 10px 0 !important;
  329. }
  330. .popup-content {
  331. height: 500px;
  332. }
  333. .device-item {
  334. height: 35px;
  335. line-height: 35px;
  336. padding: 0 30px;
  337. font-size: 13px;
  338. color: #333333;
  339. border-bottom: 1px #CACCCF;
  340. }
  341. .selected {
  342. color: #004098;
  343. }
  344. .divider {
  345. height: 0.5px;
  346. margin: 0 28px;
  347. background-color: #CACCCF;
  348. }
  349. .z-page-popup {
  350. padding: 0;
  351. background: white;
  352. border-radius: 10px 10px 0 0;
  353. }
  354. .submit-btn {
  355. width: 100%;
  356. height: 48px;
  357. border-radius: 0;
  358. }
  359. .input-readonly {
  360. caret-color: transparent;
  361. }
  362. </style>