index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <ele-split-layout
  5. width="266px"
  6. allow-collapse
  7. :right-style="{ overflow: 'hidden' }"
  8. >
  9. <div>
  10. <div class="ele-border-lighter sys-organization-list">
  11. <div class="tree-title">区域列表</div>
  12. <el-tree
  13. ref="areaTree"
  14. :data="areaTreeList"
  15. :props="defaultProps"
  16. node-key="id"
  17. highlight-current
  18. default-expand-all
  19. :expand-on-click-node="false"
  20. @node-click="handleAreaClick"
  21. >
  22. </el-tree>
  23. </div>
  24. </div>
  25. <template v-slot:content>
  26. <!-- 搜索表单 -->
  27. <camera-search ref="searchRef" @search="reload" />
  28. <!-- 数据表格 -->
  29. <ele-pro-table
  30. :page-size="defPageSize"
  31. ref="table"
  32. :columns="columns"
  33. :datasource="datasource"
  34. :selection.sync="selection"
  35. :cache-key="cacheKeyUrl"
  36. :pageSizes="tablePageSizes"
  37. height="calc(100vh - 320px)"
  38. full-height="calc(100vh - 115px)"
  39. :response="{
  40. dataName: 'data.records', // 数据列表的字段名称,支持嵌套,例如:data.rows
  41. countName: 'data.total' // 数据总数的字段名称,例如:data.total
  42. }"
  43. >
  44. <!-- 表头工具栏 -->
  45. <template v-slot:toolbar>
  46. <el-button
  47. type="primary"
  48. icon="el-icon-plus"
  49. class="ele-btn-icon"
  50. v-if="$hasPermission('ledgerAssets:camera:create')"
  51. @click="openForm('create')"
  52. >
  53. 新建
  54. </el-button>
  55. <el-button
  56. type="danger"
  57. icon="el-icon-delete"
  58. class="ele-btn-icon"
  59. v-if="
  60. $hasPermission('ledgerAssets:camera:delete') &&
  61. selection.length
  62. "
  63. @click="handleBatchDelete"
  64. >
  65. 批量删除
  66. </el-button>
  67. </template>
  68. <!-- 摄像机状态列 -->
  69. <template v-slot:activityStatus="{ row }">
  70. <el-switch
  71. v-model="row.activityStatus"
  72. :active-value="1"
  73. :inactive-value="0"
  74. @change="handleStatusChange(row)"
  75. />
  76. </template>
  77. <!-- 操作列 -->
  78. <template v-slot:action="{ row }">
  79. <el-link
  80. type="primary"
  81. :underline="false"
  82. icon="el-icon-edit"
  83. v-if="$hasPermission('ledgerAssets:camera:update')"
  84. @click="openForm('update', row.id)"
  85. >
  86. 编辑
  87. </el-link>
  88. <el-link
  89. type="primary"
  90. :underline="false"
  91. icon="el-icon-delete"
  92. :style="{ color: delColor }"
  93. v-if="$hasPermission('ledgerAssets:camera:delete')"
  94. @click="handleDelete(row.id)"
  95. >
  96. 删除
  97. </el-link>
  98. </template>
  99. </ele-pro-table>
  100. </template>
  101. </ele-split-layout>
  102. </el-card>
  103. <!-- 表单弹窗:添加/修改 -->
  104. <formModel ref="formRef" @success="reload" />
  105. </div>
  106. </template>
  107. <script>
  108. import * as CameraApi from '@/api/ledgerAssets/camera';
  109. import { basicAreaPageAPI } from '@/api/factoryModel';
  110. import formModel from './components/formModel.vue';
  111. import cameraSearch from './components/camera-search.vue';
  112. export default {
  113. name: 'LedgerCamera',
  114. components: {
  115. formModel,
  116. cameraSearch
  117. },
  118. data() {
  119. return {
  120. cacheKeyUrl: 'ledgerCameraTable',
  121. delColor: '#F56C6C',
  122. selection: [],
  123. loading: false,
  124. // 当前选中的区域
  125. currentArea: null,
  126. // 区域树数据
  127. areaTreeList: [],
  128. defaultProps: {
  129. children: 'children',
  130. label: 'name'
  131. },
  132. // 表格列配置
  133. columns: [
  134. {
  135. width: 45,
  136. type: 'selection',
  137. columnKey: 'selection',
  138. align: 'center',
  139. fixed: 'left'
  140. },
  141. {
  142. columnKey: 'index',
  143. label: '序号',
  144. type: 'index',
  145. width: 55,
  146. align: 'center',
  147. showOverflowTooltip: true,
  148. fixed: 'left'
  149. },
  150. {
  151. prop: 'deviceCode',
  152. label: '摄像机编号',
  153. headerAlign: 'center',
  154. align: 'center',
  155. showOverflowTooltip: true,
  156. width: 180
  157. },
  158. {
  159. prop: 'name',
  160. label: '摄像机名称',
  161. headerAlign: 'center',
  162. align: 'center',
  163. showOverflowTooltip: true,
  164. minWidth: 200
  165. },
  166. {
  167. prop: 'areaName',
  168. label: '所属区域',
  169. headerAlign: 'center',
  170. align: 'center',
  171. showOverflowTooltip: true,
  172. minWidth: 160
  173. },
  174. {
  175. prop: 'brandName',
  176. label: '设备品牌',
  177. headerAlign: 'center',
  178. align: 'center',
  179. showOverflowTooltip: true,
  180. width: 180
  181. },
  182. {
  183. prop: 'modelName',
  184. label: '设备型号',
  185. headerAlign: 'center',
  186. align: 'center',
  187. showOverflowTooltip: true,
  188. width: 180
  189. },
  190. {
  191. prop: 'classifyName',
  192. label: '摄像机类型',
  193. headerAlign: 'center',
  194. align: 'center',
  195. showOverflowTooltip: true,
  196. width: 180
  197. },
  198. // {
  199. // prop: 'loadDeviceName',
  200. // label: '关联设备',
  201. // headerAlign: 'center',
  202. // align: 'center',
  203. // showOverflowTooltip: true,
  204. // width: 150
  205. // },
  206. {
  207. prop: 'activityStatus',
  208. label: '摄像机状态',
  209. align: 'center',
  210. showOverflowTooltip: true,
  211. width: 120,
  212. slot: 'activityStatus'
  213. },
  214. {
  215. columnKey: 'action',
  216. fixed: 'right',
  217. label: '操作',
  218. width: 160,
  219. align: 'center',
  220. resizable: false,
  221. slot: 'action',
  222. showOverflowTooltip: true
  223. }
  224. ]
  225. };
  226. },
  227. created() {
  228. this.getAreaTreeList();
  229. },
  230. methods: {
  231. /* 获取区域树 */
  232. getAreaTreeList() {
  233. this.loading = true;
  234. basicAreaPageAPI({
  235. pageNum: 1,
  236. size: 9999
  237. })
  238. .then((list) => {
  239. this.areaTreeList = this.$util.toTreeData({
  240. data: list || [],
  241. idField: 'id',
  242. parentIdField: 'parentId'
  243. });
  244. })
  245. .finally(() => {
  246. this.loading = false;
  247. });
  248. },
  249. /* 点击区域节点查询 */
  250. handleAreaClick(data) {
  251. this.currentArea = data;
  252. // 记录所选区域到搜索条件并刷新
  253. this.reload({
  254. areaId: data.id
  255. });
  256. },
  257. /* 表格数据源 */
  258. async datasource({ page, limit, where }) {
  259. return await CameraApi.getDevicePage({
  260. pageNum: page,
  261. size: limit,
  262. ...where
  263. });
  264. },
  265. /* 刷新表格 */
  266. reload(where) {
  267. this.$refs.table.reload({ page: 1, where });
  268. },
  269. /** 添加/修改操作 */
  270. openForm(type, id) {
  271. this.$refs.formRef.open(type, id, this.currentArea);
  272. },
  273. /** 状态切换 */
  274. handleStatusChange(row) {
  275. const text = row.activityStatus === 1 ? '启用' : '停用';
  276. this.$confirm('确认要' + text + '摄像机"' + row.name + '"吗?', '提示', {
  277. confirmButtonText: '确定',
  278. cancelButtonText: '取消',
  279. type: 'warning'
  280. })
  281. .then(async () => {
  282. row.extInfo = row.extInfo || '{}';
  283. await CameraApi.updateDevice(row);
  284. this.$message.success(text + '成功');
  285. this.reload();
  286. })
  287. .catch(() => {
  288. row.activityStatus = row.activityStatus === 1 ? 0 : 1;
  289. });
  290. },
  291. /** 删除按钮操作 */
  292. handleDelete(id) {
  293. this.$confirm('是否确认删除该数据项?', '警告', {
  294. confirmButtonText: '确定',
  295. cancelButtonText: '取消',
  296. type: 'warning'
  297. })
  298. .then(async () => {
  299. await CameraApi.deletedDevice(id);
  300. this.$message.success('删除成功');
  301. this.reload();
  302. })
  303. .catch(() => {});
  304. },
  305. /** 批量删除按钮操作 */
  306. handleBatchDelete() {
  307. if (this.selection.length === 0) {
  308. this.$message.warning('请选择要删除的数据项');
  309. return;
  310. }
  311. this.$confirm('是否确认删除选中的数据项?', '警告', {
  312. confirmButtonText: '确定',
  313. cancelButtonText: '取消',
  314. type: 'warning'
  315. })
  316. .then(async () => {
  317. const ids = this.selection.map((item) => item.id);
  318. for (const id of ids) {
  319. await CameraApi.deletedDevice(id);
  320. }
  321. this.$message.success('删除成功');
  322. this.reload();
  323. })
  324. .catch(() => {});
  325. }
  326. }
  327. };
  328. </script>
  329. <style lang="scss" scoped>
  330. .sys-organization-list {
  331. position: absolute;
  332. top: 0;
  333. bottom: 0;
  334. left: 0;
  335. right: 0;
  336. box-sizing: border-box;
  337. border-width: 1px;
  338. border-style: solid;
  339. overflow: auto;
  340. }
  341. .tree-title {
  342. padding: 10px 12px;
  343. font-weight: bold;
  344. border-bottom: 1px solid #ebeef5;
  345. }
  346. .sys-organization-list :deep(.el-tree-node__content) {
  347. height: 36px;
  348. & > .el-tree-node__expand-icon {
  349. margin-left: 10px;
  350. }
  351. }
  352. </style>