|
|
@@ -15,7 +15,7 @@ import {
|
|
|
} from '@/api/storehouse'
|
|
|
import {User_List} from '@/api/user/index';
|
|
|
import TableBase from '@/components/TableBase/index.vue'
|
|
|
-import {computed, nextTick, onMounted, reactive, ref} from 'vue'
|
|
|
+import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
|
|
|
import {GlobalStore} from '@/stores'
|
|
|
import type {ColumnProps} from '@/components/TableBase/interface'
|
|
|
import {Delete, Edit, View} from '@element-plus/icons-vue'
|
|
|
@@ -208,6 +208,9 @@ const exportOperationExcel = async () => {
|
|
|
const showInStorageForm = ref(false)
|
|
|
const dialogTableVisible = ref(false)
|
|
|
const operationVisible = ref(false)
|
|
|
+const showBatchInputDialog = ref(false)
|
|
|
+const batchInputType = ref<'inStorage' | 'lend'>('inStorage')
|
|
|
+const batchSNText = ref('')
|
|
|
|
|
|
const inStorageFormRef = ref<FormInstance | null>(null)
|
|
|
const inStorageForm = reactive({
|
|
|
@@ -221,6 +224,7 @@ interface InStorageItem {
|
|
|
T_sn: string
|
|
|
Validationnumber: string
|
|
|
T_remark: string
|
|
|
+ T_class?: string | null
|
|
|
}
|
|
|
|
|
|
// 获取设备类型
|
|
|
@@ -258,6 +262,163 @@ const extractSN = (fullSN: string): string => {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 批量处理SN数据
|
|
|
+ * 去除前2个字符(03)和后6个字符(000001)
|
|
|
+ */
|
|
|
+const processBatchSN = (text: string): string[] => {
|
|
|
+ const lines = text.split('\n').map(line => line.trim()).filter(line => line.length > 0)
|
|
|
+ return lines.map(line => {
|
|
|
+ // 只有当前缀为03且后缀为000001时才截取中间值
|
|
|
+ if (line.startsWith('03') && line.endsWith('000001') && line.length > 8) {
|
|
|
+ return line.substring(2, line.length - 6).trim()
|
|
|
+ }
|
|
|
+ return line.trim()
|
|
|
+ }).filter(sn => sn.length > 0)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 打开批量录入对话框
|
|
|
+ */
|
|
|
+const openBatchInputDialog = (type: 'inStorage' | 'lend') => {
|
|
|
+ batchInputType.value = type
|
|
|
+ batchSNText.value = ''
|
|
|
+ showBatchInputDialog.value = true
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 提交批量录入的SN
|
|
|
+ */
|
|
|
+const submitBatchSN = async () => {
|
|
|
+ if (!batchSNText.value.trim()) {
|
|
|
+ ElMessage.warning('请输入SN数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const processedSNs = processBatchSN(batchSNText.value)
|
|
|
+ if (processedSNs.length === 0) {
|
|
|
+ ElMessage.warning('没有有效的SN数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ let successCount = 0
|
|
|
+ let failCount = 0
|
|
|
+ const failMessages: string[] = []
|
|
|
+
|
|
|
+ if (batchInputType.value === 'inStorage') {
|
|
|
+ // 入库批量处理
|
|
|
+ for (const sn of processedSNs) {
|
|
|
+ try {
|
|
|
+ // 检查是否已存在
|
|
|
+ if (pendingItems.value.some((item: any) => item.T_sn === sn)) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 已存在`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 检查是否已入库
|
|
|
+ const result: any = await readValidation({sn: sn})
|
|
|
+ if ((result.Code == 200) && (result.Data.T_state == 2)) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 已入库不能重复入库`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 添加到待提交列表
|
|
|
+ pendingItems.value.unshift({
|
|
|
+ T_sn: sn,
|
|
|
+ Validationnumber: inStorageForm.Validationnumber || '',
|
|
|
+ T_remark: inStorageForm.T_remark || '',
|
|
|
+ T_class: inStorageForm.T_class || null
|
|
|
+ })
|
|
|
+ successCount++
|
|
|
+ } catch (error: any) {
|
|
|
+ failCount++
|
|
|
+ const errorMsg = error?.message || error?.toString() || '未知错误'
|
|
|
+ failMessages.push(`SN ${sn} 处理失败: ${errorMsg}`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 借出批量处理
|
|
|
+ for (const sn of processedSNs) {
|
|
|
+ try {
|
|
|
+ // 检查是否已存在
|
|
|
+ if (pendingLendItems.value.some((item: any) => item.T_sn === sn)) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 已存在`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 检查SN状态
|
|
|
+ const result: any = await readValidation({sn: sn})
|
|
|
+ if (result.Code !== 200) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 未入库不能借出`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (result.Data.T_state == 5) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 设备已损坏`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (result.Data.T_state != 2) {
|
|
|
+ failCount++
|
|
|
+ failMessages.push(`SN ${sn} 未入库不能借出`)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 添加到待提交列表
|
|
|
+ pendingLendItems.value.unshift({
|
|
|
+ T_sn: sn,
|
|
|
+ Validationnumber: lendForm.Validationnumber || '',
|
|
|
+ T_remark: lendForm.T_remark || '',
|
|
|
+ LendUser: lendForm.LendUser || '',
|
|
|
+ T_project: lendForm.T_project || ''
|
|
|
+ })
|
|
|
+ successCount++
|
|
|
+ } catch (error: any) {
|
|
|
+ failCount++
|
|
|
+ const errorMsg = error?.message || error?.toString() || '未知错误'
|
|
|
+ failMessages.push(`SN ${sn} 处理失败: ${errorMsg}`)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 去重
|
|
|
+ pendingLendItems.value = pendingLendItems.value.filter((value: any, index: any, self: any) => {
|
|
|
+ return self.findIndex((t: any) => (t.T_sn === value.T_sn)) === index;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 显示处理结果
|
|
|
+ if (successCount > 0) {
|
|
|
+ ElMessage.success(`成功添加 ${successCount} 条SN数据`)
|
|
|
+ if ('speechSynthesis' in window) {
|
|
|
+ const utterance = new SpeechSynthesisUtterance(`成功添加${successCount}条数据`)
|
|
|
+ window.speechSynthesis.speak(utterance)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (failCount > 0) {
|
|
|
+ // 显示详细的失败原因
|
|
|
+ const failMessageHTML = `<div style="margin-top: 10px;">
|
|
|
+ <p style="margin-bottom: 15px; font-weight: 500; color: #303133;">有 ${failCount} 条SN数据处理失败,具体原因如下:</p>
|
|
|
+ <div style="max-height: 400px; overflow-y: auto; padding-right: 5px;">
|
|
|
+ ${failMessages.map((msg, index) => `<div style="padding: 10px 0; border-bottom: 1px solid #ebeef5; line-height: 1.8;">
|
|
|
+ <span style="color: #909399; margin-right: 10px; font-weight: 500;">${index + 1}.</span>
|
|
|
+ <span style="color: #606266;">${msg}</span>
|
|
|
+ </div>`).join('')}
|
|
|
+ </div>
|
|
|
+ </div>`
|
|
|
+ ElMessageBox.alert(
|
|
|
+ failMessageHTML,
|
|
|
+ '批量录入失败详情',
|
|
|
+ {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ type: 'warning',
|
|
|
+ dangerouslyUseHTMLString: true
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ // 关闭对话框并清空输入
|
|
|
+ showBatchInputDialog.value = false
|
|
|
+ batchSNText.value = ''
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
* 处理SN输入,自动提取中间数据并更新输入框显示
|
|
|
* @param formType 表单类型:'inStorageForm' | 'lendForm' | 'editForm'
|
|
|
*/
|
|
|
@@ -364,6 +525,25 @@ const lendForm = reactive({
|
|
|
T_project: ''
|
|
|
})
|
|
|
|
|
|
+// 同步“借出人”和“借出项目”到下方待提交表格
|
|
|
+watch(
|
|
|
+ () => lendForm.LendUser,
|
|
|
+ (newVal) => {
|
|
|
+ pendingLendItems.value.forEach((item) => {
|
|
|
+ item.LendUser = newVal || ''
|
|
|
+ })
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => lendForm.T_project,
|
|
|
+ (newVal) => {
|
|
|
+ pendingLendItems.value.forEach((item) => {
|
|
|
+ item.T_project = newVal || ''
|
|
|
+ })
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
interface LendItem {
|
|
|
T_sn: string
|
|
|
Validationnumber: string
|
|
|
@@ -800,7 +980,12 @@ onMounted(() => {
|
|
|
<el-dialog title="入库" v-model="showInStorageForm" width="50%">
|
|
|
<el-form :model="inStorageForm" :rules="rules" ref="inStorageFormRef">
|
|
|
<el-form-item label="SN" prop="T_sn">
|
|
|
- <el-input v-model="inStorageForm.T_sn" placeholder="请输入SN" @keyup.enter="submitInStorageForm" @input="handleSNInput('inStorageForm')"></el-input>
|
|
|
+ <el-input
|
|
|
+ v-model="inStorageForm.T_sn"
|
|
|
+ placeholder="请输入SN"
|
|
|
+ @keyup.enter="submitInStorageForm"
|
|
|
+ @input="handleSNInput('inStorageForm')"
|
|
|
+ />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="设备编号" prop="Validationnumber">
|
|
|
<el-input v-model="inStorageForm.Validationnumber" placeholder="请输入设备编号"></el-input>
|
|
|
@@ -877,7 +1062,11 @@ onMounted(() => {
|
|
|
<el-input v-model="lendForm.T_project" placeholder="请输入借出项目"></el-input>
|
|
|
</el-form-item>
|
|
|
<el-form-item class="m-b-6" :label-width="formLabelWidth" label="SN" prop="T_sn">
|
|
|
- <el-input v-model="lendForm.T_sn" placeholder="请输入SN" @keyup.enter="submitLendForm" @input="handleSNInput('lendForm')"></el-input>
|
|
|
+ <el-input v-model="lendForm.T_sn" placeholder="请输入SN" @keyup.enter="submitLendForm" @input="handleSNInput('lendForm')">
|
|
|
+ <template #append>
|
|
|
+ <el-button type="primary" @click="openBatchInputDialog('lend')">批量录入</el-button>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
</el-form-item>
|
|
|
<el-form-item class="m-b-6" :label-width="formLabelWidth" label="备注">
|
|
|
<el-input v-model="lendForm.T_remark" type="textarea" placeholder="请输入备注"></el-input>
|
|
|
@@ -1175,6 +1364,27 @@ onMounted(() => {
|
|
|
</Drawer>
|
|
|
<snAdd ref="btnRef" @successFun="successFun"></snAdd>
|
|
|
|
|
|
+ <!-- 批量录入SN对话框 -->
|
|
|
+ <el-dialog title="批量录入SN" v-model="showBatchInputDialog" width="60%">
|
|
|
+ <div style="margin-bottom: 10px;">
|
|
|
+ <p style="color: #909399; font-size: 12px;">
|
|
|
+ 提示:每行输入一个SN,系统会自动去除前2个字符(03)和后6个字符(000001)
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ v-model="batchSNText"
|
|
|
+ type="textarea"
|
|
|
+ :rows="10"
|
|
|
+ placeholder="请输入SN数据,每行一个,例如: 032025138451413256000001 032025144612387706000001"
|
|
|
+ />
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button @click="showBatchInputDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="submitBatchSN">确认添加</el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
</div>
|
|
|
</template>
|
|
|
|