bindCameraModal.vue 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <template>
  2. <a-modal
  3. v-model:open="visible"
  4. :title="t('deviceAdmin.addDevice')"
  5. width="620px"
  6. :ok-text="t('common.comfirm')"
  7. :footer="null"
  8. :cancel-text="t('common.cancel')"
  9. @ok="handleSubmit"
  10. @cancel="handleCancel"
  11. :confirm-loading="loading"
  12. >
  13. <a-form ref="formRef" :model="formData" layout="vertical">
  14. <a-form-item
  15. name="sn"
  16. :rules="snRules"
  17. >
  18. <a-input
  19. size="large"
  20. v-model:value="formData.sn"
  21. :placeholder="t('deviceAdmin.deviceSnPlaceholder')"
  22. />
  23. </a-form-item>
  24. <div
  25. v-for="(item, index) in formData.snList"
  26. :key="index"
  27. class="flex items-center justify-between w-full sn-item-wrap"
  28. >
  29. <a-form-item
  30. class="flex-1 w-full"
  31. :name="['snList', index, 'sn']"
  32. :rules="snRules"
  33. >
  34. <a-input
  35. size="large"
  36. v-model:value="item.sn"
  37. :placeholder="t('deviceAdmin.deviceSnPlaceholder')"
  38. />
  39. </a-form-item>
  40. <div class="del-btn" @click="removeItem(index)">
  41. <MinusCircleFilled style="color: red; font-size: 16px" />
  42. </div>
  43. </div>
  44. </a-form>
  45. <div class="flex justify-between ant-modal-footer modal-footer">
  46. <a-button type="primary" ghost @click="addItem">
  47. +{{ t('mall.myOrders.bindCameraModule.reNewDevice') }}
  48. </a-button>
  49. <div class="btn-group">
  50. <a-button style="margin-right: 16px" @click="handleCancel">{{ t('common.cancel') }}</a-button>
  51. <a-button type="primary" @click="handleSubmit">{{ t('common.comfirm') }}</a-button>
  52. </div>
  53. </div>
  54. </a-modal>
  55. </template>
  56. <script setup>
  57. import { ref, reactive, watch, computed } from "vue";
  58. import { useI18n } from "vue-i18n";
  59. import {
  60. MinusCircleFilled,
  61. } from "@ant-design/icons-vue";
  62. import { message } from "ant-design-vue";
  63. import { cameraAdd } from "@/api/equity";
  64. const { t } = useI18n();
  65. const props = defineProps({
  66. open: {
  67. type: Boolean,
  68. default: false,
  69. },
  70. cameraType: {
  71. type: Number,
  72. default: null,
  73. }
  74. });
  75. const emit = defineEmits(["update:open", "confirm"]);
  76. const visible = ref(props.open);
  77. const loading = ref(false);
  78. const formRef = ref();
  79. const formData = reactive({
  80. snList: [],
  81. sn: "",
  82. });
  83. const snRules = computed(() => [{
  84. required: true,
  85. message: t('deviceAdmin.deviceSnPlaceholder'),
  86. trigger: 'blur',
  87. }]);
  88. const addItem = () => {
  89. formData.snList.push({ sn: "" });
  90. };
  91. const removeItem = (index) => {
  92. if (formData.snList.length <= 0) return;
  93. formData.snList.splice(index, 1);
  94. formRef.value?.clearValidate(["snList", index, "sn"]);
  95. };
  96. watch(
  97. () => props.open,
  98. (val) => {
  99. visible.value = val;
  100. if (!val) {
  101. formData.snList = [];
  102. formRef.value?.resetFields();
  103. }
  104. },
  105. { immediate: true }
  106. );
  107. const handleSubmit = async () => {
  108. try {
  109. loading.value = true;
  110. const sndata = await formRef.value?.validate();
  111. let list = formData.snList?.map((item) => item.sn) || [];
  112. list.push(sndata.sn)
  113. const snArr = formData.snList.map((item) => item.sn.trim());
  114. await cameraAdd({snCode: list.join(',') })
  115. message.success(t('common.success'));
  116. emit("confirm", snArr);
  117. emit("update:open", false);
  118. } catch (err) {
  119. console.log("validate failed", err);
  120. } finally {
  121. loading.value = false;
  122. }
  123. };
  124. const handleCancel = () => {
  125. emit("update:open", false);
  126. };
  127. </script>
  128. <style scoped lang="less">
  129. .sn-item-wrap {
  130. position: relative;
  131. margin-bottom: 4px;
  132. }
  133. .del-btn {
  134. flex-shrink: 0;
  135. width: 26px;
  136. height: 26px;
  137. border-radius: 50%;
  138. display: flex;
  139. margin-bottom: 24px;
  140. margin-left: 16px;
  141. align-items: center;
  142. justify-content: center;
  143. cursor: pointer;
  144. }
  145. </style>