index.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <template>
  2. <doc-alert title="用户体系" url="https://doc.iocoder.cn/user-center/" />
  3. <doc-alert title="三方登陆" url="https://doc.iocoder.cn/social-user/" />
  4. <doc-alert title="Excel 导入导出" url="https://doc.iocoder.cn/excel-import-and-export/" />
  5. <el-row :gutter="20">
  6. <!-- 左侧 设备分类 树 -->
  7. <el-col :span="4" :xs="24">
  8. <ContentWrap class="h-1/1">
  9. <ModelCategoryTree @node-click="handleModelCategoryTreeNodeClick" />
  10. </ContentWrap>
  11. </el-col>
  12. <el-col :span="20" :xs="24">
  13. <!-- 搜索 -->
  14. <div
  15. style="border: none; background: #fff; display: flex; align-items: center"
  16. class="py-2 rounded-sm px-2"
  17. >
  18. <el-form
  19. class="-mb-15px"
  20. :model="queryParams"
  21. ref="queryFormRef"
  22. :inline="true"
  23. label-width="68px"
  24. >
  25. <el-form-item :label="t('modelTemplate.name')" prop="name" style="margin-left: 45px">
  26. <el-input
  27. v-model="queryParams.name"
  28. :placeholder="t('modelTemplate.nameHolder')"
  29. clearable
  30. @keyup.enter="handleQuery"
  31. class="!w-240px"
  32. />
  33. </el-form-item>
  34. <!-- <el-form-item label="模板编码" prop="code">
  35. <el-input
  36. v-model="queryParams.code"
  37. placeholder="请输入模板编码"
  38. clearable
  39. @keyup.enter="handleQuery"
  40. class="!w-240px"
  41. />
  42. </el-form-item>-->
  43. <el-form-item :label="t('modelTemplate.status')" prop="status">
  44. <el-select
  45. v-model="queryParams.status"
  46. :placeholder="t('modelTemplate.status')"
  47. clearable
  48. class="!w-240px"
  49. >
  50. <el-option
  51. v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  52. :key="dict.value"
  53. :label="dict.label"
  54. :value="dict.value"
  55. />
  56. </el-select>
  57. </el-form-item>
  58. <el-form-item :label="t('modelTemplate.createTime')" prop="createTime">
  59. <el-date-picker
  60. v-model="queryParams.createTime"
  61. value-format="YYYY-MM-DD HH:mm:ss"
  62. type="datetimerange"
  63. :start-placeholder="t('operationFill.start')"
  64. :end-placeholder="t('operationFill.end')"
  65. class="!w-240px"
  66. />
  67. </el-form-item>
  68. <el-form-item>
  69. <el-button @click="handleQuery"
  70. ><Icon icon="ep:search" />{{ t('operationFill.search') }}</el-button
  71. >
  72. <el-button @click="resetQuery"
  73. ><Icon icon="ep:refresh" />{{ t('operationFill.reset') }}</el-button
  74. >
  75. <el-button
  76. type="primary"
  77. plain
  78. @click="openForm('create')"
  79. v-hasPermi="['rq:iot-model-template:create']"
  80. >
  81. <Icon icon="ep:plus" />{{ t('operationFill.add') }}
  82. </el-button>
  83. </el-form-item>
  84. </el-form>
  85. </div>
  86. <ContentWrap style="border: none; margin-top: 20px">
  87. <zm-table :loading="loading" :data="list">
  88. <!-- <el-table-column
  89. label="模板编码"
  90. align="center"
  91. prop="code"
  92. :show-overflow-tooltip="true"
  93. />-->
  94. <zm-table-column
  95. :label="t('modelTemplate.name')"
  96. align="center"
  97. prop="name"
  98. :show-overflow-tooltip="true"
  99. />
  100. <zm-table-column
  101. :label="t('modelTemplate.ec')"
  102. align="center"
  103. key="deviceCategoryName"
  104. prop="deviceCategoryName"
  105. :show-overflow-tooltip="true"
  106. />
  107. <zm-table-column :label="t('modelTemplate.status')" key="status">
  108. <template #default="scope">
  109. <el-switch
  110. v-model="scope.row.status"
  111. :active-value="0"
  112. :inactive-value="1"
  113. @change="handleStatusChange(scope.row)"
  114. :disabled="!checkPermi(['rq:iot-model-template:update'])"
  115. />
  116. </template>
  117. </zm-table-column>
  118. <zm-table-column
  119. :label="t('modelTemplate.createTime')"
  120. align="center"
  121. prop="createTime"
  122. :formatter="dateFormatter"
  123. />
  124. <zm-table-column :label="t('operationFill.operation')" align="center" width="220" action>
  125. <template #default="scope">
  126. <div class="flex items-center justify-center">
  127. <el-button
  128. type="primary"
  129. link
  130. @click="
  131. openDetail(
  132. scope.row.deviceCategoryId +
  133. ',' +
  134. scope.row.deviceCategoryName +
  135. ',' +
  136. scope.row.name
  137. )
  138. "
  139. >
  140. <Icon icon="ep:edit" />{{ t('operationFill.view') }}
  141. </el-button>
  142. <el-button
  143. type="primary"
  144. link
  145. @click="openForm('update', scope.row.id)"
  146. v-hasPermi="['rq:iot-model-template:update']"
  147. >
  148. <Icon icon="ep:edit" />{{ t('modelTemplate.update') }}
  149. </el-button>
  150. <el-button
  151. type="danger"
  152. link
  153. @click="handleDelete(scope.row.id, scope.row.deviceCategoryId)"
  154. v-hasPermi="['rq:iot-model-template:delete']"
  155. >
  156. <Icon icon="ep:delete" />{{ t('modelTemplate.delete') }}
  157. </el-button>
  158. </div>
  159. </template>
  160. </zm-table-column>
  161. </zm-table>
  162. <Pagination
  163. :total="total"
  164. v-model:page="queryParams.pageNo"
  165. v-model:limit="queryParams.pageSize"
  166. @pagination="getList"
  167. />
  168. </ContentWrap>
  169. </el-col>
  170. </el-row>
  171. <!-- 添加或修改 属性模板 对话框 -->
  172. <TemplateForm ref="formRef" :category_id="selectedId" @success="getList" />
  173. </template>
  174. <script lang="ts" setup>
  175. import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  176. import { checkPermi } from '@/utils/permission'
  177. import { dateFormatter } from '@/utils/formatTime'
  178. import { CommonStatusEnum } from '@/utils/constants'
  179. import * as ModelTemplateApi from '@/api/pms/modeltemplate'
  180. import TemplateForm from './TemplateForm.vue'
  181. import ModelCategoryTree from './ModelCategoryTree.vue'
  182. import { useTreeStore } from '@/store/modules/attrTemplateTreeStore'
  183. import { useTableComponents } from '@/components/ZmTable/useTableComponents'
  184. const { ZmTable, ZmTableColumn } = useTableComponents()
  185. defineOptions({ name: 'ModelAttrsTemplate' })
  186. const treeStore = useTreeStore()
  187. const message = useMessage() // 消息弹窗
  188. const { t } = useI18n() // 国际化
  189. const { push } = useRouter()
  190. const loading = ref(true) // 列表的加载中
  191. const total = ref(0) // 列表的总页数
  192. const list = ref([]) // 列表的数
  193. const queryParams = reactive({
  194. pageNo: 1,
  195. pageSize: 10,
  196. name: undefined,
  197. code: undefined,
  198. status: undefined,
  199. deviceCategoryId: undefined,
  200. deviceCategoryName: undefined,
  201. createTime: []
  202. })
  203. const queryFormRef = ref() // 搜索的表单
  204. // 从 Store 中获取左侧 设备分类树 选中的 节点ID
  205. const selectedId = computed(() => treeStore.selectedId)
  206. const isInitialized = ref(false)
  207. /** 查询 设备属性模板 列表 */
  208. const getList = async () => {
  209. loading.value = true
  210. try {
  211. const data = await ModelTemplateApi.getModelTemplatePage(queryParams)
  212. list.value = data.list
  213. total.value = data.total
  214. // 数据加载完成后,标记为已初始化
  215. setTimeout(() => {
  216. isInitialized.value = true
  217. }, 100)
  218. } finally {
  219. loading.value = false
  220. }
  221. }
  222. /** 搜索按钮操作 */
  223. const handleQuery = () => {
  224. queryParams.pageNo = 1
  225. getList()
  226. }
  227. /** 重置按钮操作 */
  228. const resetQuery = () => {
  229. queryFormRef.value?.resetFields()
  230. handleQuery()
  231. }
  232. /** 处理 设备分类树 被点击 */
  233. const handleModelCategoryTreeNodeClick = async (row) => {
  234. queryParams.deviceCategoryId = row.id
  235. await getList()
  236. }
  237. /** 添加/修改操作 */
  238. const formRef = ref()
  239. const openForm = (type: string, id?: number) => {
  240. formRef.value.open(type, id)
  241. }
  242. /** 打开详情 */
  243. const openDetail = (id: string) => {
  244. push({ name: 'ModelAttrTemplate', params: { id } })
  245. }
  246. /** 修改 设备属性模板 状态 */
  247. const handleStatusChange = async (row: ModelTemplateApi.ModelAttrTemplateVO) => {
  248. // 如果还未初始化完成,直接返回
  249. if (!isInitialized.value) {
  250. return
  251. }
  252. try {
  253. // 修改状态的二次确认
  254. const text = row.status === CommonStatusEnum.ENABLE ? '启用' : '停用'
  255. await message.confirm('确认要"' + text + '""' + row.name + '"属性模板吗?')
  256. // 发起修改状态
  257. await ModelTemplateApi.updateModelTemplateStatus(row.id, row.status)
  258. // 刷新列表
  259. await getList()
  260. } catch {
  261. // 取消后,进行恢复按钮
  262. row.status =
  263. row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE : CommonStatusEnum.ENABLE
  264. }
  265. }
  266. /** 操作分发 */
  267. const handleCommand = (command: string, row: ModelTemplateApi.ModelAttrTemplateVO) => {
  268. switch (command) {
  269. case 'handleDelete':
  270. handleDelete(row.id, row.deviceCategoryId)
  271. break
  272. default:
  273. break
  274. }
  275. }
  276. /** 删除按钮操作 */
  277. const handleDelete = async (id: number | undefined, deviceId: number) => {
  278. try {
  279. const data = await ModelTemplateApi.getIsRelated(deviceId)
  280. if (data.length === 0) {
  281. // 删除的二次确认
  282. await message.delConfirm()
  283. // 发起删除
  284. await ModelTemplateApi.deleteModelTemplate(id)
  285. message.success(t('common.delSuccess'))
  286. } else {
  287. message.error(t('form.relatedModel'))
  288. }
  289. // 刷新列表
  290. await getList()
  291. } catch {}
  292. }
  293. /** 初始化 */
  294. onMounted(() => {
  295. getList()
  296. })
  297. </script>