Browse Source

feat(order): 添加国际化支持并优化权限控制

- 在多个组件中添加locale属性支持中英文切换
- 实现表格列标题的国际化显示
- 为首页代办功能添加菜单权限控制
- 移除菜单管理中不必要的"菜单"文字重复显示
- 禁止菜单路由字段在编辑时被修改
- 限制菜单删除功能仅对非一级菜单生效
- 新增英文版PO订单查询页面支持国际化显示
master
qiankanghui 7 days ago
parent
commit
6eaddd2b96
  1. 12
      src/views/common/home.vue
  2. 37
      src/views/modules/order/com_inspectionDetailList.vue
  3. 19
      src/views/modules/order/com_logisticsPoList.vue
  4. 87
      src/views/modules/order/com_poOrderDetail.vue
  5. 14
      src/views/modules/order/com_poPartAttribute.vue
  6. 960
      src/views/modules/order/poOrder_search_en.vue
  7. 2
      src/views/modules/sys/menu-add-or-update.vue
  8. 4
      src/views/modules/sys/menu.vue

12
src/views/common/home.vue

@ -83,10 +83,10 @@ export default {
inspectionAuditCount: 0,
inspectionChangeApplyingCount: 0,
homeTileShow: {
supplierDocExpire: true,
contractRequestExpire: true,
myPerformanceScore: true,
inspectionAudit: true,
supplierDocExpire: false,
contractRequestExpire: false,
myPerformanceScore: false,
inspectionAudit: false,
inspectionChangeApplying: false,
},
/** 代办卡片悬停外圈脉冲(双环);false 时无任何脉冲描边 */
@ -276,6 +276,10 @@ export default {
},
mounted () {
// - rqrq
this.homeTileShow.supplierDocExpire = this.hasRouteMenuAccess('srmSupplier-supplierList')
this.homeTileShow.contractRequestExpire = this.hasRouteMenuAccess('srmSupplier-supplierContractRequest')
this.homeTileShow.myPerformanceScore = this.hasRouteMenuAccess('supplierPerformance-perMyScore')
this.homeTileShow.inspectionAudit = this.hasRouteMenuAccess('inspection-inspectionRequestAudit')
this.homeTileShow.inspectionChangeApplying = this.hasRouteMenuAccess('inspection-inspectionScheduleList')
if (this.homeTileShow.supplierDocExpire) {
this.loadDocExpireReminder()

37
src/views/modules/order/com_inspectionDetailList.vue

@ -26,14 +26,14 @@
fixed="right"
header-align="center"
align="center"
label="操作"
:label="locale === 'en' ? 'Operation' : '操作'"
min-width="100">
<template slot-scope="scope">
<el-link
v-if="scope.row.inspectNo"
type="primary"
@click="jumpToInspection(scope.row)">
跳转
{{ locale === 'en' ? 'Jump' : '跳转' }}
</el-link>
<span v-else>-</span>
</template>
@ -58,6 +58,12 @@ import { getInspectionByPODetail } from '@/api/order/poOrder.js'
export default {
name: 'InspectionDetailList',
props: {
locale: {
type: String,
default: 'zh'
}
},
data() {
return {
@ -73,13 +79,18 @@ export default {
pageIndex: 1,
pageSize: 20,
totalPage: 0,
dataListLoading: false,
columnList: [
dataListLoading: false
}
},
computed: {
columnList() {
const isEn = this.locale === 'en'
return [
{
columnProp: 'requestNo',
headerAlign: 'center',
align: 'center',
columnLabel: '申请单号',
columnLabel: isEn ? 'Request No' : '申请单号',
columnWidth: '140',
columnHidden: false,
columnSortable: false,
@ -90,7 +101,7 @@ export default {
columnProp: 'inspectNo',
headerAlign: 'center',
align: 'center',
columnLabel: '检验单号',
columnLabel: isEn ? 'Inspection No' : '检验单号',
columnWidth: '140',
columnHidden: false,
columnSortable: false,
@ -101,7 +112,7 @@ export default {
columnProp: 'partNo',
headerAlign: 'center',
align: 'center',
columnLabel: '产品编码',
columnLabel: isEn ? 'Part No' : '产品编码',
columnWidth: '120',
columnHidden: false,
columnSortable: false,
@ -112,7 +123,7 @@ export default {
columnProp: 'partDesc',
headerAlign: 'center',
align: 'left',
columnLabel: '产品名称',
columnLabel: isEn ? 'Part Desc' : '产品名称',
columnWidth: '200',
columnHidden: false,
columnSortable: false,
@ -123,7 +134,7 @@ export default {
columnProp: 'inspectQty',
headerAlign: 'center',
align: 'center',
columnLabel: '验货数量',
columnLabel: isEn ? 'Inspection Qty' : '验货数量',
columnWidth: '100',
columnHidden: false,
columnSortable: false,
@ -133,7 +144,7 @@ export default {
columnProp: 'approveQty',
headerAlign: 'center',
align: 'center',
columnLabel: '检验通过数量',
columnLabel: isEn ? 'Approved Qty' : '检验通过数量',
columnWidth: '120',
columnHidden: false,
columnSortable: false,
@ -143,7 +154,7 @@ export default {
columnProp: 'status',
headerAlign: 'center',
align: 'center',
columnLabel: '验货状态',
columnLabel: isEn ? 'Inspection Status' : '验货状态',
columnWidth: '100',
columnHidden: false,
columnSortable: false,
@ -153,7 +164,7 @@ export default {
columnProp: 'inspectResult',
headerAlign: 'center',
align: 'center',
columnLabel: '验货结果',
columnLabel: isEn ? 'Inspection Result' : '验货结果',
columnWidth: '100',
columnHidden: false,
columnSortable: false,
@ -218,7 +229,7 @@ export default {
jumpToInspection(row) {
const inspectionNo = row && row.inspectNo ? String(row.inspectNo).trim() : ''
if (!inspectionNo) {
this.$message.warning('未找到检验单号')
this.$message.warning(this.locale === 'en' ? 'Inspection No not found' : '未找到检验单号')
return
}
this.$router.push({

19
src/views/modules/order/com_logisticsPoList.vue

@ -42,6 +42,12 @@ import { getPoList } from '@/api/npcIqc/npcIqc.js'
export default {
name: 'LogisticsPoList',
props: {
locale: {
type: String,
default: 'zh'
}
},
data() {
return {
@ -57,13 +63,18 @@ export default {
pageIndex: 1,
pageSize: 20,
totalPage: 0,
dataListLoading: false,
columnList: [
dataListLoading: false
}
},
computed: {
columnList() {
const isEn = this.locale === 'en'
return [
{
columnProp: 'flexId',
headerAlign: 'center',
align: 'center',
columnLabel: '进仓编号',
columnLabel: isEn ? 'Warehouse No' : '进仓编号',
columnWidth: '120',
columnHidden: false,
columnSortable: false,
@ -73,7 +84,7 @@ export default {
columnProp: 'orderDate',
headerAlign: 'center',
align: 'center',
columnLabel: 'PO日期',
columnLabel: isEn ? 'PO Date' : 'PO日期',
columnWidth: '120',
columnHidden: false,
columnSortable: false,

87
src/views/modules/order/com_poOrderDetail.vue

@ -35,6 +35,90 @@ export default {
schemaFields: {
type: Array,
default: () => []
},
locale: {
type: String,
default: 'zh'
}
},
data () {
return {
labelMap: {
'PO No': 'PO No',
'PO号': 'PO No',
'订单类型': 'Order Type',
'类型': 'Type',
'Customer': 'Customer',
'客户': 'Customer',
'Buyer': 'Buyer',
'采购员': 'Buyer',
'Vendor Name': 'Vendor Name',
'供应商名称': 'Vendor Name',
'V_Short_Office': 'V_Short_Office',
'V_Short_NPC': 'V_Short_NPC',
'Part No': 'Part No',
'产品编码': 'Part No',
'Item': 'Item',
'项目': 'Item',
'Category': 'Category',
'品类': 'Category',
'SKU': 'SKU',
'Unit Price': 'Unit Price',
'单价': 'Unit Price',
'PO Qty': 'PO Qty',
'数量': 'PO Qty',
'PO Value': 'PO Value',
'金额': 'PO Value',
'A-Qty': 'A-Qty',
'A-Value': 'A-Value',
'Departure Port': 'Departure Port',
'出发港': 'Departure Port',
'Destination Port': 'Destination Port',
'目的港': 'Destination Port',
'Method': 'Method',
'运输方式': 'Method',
'Buyer Release Date': 'Buyer Release Date',
'采购发布日期': 'Buyer Release Date',
'Planner Release Date': 'Planner Release Date',
'计划发布日期': 'Planner Release Date',
'Status': 'Status',
'状态': 'Status',
'PI Confirmed Date': 'PI Confirmed Date',
'PI确认日期': 'PI Confirmed Date',
'Original Arrival Date': 'Original Arrival Date',
'原始到货日期': 'Original Arrival Date',
'Final Confirmed Arrival Date': 'Final Confirmed Arrival Date',
'最终确认到货日期': 'Final Confirmed Arrival Date',
'PI Confirmed CRD': 'PI Confirmed CRD',
'Original CRD': 'Original CRD',
'Inspection Date': 'Inspection Date',
'验货日期': 'Inspection Date',
'Actual Completion Date': 'Actual Completion Date',
'实际完成日期': 'Actual Completion Date',
'ETA': 'ETA',
'Flexport Id': 'Flexport Id',
'On Board Date': 'On Board Date',
'装船日期': 'On Board Date',
'Doc Sent': 'Doc Sent',
'Telex Release': 'Telex Release',
'Advance Payment': 'Advance Payment',
'预付款': 'Advance Payment',
'Advanc Paid': 'Advanc Paid',
'Create Date': 'Create Date',
'创建日期': 'Create Date',
'M-Planner': 'M-Planner',
'计划员': 'M-Planner',
'Edit Date': 'Edit Date',
'编辑日期': 'Edit Date',
'Last Editor': 'Last Editor',
'最后编辑人': 'Last Editor',
'Remark Delay': 'Remark Delay',
'延迟备注': 'Remark Delay',
'Comments': 'Comments',
'备注': 'Comments',
'Inspection Completed Qty': 'Inspection Completed Qty',
'已验货数量': 'Inspection Completed Qty'
}
}
},
computed: {
@ -151,6 +235,9 @@ export default {
getFieldLabel (field) {
const label = String((field && field.fieldLabel) || '').trim()
if (label) {
if (this.locale === 'en' && this.labelMap[label]) {
return this.labelMap[label]
}
return label
}
return this.getFieldProp(field) || this.getFieldCode(field)

14
src/views/modules/order/com_poPartAttribute.vue

@ -8,27 +8,27 @@
style="width: 100%; margin-top: 5px">
<el-table-column
prop="propertiesItemNo"
label="属性编码"
:label="locale === 'en' ? 'Property Code' : '属性编码'"
header-align="center"
align="left"
min-width="140"
show-overflow-tooltip />
<el-table-column
prop="itemDesc"
label="属性名称"
:label="locale === 'en' ? 'Property Name' : '属性名称'"
header-align="center"
align="left"
min-width="180"
show-overflow-tooltip />
<el-table-column
prop="valueType"
label="值类型"
:label="locale === 'en' ? 'Value Type' : '值类型'"
header-align="center"
align="center"
min-width="90"
show-overflow-tooltip />
<el-table-column
label="属性值"
:label="locale === 'en' ? 'Property Value' : '属性值'"
header-align="center"
align="left"
min-width="180"
@ -46,6 +46,12 @@ import { getPropertiesListByPartAndCodeNo } from '@/api/part/partProperties.js'
export default {
name: 'PoPartAttribute',
props: {
locale: {
type: String,
default: 'zh'
}
},
data () {
return {
loading: false,

960
src/views/modules/order/poOrder_search_en.vue

@ -0,0 +1,960 @@
<template>
<div class="mod-config">
<com-po-order-customer-picker
:site="searchData.site"
v-model="searchData.customer"
@change="onSessionCustomerChange" />
<!-- Search Conditions -->
<el-form :inline="true" label-position="top" :model="searchData">
<el-form-item label="PO No">
<el-input v-model="searchData.poNo" clearable style="width: 140px" @keyup.enter.native="handleSearch"></el-input>
</el-form-item>
<el-form-item label="Order Type">
<el-select v-model="searchData.orderType" placeholder="Please select" style="width: 120px" clearable>
<el-option
v-for="item in poOrderTypeSearchOptions"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<span style="cursor: pointer" slot="label" @click="openSearchBaseList(2017)"><a href="javascript:void(0)">Part No</a></span>
<el-input v-model="searchData.partNo" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
</el-form-item>
<el-form-item>
<span style="cursor: pointer" slot="label" @click="openSearchBaseList(520)"><a href="javascript:void(0)">Supplier Code</a></span>
<el-input v-model="searchData.supplierNo" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
</el-form-item>
<el-form-item label="SKU">
<el-input v-model="searchData.sku" clearable style="width: 120px" @keyup.enter.native="handleSearch"></el-input>
</el-form-item>
<el-form-item label="Status">
<el-select v-model="searchData.status" placeholder="Please select" style="width:100px" clearable>
<el-option label="All" value=""></el-option>
<el-option
v-for="item in poOrderStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
</el-form>
<el-form :inline="true" label-position="top" style="margin-top:10px">
<el-form-item>
<el-button type="primary" @click="handleSearch" :disabled="!searchData.customer">Search</el-button>
<el-button type="primary" @click="exportExcel" style="margin-left: 2px">Export</el-button>
<el-button @click="resetSearch">Reset</el-button>
<el-button type="warning" plain @click="advancedQueryVisible = true" style="margin-left: 2px">Advanced Query</el-button>
</el-form-item>
</el-form>
<!-- Data Table -->
<el-table
ref="poTable"
:height="height"
:data="dataList"
border
highlight-current-row
v-loading="loading"
@row-click="changeData"
style="width: 100%;">
<el-table-column
v-for="(item, index) in visibleColumns"
:key="item.serialNumber || index"
:sortable="item.columnSortable"
:prop="item.columnProp"
:header-align="item.headerAlign"
:show-overflow-tooltip="item.showOverflowTooltip"
:align="item.align"
:fixed="item.fixed === '' ? false : item.fixed"
:min-width="item.columnWidth"
:label="item.columnLabel">
<template slot-scope="scope">
<span>{{ formatColumnCell(scope.row, item) }}</span>
</template>
</el-table-column>
</el-table>
<!-- Pagination -->
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[20, 50, 100, 200, 500]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
<!-- Detail Tabs -->
<el-tabs v-model="activeTab" style="margin-top: 0px; width: 99%;" @tab-click="handleTabClick" class="customer-tab" type="border-card">
<!-- Order Detail -->
<el-tab-pane label="Order Detail" name="orderDetail">
<po-order-detail
:detail-data="currentRow"
:schema-fields="fieldSchemaFields"
locale="en" />
</el-tab-pane>
<!-- Logistics -->
<el-tab-pane label="Logistics" name="logistics">
<logistics-po-list ref="logisticsPoList" locale="en" />
</el-tab-pane>
<!-- Inspection Detail -->
<el-tab-pane label="Inspection Detail" name="inspectionDetail">
<inspection-detail-list ref="inspectionDetailList" locale="en" />
</el-tab-pane>
<!-- Part Attribute (Read Only) -->
<el-tab-pane label="Part Attribute" name="partAttribute">
<po-part-attribute ref="partAttributeTab" locale="en" />
</el-tab-pane>
</el-tabs>
<po-order-advanced-query
:visible.sync="advancedQueryVisible"
:advanced-query-data="advancedQueryData"
@query="handleSearch" />
<ChooselistEam ref="eamList" @getBaseData="getEamData" />
</div>
</template>
<script>
import { searchPoDetailPage, searchPoDetailAdvancedPage, getPoFieldSchema } from '@/api/order/poOrder.js'
import {
createAdvancedQueryData,
createAdvancedQueryDataFromSchema,
buildPoOrderQueryParams
} from './poOrderAdvancedQueryHelper.js'
import {
applyFieldSchemaToColumns,
getAdvancedQueryFieldsFromSchema,
normalizeSchemaRowValues
} from './poOrderFieldSchemaHelper.js'
import excel from '@/utils/excel-util.js'
import LogisticsPoList from './com_logisticsPoList.vue'
import InspectionDetailList from './com_inspectionDetailList.vue'
import PoPartAttribute from './com_poPartAttribute.vue'
import PoOrderDetail from './com_poOrderDetail.vue'
import PoOrderAdvancedQuery from './com_poOrderAdvancedQuery.vue'
import ChooselistEam from '@/views/modules/common/Chooselist_eam.vue'
import ComPoOrderCustomerPicker from './com_poOrder_CustomerPicker.vue'
import { PO_ORDER_STATUS_OPTIONS } from './poOrderStatusOptions.js'
import { PO_ORDER_TYPE_OPTIONS, formatPoOrderTypeLabel } from './poOrderTypeOptions.js'
import { searchPartInfo } from '@/api/part/partInfo.js'
export default {
components: {
LogisticsPoList,
InspectionDetailList,
PoPartAttribute,
PoOrderDetail,
PoOrderAdvancedQuery,
ChooselistEam,
ComPoOrderCustomerPicker
},
name: 'PoOrderQueryEn',
data() {
return {
loading: false,
exportLoading: false,
height: 400,
activeTab: 'orderDetail',
pageIndex: 1,
pageSize: 20,
totalPage: 0,
dataList: [],
currentRow: {},
advancedQueryVisible: false,
eamTagNo: '',
poOrderTypeSearchOptions: [{ label: 'All', value: '' }, ...PO_ORDER_TYPE_OPTIONS],
/** Advanced query object (read by search/export; only reset in dialog) */
advancedQueryData: createAdvancedQueryData(),
fieldSchemaFields: [],
baseColumnList: null,
poOrderStatusOptions: PO_ORDER_STATUS_OPTIONS,
searchData: {
site: this.$store.state.user.site,
customer: '',
buyer: '',
poNo: '',
orderType: '',
partNo: '',
supplierNo: '',
sku: '',
status: '',
supplierName: '',
feeDateStart: '',
feeDateEnd: ''
},
// Column config (consistent with original page, hides edit related columns)
columnList: [
{
columnProp: 'poNo',
columnLabel: 'PO No',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'orderType',
columnLabel: 'Order Type',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'customer',
columnLabel: 'Customer',
align: 'center',
columnWidth: 180,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'buyer',
columnLabel: 'Buyer',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'supplierName',
columnLabel: 'Vendor Name',
align: 'center',
columnWidth: 180,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'shortOffice',
columnLabel: 'V_Short_Office',
align: 'center',
columnWidth: 110,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'shortNpc',
columnLabel: 'V_Short_NPC',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'partNo',
columnLabel: 'Part No',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'item',
columnLabel: 'Item',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'categoryName',
columnLabel: 'Category',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'sku',
columnLabel: 'SKU',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'price',
columnLabel: 'Unit Price',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'qty',
columnLabel: 'PO Qty',
align: 'center',
columnWidth: 80,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'value',
columnLabel: 'PO Value',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'shipQty',
columnLabel: 'A-Qty',
align: 'center',
columnWidth: 80,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'sumPrice',
columnLabel: 'A-Value',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'departure',
columnLabel: 'Departure Port',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'destination',
columnLabel: 'Destination Port',
align: 'center',
columnWidth: 110,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'shipVia',
columnLabel: 'Method',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'orderDate',
columnLabel: 'Buyer Release Date',
align: 'center',
columnWidth: 130,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'enquiry',
columnLabel: 'Planner Release Date',
align: 'center',
columnWidth: 140,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'status',
columnLabel: 'Status',
align: 'center',
columnWidth: 80,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'confirmed',
columnLabel: 'PI Confirmed Date',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'wantReceiveDate',
columnLabel: 'Original Arrival Date',
align: 'center',
columnWidth: 130,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'narrival',
columnLabel: 'Final Confirmed Arrival Date',
align: 'center',
columnWidth: 110,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'crd',
columnLabel: 'PI Confirmed CRD',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'crdOri',
columnLabel: 'Original CRD',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'inspection',
columnLabel: 'Inspection Date',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'realCrd',
columnLabel: 'Actual Completion Date',
align: 'center',
columnWidth: 150,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'eta',
columnLabel: 'ETA',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'flexid',
columnLabel: 'Flexport Id',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'obd',
columnLabel: 'On Board Date',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'docSent',
columnLabel: 'Doc Sent',
align: 'center',
columnWidth: 90,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'telexRelease',
columnLabel: 'Telex Release',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'advancePayment',
columnLabel: 'Advance Payment',
align: 'center',
columnWidth: 120,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'advancePaid',
columnLabel: 'Advanc Paid',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'createTime',
columnLabel: 'Create Date',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'planner',
columnLabel: 'M-Planner',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'edit',
columnLabel: 'Edit Date',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'endPlanner',
columnLabel: 'Last Editor',
align: 'center',
columnWidth: 100,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'remarkDelay',
columnLabel: 'Remark Delay',
align: 'center',
columnWidth: 110,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'remark',
columnLabel: 'Comments',
align: 'center',
columnWidth: 180,
showOverflowTooltip: true,
headerAlign: 'center'
},
{
columnProp: 'inspectionCompletedQty',
columnLabel: 'Inspection Completed Qty',
align: 'center',
columnWidth: 140,
showOverflowTooltip: true,
headerAlign: 'center'
}
]
}
},
computed: {
visibleColumns() {
const source = this.baseColumnList || this.columnList
const applied = applyFieldSchemaToColumns(source, this.fieldSchemaFields)
return applied.filter(c => !c.columnHidden)
}
},
created() {
this.baseColumnList = JSON.parse(JSON.stringify(this.columnList))
},
mounted() {
this.updateTableHeight()
window.addEventListener('resize', this.onWindowResize)
},
activated () {
this.updateTableHeight()
this.refreshTableLayout()
},
deactivated () {
this.refreshTableLayout()
},
beforeDestroy () {
window.removeEventListener('resize', this.onWindowResize)
},
methods: {
onWindowResize () {
this.updateTableHeight()
},
updateTableHeight () {
const calculatedHeight = (window.innerHeight - 220) / 2
this.height = calculatedHeight > 220 ? calculatedHeight : 220
this.refreshTableLayout()
},
refreshTableLayout () {
this.$nextTick(() => {
if (this.$refs.poTable && this.$refs.poTable.doLayout) {
this.$refs.poTable.doLayout()
}
})
},
formatColumnCell (row, item) {
if (item.columnProp === 'orderType') {
return formatPoOrderTypeLabel(row.orderType)
}
const prop = item && item.columnProp
if (!prop || !row) {
return ''
}
if (row[prop] !== undefined && row[prop] !== null) {
return row[prop]
}
if (row.extValues && typeof row.extValues === 'object' &&
Object.prototype.hasOwnProperty.call(row.extValues, prop)) {
return row.extValues[prop]
}
return ''
},
buildQueryRequest() {
return buildPoOrderQueryParams({
searchData: this.searchData,
advancedQueryData: this.advancedQueryData,
page: this.pageIndex,
limit: this.pageSize
})
},
handleSearch() {
if (!this.searchData.customer) {
this.$message.warning('Please select Customer first')
return
}
this.pageIndex = 1
this.getDataList()
},
onSessionCustomerChange (customer) {
this.searchData.customer = customer
this.advancedQueryData.rows = []
this.pageIndex = 1
this.dataList = []
this.totalPage = 0
this.currentRow = {}
this.clearDetailTabs()
if (!customer) {
this.fieldSchemaFields = []
this.advancedQueryData.rows = []
this.refreshTableLayout()
return
}
this.loadFieldSchema(customer).then(() => {
this.getDataList()
})
},
loadFieldSchema (customer) {
return getPoFieldSchema({
site: this.searchData.site,
customer,
scene: 'list'
}).then(({ data }) => {
if (data && data.code === 0 && data.data) {
this.fieldSchemaFields = data.data.fields || []
const queryFields = getAdvancedQueryFieldsFromSchema(this.fieldSchemaFields)
this.advancedQueryData.rows = createAdvancedQueryDataFromSchema(queryFields).rows
} else {
this.fieldSchemaFields = []
this.advancedQueryData.rows = []
this.$message.error((data && data.msg) || 'Failed to load field permissions')
}
this.refreshTableLayout()
}).catch(() => {
this.fieldSchemaFields = []
this.advancedQueryData.rows = []
this.$message.error('Failed to load field permissions')
this.refreshTableLayout()
})
},
handleListResponse(data) {
if (data.code === 0) {
this.dataList = ((data.page && data.page.list) || []).map(row => normalizeSchemaRowValues(row))
this.pageIndex = data.page.currPage
this.pageSize = data.page.pageSize
this.totalPage = data.page.totalCount
if (this.dataList.length > 0) {
this.$nextTick(() => {
if (this.$refs.poTable) {
this.$refs.poTable.setCurrentRow(this.dataList[0])
}
this.changeData(this.dataList[0])
})
} else {
this.currentRow = {}
this.clearDetailTabs()
}
} else {
this.$message.error((data && data.msg) || 'Failed to get list')
}
},
getDataList() {
if (!this.searchData.customer) {
this.loading = false
this.dataList = []
this.totalPage = 0
this.currentRow = {}
this.clearDetailTabs()
this.refreshTableLayout()
return
}
this.loading = true
const { params, useAdvanced } = this.buildQueryRequest()
const request = useAdvanced ? searchPoDetailAdvancedPage(params) : searchPoDetailPage(params)
request.then(({ data }) => {
this.handleListResponse(data)
this.loading = false
this.refreshTableLayout()
}).catch(() => {
this.loading = false
this.$message.error('Request failed')
this.refreshTableLayout()
})
},
/** External reset: only clears top basic conditions, not advancedQueryData */
resetSearch() {
const currentCustomer = this.searchData.customer
this.searchData = {
site: this.$store.state.user.site,
customer: currentCustomer,
buyer: '',
poNo: '',
orderType: '',
partNo: '',
supplierNo: '',
sku: '',
status: '',
supplierName: '',
feeDateStart: '',
feeDateEnd: ''
}
this.pageIndex = 1
this.getDataList()
},
openSearchBaseList (val) {
this.eamTagNo = val
let strVal = ''
let conSql = ''
if (val === 520) {
strVal = this.searchData.supplierNo || ''
conSql = " and supplier_no <> '' "
} else if (val === 2017) {
strVal = this.searchData.partNo || ''
conSql = " and part_no <> '' "
}
this.$nextTick(() => {
this.$refs.eamList.init(val, strVal, conSql)
})
},
getEamData (val) {
if (this.eamTagNo === 520) {
this.searchData.supplierNo = val.supplier_no || val.code || ''
this.searchData.supplierName = val.supplier_name || val.name || ''
} else if (this.eamTagNo === 2017) {
this.searchData.partNo = val.part_no || val.code || ''
}
this.eamTagNo = ''
},
// Export
exportExcel () {
if (!this.searchData.customer) {
this.$message.warning('Please select Customer first')
return
}
const now = new Date()
const year = now.getFullYear()
const month = String(now.getMonth() + 1).padStart(2, '0')
const day = String(now.getDate()).padStart(2, '0')
const hour = String(now.getHours()).padStart(2, '0')
const minute = String(now.getMinutes()).padStart(2, '0')
const second = String(now.getSeconds()).padStart(2, '0')
const exportName = `PO Order List ${year}${month}${day}${hour}${minute}${second}`
const { params, useAdvanced } = buildPoOrderQueryParams({
searchData: this.searchData,
advancedQueryData: this.advancedQueryData,
page: 1,
limit: 99999
})
try {
excel.exportTable({
url: useAdvanced ? 'pODetail/advancedPage' : 'pODetail/page',
columnMapping: this.visibleColumns,
mergeSetting: [],
params,
fileName: exportName + '.xlsx',
rowFetcher: res => {
const page = res.data && res.data.page
const rows = ((page && page.list) || []).map(row => normalizeSchemaRowValues(row))
return { rows }
},
columnFormatter: [],
dropColumns: []
})
} catch (error) {
this.$message.error('Export failed: ' + error.message)
}
},
// Page size
sizeChangeHandle(val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
// Current page
currentChangeHandle(val) {
this.pageIndex = val
this.getDataList()
},
// Row click event (similar to supplierList.vue changeData pattern)
changeData(row) {
if (!row) {
this.currentRow = {}
this.clearDetailTabs()
return
}
this.currentRow = JSON.parse(JSON.stringify(row))
this.refreshCurrentTabTable()
},
// Refresh current tab table data (similar to supplierList.vue refreshCurrentTabTable)
refreshCurrentTabTable() {
if (!this.hasCurrentRowData()) {
this.clearDetailTabs()
return
}
if (this.activeTab === 'orderDetail') {
// Order detail does not need refresh, display currentRow directly
}
if (this.activeTab === 'logistics') {
this.refreshLogisticsTable()
}
if (this.activeTab === 'inspectionDetail') {
this.refreshInspectionTable()
}
if (this.activeTab === 'partAttribute') {
this.refreshPartAttribute()
}
},
getDetailTabHeight () {
return Number(this.height) - 20
},
hasCurrentRowData () {
return !!(this.currentRow && typeof this.currentRow === 'object' && Object.keys(this.currentRow).length > 0)
},
clearDetailTabs () {
const site = this.searchData.site || this.$store.state.user.site
const height = this.getDetailTabHeight()
if (this.$refs.logisticsPoList && this.$refs.logisticsPoList.init) {
this.$refs.logisticsPoList.init({
flexId: '',
supplierNo: '',
site,
height
})
}
if (this.$refs.inspectionDetailList && this.$refs.inspectionDetailList.init) {
this.$refs.inspectionDetailList.init({
site,
orderNo: '',
itemNo: null,
height
})
}
if (this.$refs.partAttributeTab && this.$refs.partAttributeTab.init) {
this.$refs.partAttributeTab.init({
site,
partNo: '',
codeNo: '',
functionType: 'P',
height
})
}
},
// Refresh logistics tab table (similar to supplierList.vue refreshShareTable)
refreshLogisticsTable() {
if (!this.hasCurrentRowData()) {
this.clearDetailTabs()
return
}
let inData = {
flexId: this.currentRow.flexid,
supplierNo: this.currentRow.supplierNo,
site: this.$store.state.user.site,
height: this.getDetailTabHeight()
}
this.$refs.logisticsPoList.init(inData)
},
// Refresh inspection detail tab table
refreshInspectionTable() {
if (!this.hasCurrentRowData()) {
this.clearDetailTabs()
return
}
let inData = {
site: this.$store.state.user.site,
orderNo: this.currentRow.orderNo || '',
itemNo: this.currentRow.itemNo || null,
height: this.getDetailTabHeight()
}
this.$refs.inspectionDetailList.init(inData)
},
refreshPartAttribute () {
if (!this.hasCurrentRowData()) {
this.clearDetailTabs()
return
}
const site = this.currentRow.site || this.$store.state.user.site
const partNo = this.currentRow.partNo || ''
const inData = {
site,
partNo,
codeNo: this.currentRow.codeNo || '',
functionType: 'P',
height: this.getDetailTabHeight()
}
if (!partNo) {
this.initPartAttributeTab(inData)
return
}
if (inData.codeNo) {
this.initPartAttributeTab(inData)
return
}
searchPartInfo({ site, partNo }).then(({ data }) => {
const codeNo = (data && data.code === 0 && data.data)
? (data.data.codeNo || data.data.code_no || '')
: ''
this.$set(this.currentRow, 'codeNo', codeNo)
this.initPartAttributeTab({
...inData,
codeNo
})
}).catch(() => {
this.initPartAttributeTab(inData)
})
},
initPartAttributeTab (inData) {
if (this.$refs.partAttributeTab && this.$refs.partAttributeTab.init) {
this.$refs.partAttributeTab.init(inData)
}
},
// Tab click event (similar to supplierList.vue tabClick)
handleTabClick(tab, event) {
this.refreshCurrentTabTable()
}
}
}
</script>
<style scoped lang="scss">
.el-table /deep/ .cell {
height: auto;
line-height: 1.5;
}
/deep/ .customer-tab .el-tabs__content {
padding: 5px !important;
}
</style>

2
src/views/modules/sys/menu-add-or-update.vue

@ -38,7 +38,7 @@
<el-input style="width: 349px;" v-model="dataForm.parentName" v-popover:menuListPopover :readonly="true" class="menu-list__input"></el-input>
</el-form-item>
<el-form-item v-if="dataForm.type === 1" :label="buttons.route || '菜单路由'" prop="url">
<el-input style="width: 349px;" v-model="dataForm.url" placeholder="菜单路由"></el-input>
<el-input :readonly="dataForm.id?true:false" style="width: 349px;" v-model="dataForm.url" placeholder="菜单路由"></el-input>
</el-form-item>
<el-form-item v-if="dataForm.type !== 0" :label="buttons.perms || '授权标识'" prop="perms">
<el-input style="width: 349px;" v-model="dataForm.perms" placeholder="多个用逗号分隔, 如: user:list,user:create"></el-input>

4
src/views/modules/sys/menu.vue

@ -40,7 +40,7 @@
<template slot-scope="scope">
<el-link v-if="scope.row.type === 0" type="success">目录</el-link>
<el-link v-else-if="scope.row.type === 1" size="small" type="success">{{buttons.menu||'菜单'}}菜单</el-link>
<el-link v-else-if="scope.row.type === 1" size="small" type="success">{{buttons.menu||'菜单'}}</el-link>
<el-link v-else-if="scope.row.type === 2" size="small" type="info">{{buttons.button||'按钮'}}</el-link>
</template>
</el-table-column>
@ -74,7 +74,7 @@
:label="buttons.cz||'操作'">
<template slot-scope="scope">
<a v-if="isAuth('sys:menu:update')" type="text" size="small" @click="addOrUpdateHandle(scope.row.menuId)">{{buttons.edit||'修改'}}</a>
<a v-if="isAuth('sys:menu:delete')" type="text" size="small" @click="deleteHandle(scope.row.menuId)">{{buttons.delete||'删除'}}</a>
<a v-if="isAuth('sys:menu:delete') && scope.row.type !== 1" type="text" size="small" @click="deleteHandle(scope.row.menuId)">{{buttons.delete||'删除'}}</a>
<!-- <a type="text" size="small" @click="addOrUpdateLanguage(scope.row.menuId)">{{buttons.language||'语言'}}</a>-->
<!-- <a v-if="isAuth('sys:oss:all') && scope.row.type === 1 " type="text" size="small" @click="helpFileList(scope.row.menuId)">-->
<!-- {{buttons.helpFile || '帮助文档'}}</a>-->

Loading…
Cancel
Save