InStorageEditSn.vue 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <script setup lang="ts">
  2. import { ref, reactive, nextTick } from 'vue'
  3. import * as XLSX from 'xlsx';
  4. import { Delete } from '@element-plus/icons-vue'
  5. import Drawer from '@/components/Drawer/index.vue'
  6. import type { FormInstance, FormRules } from 'element-plus'
  7. import { Storehouse_Device_Check } from '@/api/storehouse/index'
  8. import { ElMessage } from 'element-plus'
  9. type Fn = () => void
  10. interface FormSnType {
  11. Id?: number
  12. sn: string
  13. type?: number
  14. }
  15. const snTable = ref()
  16. const SNDataMap = new Map<number, FormSnType[]>()
  17. const tableSnData = ref<FormSnType[]>([])
  18. const ruleSnFormRef = ref<FormInstance>()
  19. const drawerSnRef = ref<InstanceType<typeof Drawer> | null>(null)
  20. const snColumns = [
  21. { type: 'index', label: '序号', width: 80, align: 'center ' },
  22. { label: 'SN', prop: 'sn', align: 'center ' },
  23. { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
  24. ]
  25. const formSn = reactive<FormSnType>({
  26. Id: undefined,
  27. sn: '',
  28. type: undefined
  29. })
  30. const rulesSn = reactive<FormRules>({
  31. sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
  32. })
  33. const addSn = (formEl: FormInstance | undefined) => {
  34. if (!formEl) return
  35. formEl.validate(async valid => {
  36. if (valid) {
  37. if (formSn.sn.length === 16 || formSn.sn.length === 24) {
  38. if(formSn.sn.length==24){
  39. formSn.sn = formSn.sn.substring(2, formSn.sn.length - 6)
  40. }
  41. const res: any = await Storehouse_Device_Check({ T_sn: formSn.sn, T_type: formSn.type })
  42. if (res.Code === 200) {
  43. tableSnData.value.unshift({ sn: formSn.sn })
  44. tableSnData.value = tableSnData.value.filter((value, index, self) => { //去重
  45. return self.findIndex(t => (t.sn === value.sn)) === index;
  46. });
  47. nextTick(() => {
  48. resetSnForm(ruleSnFormRef.value)
  49. })
  50. }
  51. } else {
  52. ElMessage.error('扫描设备异常')
  53. nextTick(() => {
  54. resetSnForm(ruleSnFormRef.value)
  55. })
  56. return
  57. }
  58. }
  59. })
  60. }
  61. const deleteSn = (row: any) => {
  62. const index = tableSnData.value.findIndex((item: any) => row.sn === item.sn)
  63. tableSnData.value.splice(index, 1)
  64. }
  65. const callbackSnDrawer = (done: Fn) => {
  66. SNDataMap.set(formSn.Id as number, tableSnData.value)
  67. let arrs = tableSnData.value.map((item:any) => item.sn);
  68. emit('onCount', SNDataMap.get(formSn.Id as number)?.length, formSn.Id as number,arrs)
  69. done()
  70. nextTick(() => {
  71. resetSnForm(ruleSnFormRef.value)
  72. tableSnData.value = []
  73. })
  74. }
  75. const emit = defineEmits<{ (event: 'onCount', value: any, id: number,mapArr:any): void }>()
  76. const resetSnForm = (formEl: FormInstance | undefined) => {
  77. if (!formEl) return
  78. formEl.resetFields()
  79. }
  80. const addDeviceSn = (id: number, type: number) => {
  81. console.log('1212',id,type)
  82. formSn.Id = id
  83. formSn.type = type
  84. if (SNDataMap.has(id)) {
  85. tableSnData.value = SNDataMap.get(id) as FormSnType[]
  86. } else {
  87. SNDataMap.set(id, [])
  88. }
  89. drawerSnRef.value?.openDrawer()
  90. }
  91. const drawer = ref(false)
  92. /**
  93. * 导入xlsx
  94. */
  95. // 组件状态变化的回调
  96. const uploadExcelFile = (event:any) => {
  97. const files = event.target.files;
  98. if (files.length === 0) return;
  99. const file = files[0];
  100. const reader = new FileReader();
  101. reader.onload = (e:any) => {
  102. const data = new Uint8Array(e.target.result);
  103. const workbook = XLSX.read(data, { type: 'array' });
  104. // 假设我们知道第一个工作表包含我们需要的数据
  105. const firstSheetName = workbook.SheetNames[0];
  106. const worksheet:any = workbook.Sheets[firstSheetName];
  107. // 假设我们知道 t_sn 是第一列
  108. const tSnColumn = 'A'; // 或者使用 XLSX.utils.decode_col(columnNumber) 来从列号获取列名
  109. const columnNumber = XLSX.utils.decode_col(tSnColumn); // 但实际上我们可能直接知道列号,如 0
  110. // 使用 sheet_to_json 但只选择我们需要的列
  111. const json = XLSX.utils.sheet_to_json(worksheet, { header: 1, range: XLSX.utils.decode_range(worksheet['!ref']) });
  112. // 如果表头不是第一行,或者你不想要表头,可以调整 header 选项
  113. // 提取 t_sn 列的数据(假设表头在第一行,且 t_sn 是第一列)
  114. let tSnData:any = json.map((row:any) => row[0]); // 假设 t_sn 是第一列,所以使用 row[0]
  115. let snArray = tSnData.map((sn:any) => ({ sn: sn }));
  116. snArray = snArray.slice(1)
  117. let arrs = [...tableSnData.value,...snArray]
  118. // 去重
  119. let seen = new Set();
  120. tableSnData.value = arrs.filter((item:any) => {
  121. return seen.has(item.sn) ? false : seen.add(item.sn) || true;
  122. });
  123. console.log('打印',tableSnData.value)
  124. // 注意:如果 t_sn 列不是第一列,你需要调整索引号
  125. // 例如,如果 t_sn 是第三列,则使用 row[2]
  126. };
  127. reader.readAsArrayBuffer(file);
  128. };
  129. const getDeviceSn = () => SNDataMap
  130. const clearDeviceSn = () => SNDataMap.clear()
  131. const deleteDeviceSn = (id: number) => SNDataMap.delete(id)
  132. defineExpose({
  133. getDeviceSn,
  134. addDeviceSn,
  135. clearDeviceSn,
  136. deleteDeviceSn,tableSnData,drawerSnRef
  137. })
  138. </script>
  139. <template>
  140. <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
  141. <el-card class="box-card" shadow="never">
  142. <template #header>
  143. <div class="sn-header">
  144. <el-form ref="ruleSnFormRef" :model="formSn" :rules="rulesSn">
  145. <el-form-item label="SN:" label-width="120px" prop="sn">
  146. <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn(ruleSnFormRef)" class="w-50" />
  147. </el-form-item>
  148. </el-form>
  149. <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
  150. <el-button type="success" @click="drawer = true">导入xlsx</el-button>
  151. </div>
  152. </template>
  153. <div>数量:{{ tableSnData.length }}</div>
  154. <el-table
  155. ref="snTable"
  156. :data="tableSnData"
  157. style="width: 100%; height: 99%"
  158. :header-cell-style="{
  159. background: '#dedfe0',
  160. height: '50px'
  161. }"
  162. >
  163. <template v-for="item in snColumns" :key="item">
  164. <el-table-column v-if="item.type === 'index'" v-bind="item" />
  165. <el-table-column show-overflow-tooltip v-if="item.prop" align="center" v-bind="item">
  166. <template #default="{ row }">
  167. <el-button
  168. v-if="item.prop === 'operation'"
  169. link
  170. type="danger"
  171. size="small"
  172. :icon="Delete"
  173. @click="deleteSn(row)"
  174. >删除</el-button
  175. >
  176. </template>
  177. </el-table-column>
  178. </template>
  179. </el-table>
  180. </el-card>
  181. <el-drawer v-model="drawer" title="导入xlsx" size="50%" :destroy-on-close="true">
  182. <input type="file" @change="uploadExcelFile" accept=".xlsx, .xls" />
  183. </el-drawer>
  184. </Drawer>
  185. </template>
  186. <style scoped lang="scss">
  187. .box-card {
  188. height: 100%;
  189. :deep(.el-card__body) {
  190. height: calc(100% - 70px);
  191. }
  192. .sn-header {
  193. display: flex;
  194. justify-content: end;
  195. }
  196. }
  197. </style>