edit.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <template>
  2. <div class="system-edit-dic-container">
  3. <el-dialog :title="(ruleForm.id !== 0 ? '修改' : '添加') + '设备'" v-model="isShowDialog" width="769px">
  4. <el-form :model="ruleForm" ref="formRef" :rules="rules" size="default" label-width="110px">
  5. <el-form-item label="设备标识" prop="key">
  6. <el-input v-model="ruleForm.key" placeholder="请输入设备标识" :disabled="ruleForm.id" />
  7. </el-form-item>
  8. <el-form-item label="设备名称" prop="name">
  9. <el-input v-model="ruleForm.name" placeholder="请输入设备名称" />
  10. </el-form-item>
  11. <el-form-item label="所属产品" prop="productId">
  12. <el-select v-model="ruleForm.productId" @change="productIdChange" :disabled="ruleForm.id" placeholder="请选择所属产品" class="w100">
  13. <el-option v-for="item in productData" :key="item.id" :label="item.name" :value="item.id" />
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="设备坐标" prop="lng">
  17. <el-input :value="ruleForm.lng ? (ruleForm.lng + ' , ' + ruleForm.lat) : ''" placeholder="选择设备坐标" @click="selectMap" read-only />
  18. </el-form-item>
  19. <el-form-item label="标签设置" prop="lng">
  20. <div class="tags-wrapper">
  21. <el-button type="primary" size="small" @click="toAddTag">添加标签</el-button>
  22. <div class="tags">
  23. <div class="tag flex" v-for="tag, i in ruleForm.tags" :key="tag.key">
  24. <el-tag>{{ tag.key }} : {{ tag.name }} : {{ tag.value }}</el-tag>
  25. <el-button type="danger" size="small" @click="delTagRow(i)">删除</el-button>
  26. </div>
  27. </div>
  28. </div>
  29. </el-form-item>
  30. <template v-if="ruleForm.authType === 1 || ruleForm.authType === 2">
  31. <el-form-item label="认证方式" prop="">
  32. <el-radio-group v-model="ruleForm.authType">
  33. <el-radio :label="1">Basic</el-radio>
  34. <el-radio :label="2">AccessToken</el-radio>
  35. </el-radio-group>
  36. </el-form-item>
  37. <template v-if="ruleForm.authType === 1">
  38. <el-form-item label="用户名" prop="authUser">
  39. <el-input v-model="ruleForm.authUser" placeholder="请输入用户名" />
  40. </el-form-item>
  41. <el-form-item label="密码" prop="authPasswd">
  42. <el-input type="password" v-model="ruleForm.authPasswd" placeholder="请输入密码" />
  43. </el-form-item>
  44. </template>
  45. <template v-else>
  46. <el-form-item label="Aceess Token" prop="accessToken">
  47. <el-input v-model="ruleForm.accessToken" placeholder="请输入Aceess Token" />
  48. </el-form-item>
  49. </template>
  50. </template>
  51. <template v-else-if="ruleForm.authType === 3">
  52. <el-form-item label="认证证书" prop="certificateId">
  53. <el-select v-model="ruleForm.certificateId" placeholder="请选择证书">
  54. <el-option v-for="cert in certList" :key="cert.id" :label="cert.name" :value="cert.id"> </el-option>
  55. </el-select>
  56. </el-form-item>
  57. </template>
  58. <el-form-item label="固件版本号" prop="version">
  59. <el-input v-model="ruleForm.version" placeholder="请输入固件版本号" />
  60. </el-form-item>
  61. <el-form-item label="备注" prop="desc">
  62. <el-input v-model="ruleForm.desc" type="textarea" placeholder="请输入内容"></el-input>
  63. </el-form-item>
  64. <el-form-item label="设备说明">
  65. <el-input v-model="intro" type="textarea" placeholder="请输入设备说明"></el-input>
  66. </el-form-item>
  67. <el-form-item label="设备图片">
  68. <upload-vue :imgs="phone" @set-imgs="setImgsPhone" :limit="deviceImgLimit"></upload-vue>
  69. </el-form-item>
  70. <el-form-item label="证书图片">
  71. <upload-vue :imgs="certificate" @set-imgs="setImgsCertificate" :limit="deviceImgLimit"></upload-vue>
  72. </el-form-item>
  73. </el-form>
  74. <template #footer>
  75. <span class="dialog-footer">
  76. <el-button @click="onCancel" size="default">取 消</el-button>
  77. <el-button type="primary" @click="onSubmit" size="default">{{ ruleForm.id !== 0 ? '修 改' : '添 加' }}</el-button>
  78. </span>
  79. </template>
  80. </el-dialog>
  81. <tagVue ref="tagRef"></tagVue>
  82. <Map ref="mapRef" @updateMap="updateMap"></Map>
  83. </div>
  84. </template>
  85. <script lang="ts">
  86. import { reactive, toRefs, defineComponent, ref, unref, nextTick, onMounted } from 'vue';
  87. import api from '/@/api/device';
  88. import apiSystem from '/@/api/system';
  89. import { ElMessage } from "element-plus";
  90. import tagVue from './tag.vue';
  91. import Map from './map.vue';
  92. import UploadVue from '/@/components/upload/index.vue';
  93. import certApi from '/@/api/certificateManagement';
  94. import { json } from 'stream/consumers';
  95. interface RuleFormState {
  96. id: number;
  97. key: string;
  98. name: string;
  99. version: string;
  100. productId: number | string;
  101. tags: Tag[];
  102. lng: string;
  103. lat: string;
  104. desc: string;
  105. authType: number;
  106. authUser: string;
  107. authPasswd: string;
  108. accessToken: string;
  109. certificateId: string;
  110. extensionInfo: string;
  111. }
  112. const form: RuleFormState = {
  113. id: 0,
  114. key: '',
  115. name: '',
  116. productId: '',
  117. tags: [],
  118. lng: '',
  119. lat: '',
  120. version: '',
  121. authType: 0,
  122. authUser: '',
  123. authPasswd: '',
  124. accessToken: '',
  125. certificateId: '',
  126. desc: '',
  127. extensionInfo: ''
  128. }
  129. interface DicState {
  130. productData: any[];
  131. product: any;
  132. isShowDialog: boolean;
  133. ruleForm: RuleFormState;
  134. rules: {};
  135. deviceImgLimit: number;
  136. certificateLimit: number;
  137. phone: any[];
  138. certificate: any[];
  139. intro: string;
  140. }
  141. interface Tag {
  142. key: string;
  143. name: string;
  144. value: string;
  145. }
  146. export default defineComponent({
  147. name: 'deviceEditPro',
  148. components: {
  149. tagVue,
  150. Map,
  151. UploadVue
  152. },
  153. setup(prop, { emit }) {
  154. const formRef = ref<HTMLElement | null>(null);
  155. const tagRef = ref<HTMLElement | null>(null);
  156. const mapRef = ref();
  157. const certList = ref([])
  158. const state = reactive<DicState>({
  159. isShowDialog: false,
  160. product: {},
  161. productData: [], // 分类数据
  162. ruleForm: {
  163. ...form
  164. },
  165. rules: {
  166. name: [
  167. { required: true, message: "设备名称不能为空", trigger: "blur" }
  168. ],
  169. key: [
  170. { required: true, message: "设备标识不能为空", trigger: "blur" }
  171. ],
  172. productId: [{ required: true, message: '所属产品不能为空', trigger: 'blur' }],
  173. },
  174. deviceImgLimit: 0,
  175. certificateLimit: 0,
  176. phone: [],
  177. certificate: [],
  178. intro: ""
  179. });
  180. //地图选点
  181. const selectMap=()=>{
  182. mapRef.value.openDialog();
  183. }
  184. // 打开弹窗
  185. const openDialog = (row: RuleFormState | null) => {
  186. resetForm();
  187. // 证书列表
  188. certApi.certificateManagement.getAll().then((res: any) => {
  189. certList.value = res.Info || []
  190. });
  191. api.product.getLists({ status: 1 }).then((res: any) => {
  192. state.productData = res.product || [];
  193. });
  194. if (row) {
  195. state.ruleForm = row;
  196. state.ruleForm.tags = row.tags || [];
  197. state.phone = row.extensionInfo ? JSON.parse(row.extensionInfo).phone : [];
  198. state.certificate = row.extensionInfo ? JSON.parse(row.extensionInfo).certificate : [];
  199. state.intro = row.extensionInfo ? JSON.parse(row.extensionInfo).intro : "";
  200. productIdChange(row.productId as number)
  201. }
  202. state.isShowDialog = true;
  203. };
  204. const resetForm = () => {
  205. state.ruleForm = {
  206. ...form
  207. }
  208. };
  209. // 上传设备图
  210. const setImgsPhone = (res:any) => {
  211. state.phone = res;
  212. }
  213. // 上传设备资格证书
  214. const setImgsCertificate = (res:any) => {
  215. state.certificate = res;
  216. }
  217. // 关闭弹窗
  218. const closeDialog = () => {
  219. state.isShowDialog = false;
  220. };
  221. // 取消
  222. const onCancel = () => {
  223. closeDialog();
  224. };
  225. // 新增
  226. const onSubmit = () => {
  227. const formWrap = unref(formRef) as any;
  228. if (!formWrap) return;
  229. formWrap.validate((valid: boolean) => {
  230. if (valid) {
  231. if (state.ruleForm.id !== 0) {
  232. //修改
  233. const params = {
  234. ...state.ruleForm,
  235. extensionInfo: JSON.stringify({
  236. "phone": state.phone,
  237. "certificate": state.certificate,
  238. "intro": state.intro
  239. })
  240. }
  241. api.instance.edit(params).then(() => {
  242. ElMessage.success('设备类型修改成功');
  243. closeDialog(); // 关闭弹窗
  244. emit('typeList')
  245. })
  246. } else {
  247. //添加
  248. const params = {
  249. ...state.ruleForm,
  250. extensionInfo: JSON.stringify({
  251. "phone": state.phone,
  252. "certificate": state.certificate,
  253. "intro": state.intro
  254. })
  255. }
  256. api.instance.add(params).then(() => {
  257. ElMessage.success('设备类型添加成功');
  258. closeDialog(); // 关闭弹窗
  259. emit('typeList')
  260. })
  261. }
  262. }
  263. });
  264. };
  265. function toAddTag() {
  266. const tag = tagRef.value as any
  267. tag.addRow()
  268. }
  269. function addTag(row: Tag) {
  270. state.ruleForm.tags.push(row)
  271. }
  272. function delTagRow(i: number) {
  273. state.ruleForm.tags.splice(i, 1)
  274. }
  275. // 所属产品变化的时候,更新产品详情
  276. const productIdChange = (productId: number) => {
  277. api.product.detail(productId).then((res: any) => {
  278. const { authType, authUser, authPasswd, accessToken, certificateId } = res.data
  279. state.product = res.data
  280. state.ruleForm.authType = authType
  281. state.ruleForm.authUser = authUser
  282. state.ruleForm.authPasswd = authPasswd
  283. state.ruleForm.accessToken = accessToken
  284. state.ruleForm.certificateId = certificateId
  285. })
  286. }
  287. //回调地图选点
  288. const updateMap=(data:any)=>{
  289. state.ruleForm.lng = data.lng;
  290. state.ruleForm.lat = data.lat;
  291. }
  292. onMounted(() => {
  293. apiSystem.getInfoByKey({ ConfigKey: 'sys.device.phone.limit' }).then((res: any) => {
  294. state.deviceImgLimit = parseInt(res.data.configValue);
  295. });
  296. apiSystem.getInfoByKey({ ConfigKey: 'sys.device.certificate.limit' }).then((res: any) => {
  297. state.certificateLimit = parseInt(res.data.configValue);
  298. });
  299. })
  300. return {
  301. certList,
  302. productIdChange,
  303. tagRef,
  304. selectMap,
  305. mapRef,
  306. updateMap,
  307. delTagRow,
  308. toAddTag,
  309. addTag,
  310. openDialog,
  311. closeDialog,
  312. onCancel,
  313. onSubmit,
  314. setImgsPhone,
  315. setImgsCertificate,
  316. formRef,
  317. ...toRefs(state),
  318. };
  319. },
  320. });
  321. </script>
  322. <style lang="scss" scoped>
  323. .tags-wrapper {
  324. .tag {
  325. margin: 8px 0;
  326. }
  327. .tags {
  328. .el-button {
  329. margin-left: 10px;
  330. }
  331. }
  332. }
  333. </style>