迁移托盘登录模块
- 新增计划与生产托盘登录 V2 页面 - 新增托盘登录接口、旧路径路由和中英文文案 - 更新迁移任务列表中的托盘登录状态
This commit is contained in:
@@ -3,8 +3,8 @@
|
|||||||
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
> 根据 `后台Webman界面截图对照表.md` 生成。状态以当前 V2 项目中已落地的页面目录为准。
|
||||||
|
|
||||||
- 总功能数:79
|
- 总功能数:79
|
||||||
- 已迁移:24
|
- 已迁移:25
|
||||||
- 未迁移:55
|
- 未迁移:54
|
||||||
|
|
||||||
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
| 状态 | 一级模块 | 二级模块 | 三级模块 | 功能说明 | V2 目标路径 |
|
||||||
|:---:|---|---|---|---|---|
|
|:---:|---|---|---|---|---|
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 物料监控 (Material Monitoring) | 物料监控 | 待确认 |
|
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 物料监控 (Material Monitoring) | 物料监控 | 待确认 |
|
||||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池复投管理 (Rework Management) | 返工管理 | 待确认 |
|
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池复投管理 (Rework Management) | 返工管理 | 待确认 |
|
||||||
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘管理 (Tray Management) | 托盘管理 | `src/views/planning-production/production-monitoring/tray-management/` |
|
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘管理 (Tray Management) | 托盘管理 | `src/views/planning-production/production-monitoring/tray-management/` |
|
||||||
| ⬜ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘登录 (Tray Registration) | 托盘登记 | 待确认 |
|
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 托盘登录 (Tray Registration) | 托盘登记 | `src/views/planning-production/production-monitoring/tray-registration/` |
|
||||||
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 设备监控 (Equipment Monitoring) | 设备监控 | `src/views/planning-production/production-monitoring/equipment-monitoring/` |
|
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 设备监控 (Equipment Monitoring) | 设备监控 | `src/views/planning-production/production-monitoring/equipment-monitoring/` |
|
||||||
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池工序管理 (Process Execution) | 工序管理 | `src/views/planning-production/production-monitoring/process-execution/` |
|
| ✅ | 计划与生产 (Planning & Production) | 生产监控 (Production Monitoring) | 电池工序管理 (Process Execution) | 工序管理 | `src/views/planning-production/production-monitoring/process-execution/` |
|
||||||
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 检验类别管理 (Inspection Type Management) | | 待确认 |
|
| ⬜ | 质量管理 (Quality Management) | 过程控制 (Process Control) | 检验类别管理 (Inspection Type Management) | | 待确认 |
|
||||||
|
|||||||
51
src/api/planning-production/tray-registration.js
Normal file
51
src/api/planning-production/tray-registration.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { request } from '@/api/_service'
|
||||||
|
|
||||||
|
const BASE = 'planning_production/produce/tray_login/'
|
||||||
|
|
||||||
|
function apiParams (method, data = {}) {
|
||||||
|
return {
|
||||||
|
method,
|
||||||
|
platform: 'background',
|
||||||
|
...data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBatchAll (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'all',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('planning_production_produce_traylogin_all', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBatchTrayFormatAll (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'trayformat_all',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('planning_production_produce_trayformat_all', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBatchTrayFormat (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'create',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('planning_production_produce_trayformat_create', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteBatchTrayFormat (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'delete',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('planning_production_produce_trayformat_delete', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkBatteryid (data) {
|
||||||
|
return request({
|
||||||
|
url: BASE + 'check_batteryid',
|
||||||
|
method: 'get',
|
||||||
|
params: apiParams('planning_production_produce_trayformat_check_batteryid', data)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1010,6 +1010,73 @@
|
|||||||
"exception": "Exception",
|
"exception": "Exception",
|
||||||
"offline": "Offline",
|
"offline": "Offline",
|
||||||
"idle": "Waiting for Material"
|
"idle": "Waiting for Material"
|
||||||
|
},
|
||||||
|
"tray_registration": {
|
||||||
|
"query": "Search",
|
||||||
|
"reset": "Reset",
|
||||||
|
"login": "Register",
|
||||||
|
"tray_unbind": "Unbind Tray",
|
||||||
|
"tray_stop": "Stop Tray",
|
||||||
|
"add": "Add",
|
||||||
|
"delete": "Delete",
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"prompt": "Notice",
|
||||||
|
"data_table": "Data Table",
|
||||||
|
"process_channel": "Channel",
|
||||||
|
"battery_id": "Battery ID",
|
||||||
|
"previous_batch": "Previous Batch",
|
||||||
|
"previous_tray": "Previous Tray",
|
||||||
|
"completed_process": "Completed Process",
|
||||||
|
"tray_barcode_format": "Tray Barcode Format",
|
||||||
|
"battery_barcode_format": "Battery Barcode Format",
|
||||||
|
"tray_battery_count": "Tray Capacity",
|
||||||
|
"operation": "Actions",
|
||||||
|
"batch_no": "Batch No.",
|
||||||
|
"enter_batch_no": "Enter batch number",
|
||||||
|
"tray_code": "Tray Code",
|
||||||
|
"enter_tray_code": "Enter tray code",
|
||||||
|
"battery_code": "Battery Code",
|
||||||
|
"enter_battery_code": "Enter battery code",
|
||||||
|
"tray_code_format": "Tray Code Format",
|
||||||
|
"battery_code_format": "Battery Code Format",
|
||||||
|
"tray_battery_format_edit": "Tray & Battery Format Editor",
|
||||||
|
"format_dialog_title": "Tray & Battery Format",
|
||||||
|
"submit_login": "Submit Registration",
|
||||||
|
"add_format_title": "Add Format",
|
||||||
|
"format_error": "Invalid format",
|
||||||
|
"process_flow_name": "Process Flow Name",
|
||||||
|
"format_error_exclamation": "Invalid format!",
|
||||||
|
"insert_duplicate_battery": "Duplicate battery",
|
||||||
|
"delete_confirm": "Delete this format?",
|
||||||
|
"delete_success": "Deleted successfully",
|
||||||
|
"add_tray_format": "Add tray format",
|
||||||
|
"add_battery_format": "Add battery format",
|
||||||
|
"add_battery_count": "Add battery count",
|
||||||
|
"tray_unbind_desc": "Note: unbinding deactivates the tray, but batteries remain activated.",
|
||||||
|
"tray_unbind_success": "Tray unbound successfully",
|
||||||
|
"tray_stop_desc": "Note: stopping deactivates both tray and batteries.",
|
||||||
|
"tray_stop_success": "Tray stopped successfully",
|
||||||
|
"enter_tray_no": "Enter tray number",
|
||||||
|
"batch_create_time": "Batch Create Time",
|
||||||
|
"tray_load_battery_count": "Loaded Count",
|
||||||
|
"batch_deactivate": "Batch Deactivate",
|
||||||
|
"please_enter_tray_code": "Please enter tray code",
|
||||||
|
"upload_success": "Upload successful",
|
||||||
|
"no_batch_no": "No batch number",
|
||||||
|
"has_active_battery_login_forbidden": "Cannot register: contains activated batteries.",
|
||||||
|
"select_battery_to_deactivate": "Select batteries to deactivate",
|
||||||
|
"battery_deactivate": "Battery Deactivation",
|
||||||
|
"batch_battery_deactivate_success": "Batch deactivation successful",
|
||||||
|
"channel": "Channel:",
|
||||||
|
"select_format": "Select format",
|
||||||
|
"select_format_first": "Select tray and battery format first",
|
||||||
|
"activation_status": "Activation Status",
|
||||||
|
"activated": "Activated",
|
||||||
|
"not_activated": "Not Activated",
|
||||||
|
"operation_success": "Operation successful",
|
||||||
|
"operation_failed": "Operation failed",
|
||||||
|
"format_rule": "Format rule: fixed characters are literal; use * for variable characters, e.g. A** or ******."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"alert_center": {
|
"alert_center": {
|
||||||
|
|||||||
@@ -1010,6 +1010,73 @@
|
|||||||
"exception": "异常中",
|
"exception": "异常中",
|
||||||
"offline": "离线中",
|
"offline": "离线中",
|
||||||
"idle": "待料中"
|
"idle": "待料中"
|
||||||
|
},
|
||||||
|
"tray_registration": {
|
||||||
|
"query": "查询",
|
||||||
|
"reset": "重置",
|
||||||
|
"login": "登录",
|
||||||
|
"tray_unbind": "托盘解绑",
|
||||||
|
"tray_stop": "托盘停止",
|
||||||
|
"add": "新增",
|
||||||
|
"delete": "删除",
|
||||||
|
"confirm": "确定",
|
||||||
|
"cancel": "取消",
|
||||||
|
"prompt": "提示",
|
||||||
|
"data_table": "数据表",
|
||||||
|
"process_channel": "通道",
|
||||||
|
"battery_id": "电池ID",
|
||||||
|
"previous_batch": "上一个批次",
|
||||||
|
"previous_tray": "上一个托盘",
|
||||||
|
"completed_process": "电池已完成工序",
|
||||||
|
"tray_barcode_format": "托盘条码格式",
|
||||||
|
"battery_barcode_format": "电池条码格式",
|
||||||
|
"tray_battery_count": "托盘装载电池数量",
|
||||||
|
"operation": "操作",
|
||||||
|
"batch_no": "批次号",
|
||||||
|
"enter_batch_no": "请输入批次号",
|
||||||
|
"tray_code": "托盘编码",
|
||||||
|
"enter_tray_code": "请输入托盘编码",
|
||||||
|
"battery_code": "电池编码",
|
||||||
|
"enter_battery_code": "请输入电池编码",
|
||||||
|
"tray_code_format": "托盘编码格式",
|
||||||
|
"battery_code_format": "电池编码格式",
|
||||||
|
"tray_battery_format_edit": "托盘与电池格式编辑",
|
||||||
|
"format_dialog_title": "托盘与电池格式",
|
||||||
|
"submit_login": "提交登录",
|
||||||
|
"add_format_title": "新增格式",
|
||||||
|
"format_error": "格式不对",
|
||||||
|
"process_flow_name": "工艺流程名称",
|
||||||
|
"format_error_exclamation": "格式不对!",
|
||||||
|
"insert_duplicate_battery": "插入重复电池",
|
||||||
|
"delete_confirm": "删除这条格式?",
|
||||||
|
"delete_success": "删除成功",
|
||||||
|
"add_tray_format": "请添加托盘格式",
|
||||||
|
"add_battery_format": "请添加电池格式",
|
||||||
|
"add_battery_count": "请添加电池数量",
|
||||||
|
"tray_unbind_desc": "说明:托盘解绑后,该托盘的状态是取消激活的,与它装载的电池还是激活状态",
|
||||||
|
"tray_unbind_success": "托盘解绑成功",
|
||||||
|
"tray_stop_desc": "说明:托盘停止后,该托盘和它装载的电池会一同取消激活",
|
||||||
|
"tray_stop_success": "托盘停止成功",
|
||||||
|
"enter_tray_no": "请输入托盘号",
|
||||||
|
"batch_create_time": "批次创建时间",
|
||||||
|
"tray_load_battery_count": "装载电池数量",
|
||||||
|
"batch_deactivate": "批量取消激活",
|
||||||
|
"please_enter_tray_code": "请填写托盘编码",
|
||||||
|
"upload_success": "上传成功",
|
||||||
|
"no_batch_no": "没有批次号",
|
||||||
|
"has_active_battery_login_forbidden": "有电池属于激活状态,无法登录",
|
||||||
|
"select_battery_to_deactivate": "请选择需要取消激活的电池",
|
||||||
|
"battery_deactivate": "电池取消激活",
|
||||||
|
"batch_battery_deactivate_success": "批量取消电池激活成功",
|
||||||
|
"channel": "通道:",
|
||||||
|
"select_format": "请选择格式",
|
||||||
|
"select_format_first": "请先选择托盘与电池格式",
|
||||||
|
"activation_status": "激活状态",
|
||||||
|
"activated": "已激活",
|
||||||
|
"not_activated": "未激活",
|
||||||
|
"operation_success": "操作成功",
|
||||||
|
"operation_failed": "操作失败",
|
||||||
|
"format_rule": "格式规则:固定字符直接填写,可变字符使用 * 代替,例如 A** 或 ******。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"alert_center": {
|
"alert_center": {
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ export default {
|
|||||||
meta: { ...meta, cache: true, title: '托盘管理' },
|
meta: { ...meta, cache: true, title: '托盘管理' },
|
||||||
component: _import('planning-production/production-monitoring/tray-management')
|
component: _import('planning-production/production-monitoring/tray-management')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'produce/monitor/tray_login',
|
||||||
|
name: `${pre}monitor-tray_login`,
|
||||||
|
meta: { ...meta, cache: true, title: '托盘登录' },
|
||||||
|
component: _import('planning-production/production-monitoring/tray-registration')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'produce/monitor/device',
|
path: 'produce/monitor/device',
|
||||||
name: `${pre}monitor-device`,
|
name: `${pre}monitor-device`,
|
||||||
|
|||||||
@@ -0,0 +1,695 @@
|
|||||||
|
<template>
|
||||||
|
<d2-container>
|
||||||
|
<template #header>
|
||||||
|
<div class="search-bar">
|
||||||
|
<el-form ref="form" :inline="true" :model="form" size="mini">
|
||||||
|
<el-form-item :label="$t(key('batch_no'))" prop="batch">
|
||||||
|
<el-input
|
||||||
|
v-model="form.batch"
|
||||||
|
:placeholder="$t(key('enter_batch_no'))"
|
||||||
|
clearable
|
||||||
|
readonly
|
||||||
|
style="width:220px"
|
||||||
|
@focus="openBatchDialog"
|
||||||
|
>
|
||||||
|
<el-button slot="append" icon="el-icon-search" @click="openBatchDialog" />
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('tray_code_format'))">
|
||||||
|
<el-select
|
||||||
|
v-model="selectedFormatId"
|
||||||
|
:placeholder="$t(key('select_format'))"
|
||||||
|
filterable
|
||||||
|
style="width:220px"
|
||||||
|
@change="selectFormat"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in formatList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="formatLabel(item)"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('tray_code'))" prop="tray">
|
||||||
|
<el-input
|
||||||
|
v-model="form.tray"
|
||||||
|
:placeholder="$t(key('enter_tray_code'))"
|
||||||
|
:disabled="!currentFormat"
|
||||||
|
clearable
|
||||||
|
style="width:220px"
|
||||||
|
@keyup.enter.native="focusFirstChannel"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-check" :disabled="submitting" @click="openSubmitDialog">
|
||||||
|
{{ $t(key('login')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="warning" icon="el-icon-unlock" :disabled="submitting" @click="unbindTray">
|
||||||
|
{{ $t(key('tray_unbind')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" icon="el-icon-switch-button" :disabled="submitting" @click="stopTray">
|
||||||
|
{{ $t(key('tray_stop')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="el-icon-edit" :disabled="loadingFormats" @click="openFormatDialog">
|
||||||
|
{{ $t(key('tray_battery_format_edit')) }}
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" :disabled="submitting" @click="resetPage">
|
||||||
|
{{ $t(key('reset')) }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="registration-layout">
|
||||||
|
<section class="channel-panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span>{{ $t(key('data_table')) }}</span>
|
||||||
|
<el-tag size="mini">{{ loadedCount }} / {{ capacity }}</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="!currentFormat" :description="$t(key('select_format_first'))" :image-size="80" />
|
||||||
|
<div v-else class="channel-grid">
|
||||||
|
<el-form label-width="74px" size="mini">
|
||||||
|
<el-form-item
|
||||||
|
v-for="channel in channelList"
|
||||||
|
:key="channel"
|
||||||
|
:label="$t(key('channel')) + channel"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
:ref="inputRef(channel)"
|
||||||
|
v-model="batteryInputs[channel]"
|
||||||
|
:placeholder="$t(key('enter_battery_code'))"
|
||||||
|
clearable
|
||||||
|
@keyup.enter.native="scanBattery(channel)"
|
||||||
|
@clear="removeBattery(channel)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="battery-panel">
|
||||||
|
<div class="panel-head">
|
||||||
|
<span>{{ $t(key('tray_load_battery_count')) }}</span>
|
||||||
|
<el-button
|
||||||
|
type="text"
|
||||||
|
class="danger-action"
|
||||||
|
:disabled="!selectedRows.length"
|
||||||
|
@click="batchInactivity"
|
||||||
|
>
|
||||||
|
{{ $t(key('batch_deactivate')) }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<page-table
|
||||||
|
:columns="columns"
|
||||||
|
:data="tableData"
|
||||||
|
:loading="loadingBattery"
|
||||||
|
:toolbar-buttons="[]"
|
||||||
|
:row-buttons="[]"
|
||||||
|
:pagination="null"
|
||||||
|
:table-attrs="{ size: 'mini', rowKey: 'index', highlightCurrentRow: true, rowClassName: rowClassName }"
|
||||||
|
height="520px"
|
||||||
|
@selection-change="selectedRows = $event"
|
||||||
|
>
|
||||||
|
<template #col-battery="{ row }">
|
||||||
|
<span>{{ row.Battery || row.battery_id }}</span>
|
||||||
|
</template>
|
||||||
|
<template #col-active="{ row }">
|
||||||
|
<el-tag :type="Number(row.active) === 1 ? 'danger' : 'success'" size="mini">
|
||||||
|
{{ Number(row.active) === 1 ? $t(key('activated')) : $t(key('not_activated')) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<el-empty :description="$t('暂无数据')" :image-size="80" />
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('batch_no'))" :visible.sync="batchDialogVisible" width="760px">
|
||||||
|
<page-table
|
||||||
|
:columns="batchColumns"
|
||||||
|
:data="batchList"
|
||||||
|
:loading="loadingBatches"
|
||||||
|
:toolbar-buttons="[]"
|
||||||
|
:row-buttons="[]"
|
||||||
|
:pagination="null"
|
||||||
|
:table-attrs="{ size: 'mini', rowKey: 'batch', highlightCurrentRow: true }"
|
||||||
|
height="420px"
|
||||||
|
@row-dblclick="selectBatch"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('format_dialog_title'))" :visible.sync="formatDialogVisible" width="820px">
|
||||||
|
<el-button type="primary" size="mini" icon="el-icon-plus" @click="openFormatForm">
|
||||||
|
{{ $t(key('add')) }}
|
||||||
|
</el-button>
|
||||||
|
<page-table
|
||||||
|
class="format-table"
|
||||||
|
:columns="formatColumns"
|
||||||
|
:data="formatList"
|
||||||
|
:loading="loadingFormats"
|
||||||
|
:toolbar-buttons="[]"
|
||||||
|
:row-buttons="[]"
|
||||||
|
:pagination="null"
|
||||||
|
:table-attrs="{ size: 'mini', rowKey: 'id', highlightCurrentRow: true }"
|
||||||
|
height="360px"
|
||||||
|
@row-dblclick="selectFormatRow"
|
||||||
|
>
|
||||||
|
<template #col-actions="{ row }">
|
||||||
|
<el-button type="text" class="danger-action" @click="deleteFormat(row)">
|
||||||
|
{{ $t(key('delete')) }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('add_format_title'))" :visible.sync="formatFormVisible" width="620px">
|
||||||
|
<el-form :model="formatForm" label-width="150px" size="mini">
|
||||||
|
<el-form-item :label="$t(key('tray_barcode_format'))">
|
||||||
|
<el-input v-model="formatForm.tray_format" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('battery_barcode_format'))">
|
||||||
|
<el-input v-model="formatForm.battery_format" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t(key('tray_battery_count'))">
|
||||||
|
<el-input-number v-model="formatForm.battery_count" :min="1" :max="96" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-alert :title="$t(key('format_rule'))" type="warning" :closable="false" />
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button size="mini" @click="formatFormVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||||
|
<el-button size="mini" type="primary" @click="createFormat">{{ $t(key('confirm')) }}</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="$t(key('submit_login'))" :visible.sync="submitDialogVisible" width="640px">
|
||||||
|
<page-table
|
||||||
|
:columns="submitColumns"
|
||||||
|
:data="tableData"
|
||||||
|
:loading="submitting"
|
||||||
|
:toolbar-buttons="[]"
|
||||||
|
:row-buttons="[]"
|
||||||
|
:pagination="null"
|
||||||
|
:table-attrs="{ size: 'mini', rowKey: 'index' }"
|
||||||
|
height="360px"
|
||||||
|
>
|
||||||
|
<template #col-battery="{ row }">
|
||||||
|
<span>{{ row.Battery || row.battery_id }}</span>
|
||||||
|
</template>
|
||||||
|
</page-table>
|
||||||
|
<span slot="footer">
|
||||||
|
<el-button size="mini" @click="submitDialogVisible = false">{{ $t(key('cancel')) }}</el-button>
|
||||||
|
<el-button size="mini" type="primary" :disabled="submitting" @click="submitRegistration">
|
||||||
|
{{ $t(key('confirm')) }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</el-dialog>
|
||||||
|
</d2-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useTableColumns } from '@/composables/useTableColumns'
|
||||||
|
import { i18nMixin } from '@/composables/useI18n'
|
||||||
|
import PageTable from '@/components/page-table'
|
||||||
|
import { sendWorkerman } from '@/api/production-master-data/workerman'
|
||||||
|
import {
|
||||||
|
getBatchAll,
|
||||||
|
getBatchTrayFormatAll,
|
||||||
|
createBatchTrayFormat,
|
||||||
|
deleteBatchTrayFormat,
|
||||||
|
checkBatteryid
|
||||||
|
} from '@/api/planning-production/tray-registration'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'planning-production-tray-registration',
|
||||||
|
components: { PageTable },
|
||||||
|
mixins: [i18nMixin('page.planning_production.production_monitoring.tray_registration')],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
batch: '',
|
||||||
|
tray: ''
|
||||||
|
},
|
||||||
|
selectedFormatId: '',
|
||||||
|
currentFormat: null,
|
||||||
|
batteryInputs: {},
|
||||||
|
tableData: [],
|
||||||
|
batchList: [],
|
||||||
|
formatList: [],
|
||||||
|
selectedRows: [],
|
||||||
|
batchDialogVisible: false,
|
||||||
|
formatDialogVisible: false,
|
||||||
|
formatFormVisible: false,
|
||||||
|
submitDialogVisible: false,
|
||||||
|
loadingBatches: false,
|
||||||
|
loadingFormats: false,
|
||||||
|
loadingBattery: false,
|
||||||
|
submitting: false,
|
||||||
|
formatForm: {
|
||||||
|
tray_format: '',
|
||||||
|
battery_format: '',
|
||||||
|
battery_count: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
capacity () {
|
||||||
|
return Number((this.currentFormat && this.currentFormat.battery_count) || 0)
|
||||||
|
},
|
||||||
|
loadedCount () {
|
||||||
|
return this.tableData.length
|
||||||
|
},
|
||||||
|
channelList () {
|
||||||
|
return Array.from({ length: this.capacity }, (_, index) => index + 1)
|
||||||
|
},
|
||||||
|
trayRegExp () {
|
||||||
|
return this.createFormatRegExp(this.currentFormat && this.currentFormat.tray_format)
|
||||||
|
},
|
||||||
|
batteryRegExp () {
|
||||||
|
return this.createFormatRegExp(this.currentFormat && this.currentFormat.battery_format)
|
||||||
|
},
|
||||||
|
columns () {
|
||||||
|
return useTableColumns([
|
||||||
|
{ prop: 'index', label: this.key('process_channel'), width: 90 },
|
||||||
|
{ prop: 'Battery', label: this.key('battery_id'), minWidth: 180, slot: 'battery', showOverflowTooltip: true },
|
||||||
|
{ prop: 'active', label: this.key('activation_status'), width: 110, slot: 'active' },
|
||||||
|
{ prop: 'batch', label: this.key('previous_batch'), minWidth: 150, showOverflowTooltip: true },
|
||||||
|
{ prop: 'tray', label: this.key('previous_tray'), minWidth: 150, showOverflowTooltip: true },
|
||||||
|
{ prop: 'process_code', label: this.key('completed_process'), minWidth: 160, showOverflowTooltip: true }
|
||||||
|
], {
|
||||||
|
selectionWidth: 55,
|
||||||
|
indexWidth: 0
|
||||||
|
})
|
||||||
|
},
|
||||||
|
batchColumns () {
|
||||||
|
return useTableColumns([
|
||||||
|
{ prop: 'batch', label: this.key('batch_no'), minWidth: 200, showOverflowTooltip: true },
|
||||||
|
{ prop: 'flow_name', label: this.key('process_flow_name'), minWidth: 200, showOverflowTooltip: true },
|
||||||
|
{ prop: 'create_time', label: this.key('batch_create_time'), minWidth: 180, showOverflowTooltip: true }
|
||||||
|
], {
|
||||||
|
selectionWidth: 0,
|
||||||
|
indexWidth: 55
|
||||||
|
})
|
||||||
|
},
|
||||||
|
formatColumns () {
|
||||||
|
return useTableColumns([
|
||||||
|
{ prop: 'tray_format', label: this.key('tray_barcode_format'), minWidth: 160, showOverflowTooltip: true },
|
||||||
|
{ prop: 'battery_format', label: this.key('battery_barcode_format'), minWidth: 180, showOverflowTooltip: true },
|
||||||
|
{ prop: 'battery_count', label: this.key('tray_battery_count'), width: 140 },
|
||||||
|
{ prop: 'actions', label: this.key('operation'), width: 90, slot: 'actions' }
|
||||||
|
], {
|
||||||
|
selectionWidth: 0,
|
||||||
|
indexWidth: 55
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitColumns () {
|
||||||
|
return useTableColumns([
|
||||||
|
{ prop: 'index', label: this.key('process_channel'), width: 120 },
|
||||||
|
{ prop: 'Battery', label: this.key('battery_id'), minWidth: 220, slot: 'battery', showOverflowTooltip: true }
|
||||||
|
], {
|
||||||
|
selectionWidth: 0,
|
||||||
|
indexWidth: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.fetchBatchList()
|
||||||
|
this.fetchFormatList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
responseData (res) {
|
||||||
|
const payload = res && res.data ? res.data : (res || {})
|
||||||
|
return payload.data || payload
|
||||||
|
},
|
||||||
|
formatLabel (item) {
|
||||||
|
return `${item.tray_format} / ${item.battery_format} / ${item.battery_count}`
|
||||||
|
},
|
||||||
|
inputRef (channel) {
|
||||||
|
return `batteryInput${channel}`
|
||||||
|
},
|
||||||
|
createFormatRegExp (format) {
|
||||||
|
if (!format) return null
|
||||||
|
const escaped = String(format).replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[A-Z0-9-]')
|
||||||
|
return new RegExp(`^${escaped}$`)
|
||||||
|
},
|
||||||
|
openBatchDialog () {
|
||||||
|
this.batchDialogVisible = true
|
||||||
|
if (!this.batchList.length) this.fetchBatchList()
|
||||||
|
},
|
||||||
|
selectBatch (row) {
|
||||||
|
this.form.batch = row.batch
|
||||||
|
this.batchDialogVisible = false
|
||||||
|
},
|
||||||
|
async fetchBatchList () {
|
||||||
|
this.loadingBatches = true
|
||||||
|
try {
|
||||||
|
const res = await getBatchAll({ action: 'get_batch' })
|
||||||
|
const data = this.responseData(res)
|
||||||
|
this.batchList = Array.isArray(data) ? data : []
|
||||||
|
} finally {
|
||||||
|
this.loadingBatches = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async fetchFormatList () {
|
||||||
|
this.loadingFormats = true
|
||||||
|
try {
|
||||||
|
const res = await getBatchTrayFormatAll({ action: 'get_login_format' })
|
||||||
|
const data = this.responseData(res)
|
||||||
|
this.formatList = Array.isArray(data) ? data : []
|
||||||
|
if (!this.currentFormat && this.formatList.length) {
|
||||||
|
this.selectFormat(this.formatList[0].id)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.loadingFormats = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectFormat (id) {
|
||||||
|
const target = this.formatList.find(item => String(item.id) === String(id))
|
||||||
|
if (!target) return
|
||||||
|
this.currentFormat = target
|
||||||
|
this.selectedFormatId = target.id
|
||||||
|
this.tableData = []
|
||||||
|
this.selectedRows = []
|
||||||
|
this.batteryInputs = {}
|
||||||
|
},
|
||||||
|
selectFormatRow (row) {
|
||||||
|
this.selectFormat(row.id)
|
||||||
|
this.formatDialogVisible = false
|
||||||
|
},
|
||||||
|
focusFirstChannel () {
|
||||||
|
if (!this.validateTray()) return
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refs = this.$refs[this.inputRef(1)]
|
||||||
|
const input = Array.isArray(refs) ? refs[0] : refs
|
||||||
|
if (input) input.focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
validateTray () {
|
||||||
|
if (!this.currentFormat) {
|
||||||
|
this.$message.warning(this.$t(this.key('select_format_first')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.form.tray) {
|
||||||
|
this.$message.warning(this.$t(this.key('please_enter_tray_code')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (this.trayRegExp && !this.trayRegExp.test(this.form.tray)) {
|
||||||
|
this.$message.warning(this.$t(this.key('format_error_exclamation')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
async scanBattery (channel) {
|
||||||
|
if (!this.validateTray()) return
|
||||||
|
const batteryId = this.batteryInputs[channel]
|
||||||
|
if (!batteryId) {
|
||||||
|
this.removeBattery(channel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.batteryRegExp && !this.batteryRegExp.test(batteryId)) {
|
||||||
|
this.$message.warning(this.$t(this.key('format_error')))
|
||||||
|
this.removeBattery(channel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const duplicate = this.tableData.find(item => item.index !== channel && item.Battery === batteryId)
|
||||||
|
if (duplicate) {
|
||||||
|
this.$message.warning(this.$t(this.key('insert_duplicate_battery')))
|
||||||
|
this.removeBattery(channel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loadingBattery = true
|
||||||
|
try {
|
||||||
|
const res = await checkBatteryid({
|
||||||
|
action: 'check_elements_code',
|
||||||
|
battery_id: batteryId
|
||||||
|
})
|
||||||
|
const payload = res && res.data ? res.data : (res || {})
|
||||||
|
const data = payload.data || {}
|
||||||
|
if (payload.code !== undefined && Number(payload.code) !== 0) {
|
||||||
|
this.$message.error(payload.msg || payload.errmsg || this.$t(this.key('format_error')))
|
||||||
|
this.removeBattery(channel)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const row = {
|
||||||
|
...data,
|
||||||
|
Battery: batteryId,
|
||||||
|
battery_id: data.battery_id || batteryId,
|
||||||
|
index: channel
|
||||||
|
}
|
||||||
|
const exists = this.tableData.findIndex(item => item.index === channel)
|
||||||
|
if (exists >= 0) {
|
||||||
|
this.$set(this.tableData, exists, row)
|
||||||
|
} else {
|
||||||
|
this.tableData.push(row)
|
||||||
|
}
|
||||||
|
this.tableData.sort((a, b) => a.index - b.index)
|
||||||
|
this.focusNextChannel(channel)
|
||||||
|
} finally {
|
||||||
|
this.loadingBattery = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focusNextChannel (channel) {
|
||||||
|
const next = channel + 1
|
||||||
|
if (next > this.capacity) return
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const refs = this.$refs[this.inputRef(next)]
|
||||||
|
const input = Array.isArray(refs) ? refs[0] : refs
|
||||||
|
if (input) {
|
||||||
|
input.focus()
|
||||||
|
input.select()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
removeBattery (channel) {
|
||||||
|
this.$delete(this.batteryInputs, channel)
|
||||||
|
this.tableData = this.tableData.filter(item => item.index !== channel)
|
||||||
|
},
|
||||||
|
openFormatDialog () {
|
||||||
|
this.formatDialogVisible = true
|
||||||
|
this.fetchFormatList()
|
||||||
|
},
|
||||||
|
openFormatForm () {
|
||||||
|
this.formatForm = {
|
||||||
|
tray_format: '',
|
||||||
|
battery_format: '',
|
||||||
|
battery_count: 1
|
||||||
|
}
|
||||||
|
this.formatFormVisible = true
|
||||||
|
},
|
||||||
|
async createFormat () {
|
||||||
|
if (!this.formatForm.tray_format) {
|
||||||
|
this.$message.warning(this.$t(this.key('add_tray_format')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.formatForm.battery_format) {
|
||||||
|
this.$message.warning(this.$t(this.key('add_battery_format')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.formatForm.battery_count || Number(this.formatForm.battery_count) <= 0) {
|
||||||
|
this.$message.warning(this.$t(this.key('add_battery_count')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
await createBatchTrayFormat({
|
||||||
|
action: 'set_login_format',
|
||||||
|
...this.formatForm
|
||||||
|
})
|
||||||
|
this.$message.success(this.$t(this.key('operation_success')))
|
||||||
|
this.formatFormVisible = false
|
||||||
|
this.fetchFormatList()
|
||||||
|
},
|
||||||
|
deleteFormat (row) {
|
||||||
|
this.$confirm(this.$t(this.key('delete_confirm')), this.$t(this.key('prompt')), {
|
||||||
|
confirmButtonText: this.$t(this.key('confirm')),
|
||||||
|
cancelButtonText: this.$t(this.key('cancel')),
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
await deleteBatchTrayFormat({
|
||||||
|
action: 'set_login_format',
|
||||||
|
id: row.id
|
||||||
|
})
|
||||||
|
this.$message.success(this.$t(this.key('delete_success')))
|
||||||
|
this.fetchFormatList()
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
openSubmitDialog () {
|
||||||
|
if (!this.validateSubmit()) return
|
||||||
|
this.submitDialogVisible = true
|
||||||
|
},
|
||||||
|
validateSubmit () {
|
||||||
|
if (!this.validateTray()) return false
|
||||||
|
if (!this.form.batch) {
|
||||||
|
this.$message.warning(this.$t(this.key('no_batch_no')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.tableData.length) {
|
||||||
|
this.$message.warning(this.$t(this.key('enter_battery_code')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (this.tableData.some(item => Number(item.active) === 1)) {
|
||||||
|
this.$message.warning(this.$t(this.key('has_active_battery_login_forbidden')))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
batteryIdsForSubmit () {
|
||||||
|
return this.channelList.map(channel => {
|
||||||
|
const row = this.tableData.find(item => item.index === channel)
|
||||||
|
return row ? row.Battery : '0'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async submitRegistration () {
|
||||||
|
if (!this.validateSubmit()) return
|
||||||
|
this.submitting = true
|
||||||
|
try {
|
||||||
|
const res = await sendWorkerman({
|
||||||
|
sendData: {
|
||||||
|
action: 'set_tray_login',
|
||||||
|
param: {
|
||||||
|
workingsubclass: 'LOGIN',
|
||||||
|
tray: this.form.tray,
|
||||||
|
batch: this.form.batch,
|
||||||
|
device_code: 'WEBMAN_LOGIN',
|
||||||
|
direction_sign: '',
|
||||||
|
lot: String(new Date().valueOf()),
|
||||||
|
battery_ids: this.batteryIdsForSubmit(),
|
||||||
|
Manual: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const payload = res && res.data ? res.data : (res || {})
|
||||||
|
if (payload.code !== undefined && Number(payload.code) !== 0) {
|
||||||
|
this.$message.warning(payload.errmsg || payload.msg || this.$t(this.key('operation_failed')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$message.success(this.$t(this.key('upload_success')))
|
||||||
|
this.submitDialogVisible = false
|
||||||
|
this.resetPage()
|
||||||
|
} finally {
|
||||||
|
this.submitting = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unbindTray () {
|
||||||
|
this.promptTray('tray_unbind_desc', 'tray_unbind', 'set_tray_unbinding', 'tray_unbind_success')
|
||||||
|
},
|
||||||
|
stopTray () {
|
||||||
|
this.promptTray('tray_stop_desc', 'tray_stop', 'set_tray_inactivity', 'tray_stop_success')
|
||||||
|
},
|
||||||
|
promptTray (messageKey, titleKey, action, successKey) {
|
||||||
|
this.$prompt(this.$t(this.key(messageKey)), this.$t(this.key(titleKey)), {
|
||||||
|
confirmButtonText: this.$t(this.key('confirm')),
|
||||||
|
cancelButtonText: this.$t(this.key('cancel')),
|
||||||
|
inputValue: this.form.tray,
|
||||||
|
inputValidator: value => {
|
||||||
|
if (!value) return this.$t(this.key('enter_tray_no'))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}).then(async ({ value }) => {
|
||||||
|
const param = action === 'set_tray_inactivity'
|
||||||
|
? { data: [{ tray: value }] }
|
||||||
|
: { tray: value }
|
||||||
|
await sendWorkerman({
|
||||||
|
sendData: {
|
||||||
|
action,
|
||||||
|
param
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$message.success(this.$t(this.key(successKey)))
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
batchInactivity () {
|
||||||
|
if (!this.selectedRows.length) {
|
||||||
|
this.$message.warning(this.$t(this.key('select_battery_to_deactivate')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm(this.$t(this.key('battery_deactivate')), this.$t(this.key('prompt')), {
|
||||||
|
confirmButtonText: this.$t(this.key('confirm')),
|
||||||
|
cancelButtonText: this.$t(this.key('cancel')),
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
await sendWorkerman({
|
||||||
|
sendData: {
|
||||||
|
action: 'set_battery_inactivity',
|
||||||
|
param: {
|
||||||
|
data: this.selectedRows.map(row => ({
|
||||||
|
battery_id: row.Battery || row.battery_id,
|
||||||
|
class: 'NG',
|
||||||
|
classname: 'web_inactivity'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.selectedRows.forEach(row => {
|
||||||
|
const target = this.tableData.find(item => item.index === row.index)
|
||||||
|
if (target) this.$set(target, 'active', 0)
|
||||||
|
})
|
||||||
|
this.$message.success(this.$t(this.key('batch_battery_deactivate_success')))
|
||||||
|
}).catch(() => {})
|
||||||
|
},
|
||||||
|
rowClassName ({ row }) {
|
||||||
|
return Number(row.active) === 1 ? 'is-active-battery' : ''
|
||||||
|
},
|
||||||
|
resetPage () {
|
||||||
|
this.form.tray = ''
|
||||||
|
this.batteryInputs = {}
|
||||||
|
this.tableData = []
|
||||||
|
this.selectedRows = []
|
||||||
|
this.submitDialogVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.registration-layout {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(360px, 1fr) minmax(520px, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-panel,
|
||||||
|
.battery-panel {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
min-height: 32px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-grid {
|
||||||
|
max-height: 560px;
|
||||||
|
padding-right: 8px;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
::v-deep .el-form {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(220px, 1fr));
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-table {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-action {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .is-active-battery td {
|
||||||
|
background-color: rgba(245, 108, 108, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1100px) {
|
||||||
|
.registration-layout {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user