Merge remote-tracking branch 'origin/0.8.X' into 0.8.X
This commit is contained in:
@@ -26,6 +26,15 @@ export function addProduct(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 新增产品带默认BOM
|
||||
export function addProductWithBom(data) {
|
||||
return request({
|
||||
url: '/wms/product/addWithBom',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改产品
|
||||
export function updateProduct(data) {
|
||||
return request({
|
||||
|
||||
@@ -26,6 +26,15 @@ export function addRawMaterial(data) {
|
||||
})
|
||||
}
|
||||
|
||||
// 新增原材料带默认BOM
|
||||
export function addRawMaterialWithBom(data) {
|
||||
return request({
|
||||
url: '/wms/rawMaterial/addWithBom',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改原材料
|
||||
export function updateRawMaterial(data) {
|
||||
return request({
|
||||
|
||||
1
klp-ui/src/assets/icons/svg/coil.svg
Normal file
1
klp-ui/src/assets/icons/svg/coil.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.0 KiB |
397
klp-ui/src/components/HomeModules/AllApplications.vue
Normal file
397
klp-ui/src/components/HomeModules/AllApplications.vue
Normal file
@@ -0,0 +1,397 @@
|
||||
<template>
|
||||
<div class="all-applications-container">
|
||||
<!-- 常用应用区域 -->
|
||||
<div class="frequently-used-section">
|
||||
<div class="frequently-used-header">
|
||||
<h3 class="frequently-title">常用应用</h3>
|
||||
<el-button
|
||||
type="text"
|
||||
size="small"
|
||||
class="edit-btn"
|
||||
@click="isEditingFavorites = !isEditingFavorites"
|
||||
>
|
||||
{{ isEditingFavorites ? '完成' : '编辑' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div class="frequently-used-grid" v-if="frequentlyUsedApps.length > 0">
|
||||
<div
|
||||
v-for="app in frequentlyUsedApps"
|
||||
:key="`fav-${app.parentPath}-${app.childPath}`"
|
||||
class="frequently-app-item"
|
||||
@click="handleAppClick(getParentMenu(app.parentPath), getChildMenu(app.parentPath, app.childPath))"
|
||||
>
|
||||
<div class="app-icon-wrapper">
|
||||
<svg-icon :icon-class="getChildMenu(app.parentPath, app.childPath).meta.icon || 'documentation'" class="app-icon" />
|
||||
</div>
|
||||
<span class="app-name">{{ getChildMenu(app.parentPath, app.childPath).meta.title }}</span>
|
||||
|
||||
<!-- 删除按钮 - 仅在编辑模式显示 -->
|
||||
<div
|
||||
class="remove-btn"
|
||||
v-if="isEditingFavorites"
|
||||
@click.stop="removeFromFavorites(app.parentPath, app.childPath)"
|
||||
>
|
||||
<i class="el-icon-close"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<el-empty description="暂无常用应用" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 原有全部应用区域 -->
|
||||
<h3 class="title" v-if="isEditingFavorites">全部应用</h3>
|
||||
<el-tabs v-model="activeTabName" class="app-tabs" v-if="isEditingFavorites">
|
||||
<el-tab-pane
|
||||
v-for="menu in filteredMenus"
|
||||
:key="menu.path"
|
||||
:label="menu.meta.title"
|
||||
:name="menu.path"
|
||||
>
|
||||
<div class="app-grid">
|
||||
<div
|
||||
v-for="child in menu.children"
|
||||
:key="child.path"
|
||||
class="app-item"
|
||||
>
|
||||
<!-- @click="handleAppClick(menu, child)" -->
|
||||
<div class="app-icon-wrapper">
|
||||
<svg-icon :icon-class="child.meta.icon || 'documentation'" class="app-icon" />
|
||||
|
||||
<!-- 添加到常用按钮 -->
|
||||
<div
|
||||
class="add-to-favorite-btn"
|
||||
@click.stop="addToFavorites(menu.path, child.path)"
|
||||
v-if="!isInFavorites(menu.path, child.path)"
|
||||
>
|
||||
<i class="el-icon-star-off"></i>
|
||||
</div>
|
||||
|
||||
<!-- 已在常用中的标识 -->
|
||||
<div
|
||||
class="in-favorite-indicator"
|
||||
v-if="isInFavorites(menu.path, child.path)"
|
||||
>
|
||||
<i class="el-icon-star-on"></i>
|
||||
</div>
|
||||
</div>
|
||||
<span class="app-name">{{ child.meta.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getRouters } from '@/api/menu'
|
||||
import path from 'path'
|
||||
|
||||
export default {
|
||||
name: 'AllApplications',
|
||||
data() {
|
||||
return {
|
||||
allMenus: [],
|
||||
activeTabName: '',
|
||||
frequentlyUsedApps: [], // 存储常用应用
|
||||
isEditingFavorites: false // 是否处于编辑常用应用模式
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredMenus() {
|
||||
const filterHidden = (menus) => {
|
||||
return menus
|
||||
.filter(menu => menu.hidden !== true)
|
||||
.map(menu => {
|
||||
if (menu.children) {
|
||||
menu.children = filterHidden(menu.children)
|
||||
}
|
||||
return menu
|
||||
})
|
||||
}
|
||||
const topLevelMenus = filterHidden(this.allMenus).filter(
|
||||
menu => menu.children && menu.children.length > 0
|
||||
)
|
||||
return topLevelMenus
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchMenus()
|
||||
this.loadFrequentlyUsedApps()
|
||||
},
|
||||
methods: {
|
||||
fetchMenus() {
|
||||
getRouters().then(response => {
|
||||
this.allMenus = response.data
|
||||
if (this.filteredMenus.length > 0) {
|
||||
this.activeTabName = this.filteredMenus[0].path
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 加载常用应用(从localStorage)
|
||||
loadFrequentlyUsedApps() {
|
||||
const saved = localStorage.getItem('frequentlyUsedApps')
|
||||
if (saved) {
|
||||
try {
|
||||
this.frequentlyUsedApps = JSON.parse(saved)
|
||||
} catch (e) {
|
||||
console.error('Failed to parse frequently used apps', e)
|
||||
this.frequentlyUsedApps = []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 保存常用应用到localStorage
|
||||
saveFrequentlyUsedApps() {
|
||||
localStorage.setItem('frequentlyUsedApps', JSON.stringify(this.frequentlyUsedApps))
|
||||
},
|
||||
|
||||
// 添加到常用应用
|
||||
addToFavorites(parentPath, childPath) {
|
||||
if (!this.isInFavorites(parentPath, childPath)) {
|
||||
// 限制最多10个常用应用
|
||||
if (this.frequentlyUsedApps.length >= 10) {
|
||||
this.$message.warning('常用应用最多只能添加10个')
|
||||
return
|
||||
}
|
||||
|
||||
this.frequentlyUsedApps.unshift({ parentPath, childPath })
|
||||
this.saveFrequentlyUsedApps()
|
||||
this.$message.success('已添加到常用应用')
|
||||
}
|
||||
},
|
||||
|
||||
// 从常用应用中移除
|
||||
removeFromFavorites(parentPath, childPath) {
|
||||
this.frequentlyUsedApps = this.frequentlyUsedApps.filter(
|
||||
app =>!(app.parentPath === parentPath && app.childPath === childPath)
|
||||
)
|
||||
this.saveFrequentlyUsedApps()
|
||||
},
|
||||
|
||||
// 检查应用是否在常用列表中
|
||||
isInFavorites(parentPath, childPath) {
|
||||
return this.frequentlyUsedApps.some(
|
||||
app => app.parentPath === parentPath && app.childPath === childPath
|
||||
)
|
||||
},
|
||||
|
||||
// 根据路径获取父菜单
|
||||
getParentMenu(parentPath) {
|
||||
return this.filteredMenus.find(menu => menu.path === parentPath)
|
||||
},
|
||||
|
||||
// 根据路径获取子菜单
|
||||
getChildMenu(parentPath, childPath) {
|
||||
const parent = this.getParentMenu(parentPath)
|
||||
if (parent && parent.children) {
|
||||
return parent.children.find(child => child.path === childPath)
|
||||
}
|
||||
return {
|
||||
meta: {}
|
||||
}
|
||||
},
|
||||
|
||||
handleAppClick(parentMenu, childMenu) {
|
||||
if (!childMenu) return
|
||||
|
||||
const basePath = parentMenu.path
|
||||
const fullPath = path.resolve(basePath, childMenu.path)
|
||||
this.$router.push(fullPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.all-applications-container {
|
||||
padding: 16px; /* 调整间距,更贴近飞书紧凑感 */
|
||||
border-radius: 12px; /* 飞书常用较大圆角 */
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
// 常用应用样式
|
||||
.frequently-used-section {
|
||||
margin-bottom: 32px; /* 增大间距 */
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #ddd; /* 飞书浅灰边框色 */
|
||||
}
|
||||
|
||||
.frequently-used-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
// margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.frequently-title {
|
||||
font-size: 16px; /* 稍小字体,飞书风格更简洁 */
|
||||
font-weight: 500; /* 调整 FontWeight */
|
||||
color: #111; /* 深一点的标题色 */
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
color: #687b98; /* 飞书常用的主题蓝 */
|
||||
padding: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.frequently-used-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); /* 调整卡片宽度 */
|
||||
gap: 20px; /* 增大间距 */
|
||||
}
|
||||
|
||||
.frequently-app-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 16px; /* 调整内边距 */
|
||||
border-radius: 12px; /* 大圆角 */
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
// background-color: ; /* 飞书卡片常用浅灰底色 */
|
||||
|
||||
&:hover {
|
||||
background-color: #fff; /* hover 时的浅灰 */
|
||||
}
|
||||
}
|
||||
|
||||
// 全部应用标题
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
// 应用网格布局
|
||||
.app-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); /* 调整卡片宽度 */
|
||||
gap: 24px; /* 增大间距 */
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.app-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
transition: background-color 0.3s ease;
|
||||
position: relative;
|
||||
// background-color: #222;
|
||||
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
// 应用图标样式
|
||||
.app-icon-wrapper {
|
||||
width: 48px; /* 稍小图标容器 */
|
||||
height: 48px;
|
||||
border-radius: 10px; /* 图标容器圆角 */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 12px;
|
||||
background-color: #fff; /* 飞书风格的浅蓝底色 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.app-icon {
|
||||
font-size: 24px; /* 调整图标大小 */
|
||||
color: #687b98; /* 主题蓝 */
|
||||
}
|
||||
|
||||
// 应用名称样式
|
||||
.app-name {
|
||||
font-size: 14px;
|
||||
color: #687b98; /* 飞书常用的文本色 */
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// 添加到常用按钮
|
||||
.add-to-favorite-btn {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 4px;
|
||||
width: 24px; /* 稍大按钮 */
|
||||
height: 24px;
|
||||
border-radius: 6px; /* 小圆角 */
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #c0c4cc;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
color: #ffb400; /* 飞书常用的强调色 */
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
// 已在常用中的标识
|
||||
.in-favorite-indicator {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 4px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 6px;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 14px;
|
||||
color: #ffb400;
|
||||
}
|
||||
|
||||
// 删除常用应用按钮
|
||||
.remove-btn {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 6px;
|
||||
background-color: #ff4d4f; /* 飞书删除按钮红 */
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: #ff3839;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
// 标签页样式
|
||||
::v-deep .el-tabs__header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
::v-deep .el-tabs__nav-wrap::after {
|
||||
height: 1px;
|
||||
}
|
||||
</style>
|
||||
0
klp-ui/src/components/HomeModules/DetailTable.vue
Normal file
0
klp-ui/src/components/HomeModules/DetailTable.vue
Normal file
132
klp-ui/src/components/HomeModules/FlowTable.vue
Normal file
132
klp-ui/src/components/HomeModules/FlowTable.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="order-analysis-dashboard" v-loading="loading">
|
||||
<!-- 业绩区 -->
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="我的流程" name="my">
|
||||
<KLPTable v-loading="loading" :data="ownProcessList">
|
||||
<el-table-column label="流程编号" align="center" prop="procInsId" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="流程名称" align="center" prop="procDefName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="流程类别" align="center" prop="category" />
|
||||
<el-table-column label="流程版本" align="center" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium">v{{ scope.row.procDefVersion }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前节点" align="center" prop="taskName" />
|
||||
<el-table-column label="提交时间" align="center" prop="createTime" width="180" />
|
||||
<el-table-column label="流程状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.wf_process_status" :value="scope.row.processStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="耗时" align="center" prop="duration" width="180" />
|
||||
</KLPTable>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="代办任务" name="todo">
|
||||
<KLPTable v-loading="loading" :data="todoList">
|
||||
<el-table-column label="任务编号" align="center" prop="taskId" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="流程名称" align="center" prop="procDefName" />
|
||||
<el-table-column label="任务节点" align="center" prop="taskName" />
|
||||
<el-table-column label="流程版本" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="medium">v{{ scope.row.procDefVersion }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="流程发起人" align="center">
|
||||
<template slot-scope="scope">
|
||||
<label>{{ scope.row.startUserName }}</label>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="接收时间" align="center" prop="createTime" width="180" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit-outline" @click="handleProcess(scope.row)"
|
||||
v-hasPermi="['workflow:process:approval']">办理
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listOwnProcess } from '@/api/workflow/process';
|
||||
import { listTodoProcess } from '@/api/workflow/process';
|
||||
|
||||
export default {
|
||||
name: 'OrderAnalysisDashboard',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
activeTab: 'my',
|
||||
ownProcessList: [],
|
||||
todoList: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20
|
||||
},
|
||||
dateRange: []
|
||||
}
|
||||
},
|
||||
dicts: ['wf_process_status'],
|
||||
created() {
|
||||
this.loading = true;
|
||||
Promise.all([this.getList1(), this.getList2()]).then(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/** 查询流程定义列表 */
|
||||
async getList1() {
|
||||
const response = await listOwnProcess(this.addDateRange(this.queryParams, this.dateRange));
|
||||
this.ownProcessList = response.rows;
|
||||
},
|
||||
async getList2() {
|
||||
const response = await listTodoProcess(this.addDateRange(this.queryParams, this.dateRange));
|
||||
this.todoList = response.rows;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.order-analysis-dashboard {
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.section-row {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin-bottom: 20px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.section-title h2 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-title p {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.top-row,
|
||||
.chart-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart-row>.el-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
}
|
||||
</style>
|
||||
238
klp-ui/src/components/HomeModules/MiniCalendar.vue
Normal file
238
klp-ui/src/components/HomeModules/MiniCalendar.vue
Normal file
@@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<!-- 外层容器:占用 30% 宽度,可根据需要自行调样式 -->
|
||||
<div class="mini-calendar" style="">
|
||||
<!-- 日历头部,显示“YYYY年M月” -->
|
||||
<div class="calendar-header">
|
||||
<div>个人日历</div>
|
||||
<div>{{ currentMonthYear }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 日历主体:使用 table 简易排版,每周 7 列,只显示当前月的日期 -->
|
||||
<table class="calendar-body">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(day, index) in weekDays" :key="index">{{ day }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIndex) in calendarRows" :key="rowIndex">
|
||||
<td
|
||||
v-for="(cell, cellIndex) in row"
|
||||
:key="cellIndex"
|
||||
:class="getDayClass(cell.type)"
|
||||
>
|
||||
<!-- 只显示数字,不含任何额外文本 -->
|
||||
<span>{{ cell.dayNum }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- legend 区域:展示不同 type 的色块与说明 -->
|
||||
<div class="calendar-legend">
|
||||
<div class="legend-item" v-for="legend in legends" :key="legend.type">
|
||||
<span
|
||||
class="color-box"
|
||||
:style="{ backgroundColor: legend.color }"
|
||||
></span>
|
||||
<span class="legend-text">{{ legend.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MiniCalendar",
|
||||
/**
|
||||
* 父组件可以通过 :daysData 传入当前月的具体日期和 type。
|
||||
* 示例:[{ date: '2025-03-01', type: 1 }, { date: '2025-03-02', type: 2 }, ...]
|
||||
*/
|
||||
props: {
|
||||
daysData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 星期栏
|
||||
weekDays: ["日", "一", "二", "三", "四", "五", "六"],
|
||||
// legend 配置:type对应的背景色 + 说明
|
||||
legends: [
|
||||
{ type: 1, label: "休息日", color: "#d3f6f3" },
|
||||
{ type: 2, label: "节假日", color: "#ffe7ba" },
|
||||
{ type: 3, label: "调休", color: "#ffdede" },
|
||||
{ type: 4, label: "出差", color: "#fa18bc" },
|
||||
{ type: 5, label: "请假", color: "#c4c4eb" }
|
||||
]
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* 当前日期对象(默认为今天,也可自行改成其它月份)
|
||||
*/
|
||||
currentDate() {
|
||||
return new Date();
|
||||
},
|
||||
currentMonth() {
|
||||
return this.currentDate.getMonth(); // 0-11
|
||||
},
|
||||
currentYear() {
|
||||
return this.currentDate.getFullYear();
|
||||
},
|
||||
// 用于在日历头部显示“YYYY年M月”
|
||||
currentMonthYear() {
|
||||
return `${this.currentYear}年${this.currentMonth + 1}月`;
|
||||
},
|
||||
/**
|
||||
* 生成一个二维数组,每一行代表一周,单元格中有 { dayNum, dateStr, type }。
|
||||
* 只显示当月的日期,如果第一天不是周日,前面会插入空格。
|
||||
*/
|
||||
calendarRows() {
|
||||
// 当前月1号
|
||||
const firstDayOfMonth = new Date(this.currentYear, this.currentMonth, 1);
|
||||
const firstDayIndex = firstDayOfMonth.getDay(); // 0=周日,1=周一, ...
|
||||
|
||||
// 本月总天数
|
||||
const daysInMonth = new Date(this.currentYear, this.currentMonth + 1, 0).getDate();
|
||||
|
||||
// 准备一个空数组,往里放 dayNum 和 type
|
||||
const cells = [];
|
||||
// 1) 填充本月第一天前面的空白单元格
|
||||
for (let i = 0; i < firstDayIndex; i++) {
|
||||
cells.push({ dayNum: "", dateStr: "", type: null });
|
||||
}
|
||||
// 2) 填充本月每一天
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const dateObj = new Date(this.currentYear, this.currentMonth, day);
|
||||
const dateStr = this.formatDate(dateObj); // YYYY-MM-DD
|
||||
// 根据 daysData 查找 type
|
||||
const dayType = this.findDayType(dateStr);
|
||||
cells.push({
|
||||
dayNum: day,
|
||||
dateStr,
|
||||
type: dayType
|
||||
});
|
||||
}
|
||||
|
||||
// 3) 将 cells 拆分成多行,每行7列
|
||||
const rows = [];
|
||||
for (let i = 0; i < cells.length; i += 7) {
|
||||
rows.push(cells.slice(i, i + 7));
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 格式化 Date => "YYYY-MM-DD"
|
||||
*/
|
||||
formatDate(d) {
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
return `${year}-${month}-${day}`;
|
||||
},
|
||||
/**
|
||||
* 在 daysData 中找对应日期的 type,找不到就默认为 0(工作日)
|
||||
*/
|
||||
findDayType(dateStr) {
|
||||
const item = this.daysData.find((day) => day.date === dateStr);
|
||||
return item ? item.type : 0; // 默认工作日(0)
|
||||
},
|
||||
/**
|
||||
* 返回一个 class 用于设置对应背景色
|
||||
*/
|
||||
getDayClass(type) {
|
||||
switch (type) {
|
||||
case 0: return "type-workday"; // 工作日
|
||||
case 1: return "type-rest"; // 休息日
|
||||
case 2: return "type-holiday"; // 节假日
|
||||
case 3: return "type-adjust"; // 调休
|
||||
case 4: return "type-trip"; // 出差
|
||||
case 5: return "type-leave"; // 请假
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.mini-calendar {
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
box-sizing: border-box;
|
||||
/* 若需要更细节的布局控制,可以加上 float 或 display 属性,比如 float: left; */
|
||||
}
|
||||
|
||||
/* 日历头部 */
|
||||
.calendar-header {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 日历主体样式 */
|
||||
.calendar-body {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.calendar-body th,
|
||||
.calendar-body td {
|
||||
width: 14.28%; /* 7天 */
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 不同 type 的背景色 */
|
||||
.type-workday {
|
||||
background-color: transparent;
|
||||
}
|
||||
.type-rest {
|
||||
background-color: #d3f6f3;
|
||||
}
|
||||
.type-holiday {
|
||||
background-color: #ffe7ba;
|
||||
}
|
||||
.type-adjust {
|
||||
background-color: #ffdede;
|
||||
}
|
||||
.type-trip {
|
||||
background-color: #c6ebf5;
|
||||
}
|
||||
.type-leave {
|
||||
background-color: #c4c4eb;
|
||||
}
|
||||
|
||||
/* legend 部分:展示各类型色块和说明 */
|
||||
.calendar-legend {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.color-box {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 4px;
|
||||
|
||||
}
|
||||
|
||||
.legend-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
309
klp-ui/src/components/HomeModules/StatisticGroup.vue
Normal file
309
klp-ui/src/components/HomeModules/StatisticGroup.vue
Normal file
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<el-row :gutter="10" class="panel-group">
|
||||
<el-col
|
||||
v-if="!loading"
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="4"
|
||||
:xl="4"
|
||||
class="card-panel-col"
|
||||
v-for="(item, index) in statsData"
|
||||
:key="index"
|
||||
>
|
||||
<div class="card-panel" @click="handleSetLineChartData(item.type)">
|
||||
<div class="card-panel-icon-wrapper" :class="item.iconClass">
|
||||
<svg-icon :icon-class="item.icon" class-name="card-panel-icon" />
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<count-to
|
||||
:start-val="0"
|
||||
:end-val="item.value"
|
||||
:duration="item.duration"
|
||||
class="card-panel-num"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<div v-else>
|
||||
<!-- 骨架屏 -->
|
||||
<el-skeleton
|
||||
:rows="1"
|
||||
:loading="loading"
|
||||
/>
|
||||
</div>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CountTo from 'vue-count-to'
|
||||
import { listProduct } from '@/api/wms/product'
|
||||
import { listRawMaterial } from '@/api/wms/rawMaterial'
|
||||
import { listMaterialCoil } from '@/api/wms/coil'
|
||||
import { listEquipmentManagement } from '@/api/mes/eqp/equipmentManagement'
|
||||
import { listOrder } from '@/api/wms/order'
|
||||
import { listCustomer } from '@/api/wms/customer'
|
||||
import { listSupplier } from '@/api/wms/supplier'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CountTo
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statsData: [
|
||||
{
|
||||
type: 'materialCount',
|
||||
title: '物料类型',
|
||||
icon: 'international',
|
||||
iconClass: 'icon-material',
|
||||
value: 0,
|
||||
duration: 2600
|
||||
},
|
||||
{
|
||||
type: 'steelCoilCount',
|
||||
title: '钢卷数量',
|
||||
icon: 'coil',
|
||||
iconClass: 'icon-steel',
|
||||
value: 0,
|
||||
duration: 3000
|
||||
},
|
||||
{
|
||||
type: 'orderCount',
|
||||
title: '订单数量',
|
||||
icon: 'log',
|
||||
iconClass: 'icon-order',
|
||||
value: 0,
|
||||
duration: 3200
|
||||
},
|
||||
{
|
||||
type: 'customerCount',
|
||||
title: '客户',
|
||||
icon: 'people',
|
||||
iconClass: 'icon-customer',
|
||||
value: 0,
|
||||
duration: 3600
|
||||
},
|
||||
{
|
||||
type: 'supplierCount',
|
||||
title: '供应商',
|
||||
icon: 'peoples',
|
||||
iconClass: 'icon-supplier',
|
||||
value: 0,
|
||||
duration: 3600
|
||||
},
|
||||
{
|
||||
type: 'equipmentCount',
|
||||
title: '设备数量',
|
||||
icon: 'redis',
|
||||
iconClass: 'icon-equipment',
|
||||
value: 0,
|
||||
duration: 2800
|
||||
}
|
||||
],
|
||||
loading: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadCount()
|
||||
},
|
||||
methods: {
|
||||
handleSetLineChartData(type) {
|
||||
this.$emit('handleSetLineChartData', type)
|
||||
},
|
||||
loadCount() {
|
||||
this.loading = true
|
||||
Promise.all([
|
||||
listProduct({ pageSise: 1, pageNum: 1 }),
|
||||
listRawMaterial({ pageSise: 1, pageNum: 1 }),
|
||||
listMaterialCoil({ pageSise: 1, pageNum: 1 }),
|
||||
listEquipmentManagement({ pageSise: 1, pageNum: 1 }),
|
||||
listOrder({ pageSise: 1, pageNum: 1 }),
|
||||
listCustomer({ pageSise: 1, pageNum: 1 }),
|
||||
listSupplier({ pageSise: 1, pageNum: 1 })
|
||||
]).then(([
|
||||
productRes,
|
||||
rawMaterialRes,
|
||||
materialCoilRes,
|
||||
equipmentRes,
|
||||
orderRes,
|
||||
customerRes,
|
||||
supplierRes
|
||||
]) => {
|
||||
this.loading = false
|
||||
this.statsData.forEach(item => {
|
||||
if (item.type === 'materialCount') {
|
||||
item.value = productRes.total + rawMaterialRes.total
|
||||
} else if (item.type === 'steelCoilCount') {
|
||||
item.value = materialCoilRes.total
|
||||
} else if (item.type === 'orderCount') {
|
||||
item.value = orderRes.total
|
||||
} else if (item.type === 'customerCount') {
|
||||
item.value = customerRes.total
|
||||
} else if (item.type === 'supplierCount') {
|
||||
item.value = supplierRes.total
|
||||
} else if (item.type === 'equipmentCount') {
|
||||
item.value = equipmentRes.total
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.panel-group {
|
||||
margin-top: 18px;
|
||||
|
||||
.card-panel-col {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.card-panel {
|
||||
height: 108px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
color: #666;
|
||||
background: #fff;
|
||||
box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
|
||||
border-color: rgba(0, 0, 0, .05);
|
||||
|
||||
&:hover {
|
||||
.card-panel-icon-wrapper {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.icon-material {
|
||||
background: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-steel {
|
||||
background: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-order {
|
||||
background: #f4516c;
|
||||
}
|
||||
|
||||
.icon-customer {
|
||||
background: #34bfa3;
|
||||
}
|
||||
|
||||
.icon-equipment {
|
||||
background: #722ed1;
|
||||
}
|
||||
|
||||
.icon-supplier {
|
||||
background: #ffed65;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-material {
|
||||
color: #40c9c6;
|
||||
}
|
||||
|
||||
.icon-steel {
|
||||
color: #36a3f7;
|
||||
}
|
||||
|
||||
.icon-order {
|
||||
color: #f4516c;
|
||||
}
|
||||
|
||||
.icon-customer {
|
||||
color: #34bfa3;
|
||||
}
|
||||
|
||||
.icon-equipment {
|
||||
color: #722ed1;
|
||||
}
|
||||
|
||||
.icon-supplier {
|
||||
color: #ffed65;
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: left;
|
||||
margin: 14px 0 0 14px;
|
||||
padding: 16px;
|
||||
transition: all 0.38s ease-out;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-panel-icon {
|
||||
float: left;
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.card-panel-description {
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin: 26px;
|
||||
margin-left: 0px;
|
||||
|
||||
.card-panel-text {
|
||||
line-height: 18px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.card-panel-num {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.card-panel-description .card-panel-text {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card-panel-num {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.card-panel-description {
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.card-panel-icon {
|
||||
font-size: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.card-panel-description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.card-panel-icon-wrapper {
|
||||
float: none !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 !important;
|
||||
|
||||
.svg-icon {
|
||||
display: block;
|
||||
margin: 14px auto !important;
|
||||
float: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<span class="product-name" @click="clickHandle">
|
||||
<span class="product-name" @click.stop="clickHandle">
|
||||
<slot name="default" :product="product">
|
||||
{{ product && product.productName ? product.productName : '--' }}
|
||||
</slot>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 作用域插槽 -->
|
||||
<span class="material-name" @click="showDetail = true">
|
||||
<span class="material-name" @click.stop="showDetail = true">
|
||||
<slot name="default" :material="material">
|
||||
{{ material.rawMaterialName ? material.rawMaterialName : '-' }}
|
||||
</slot>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
<div class="card-panel-description">
|
||||
<div class="card-panel-text">
|
||||
访客
|
||||
物料统计
|
||||
</div>
|
||||
<count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
|
||||
</div>
|
||||
|
||||
@@ -1,39 +1,84 @@
|
||||
<template>
|
||||
<div class="dashboard-root">
|
||||
<!-- 全部应用 -->
|
||||
<el-row>
|
||||
<AllApplications />
|
||||
</el-row>
|
||||
<div class="dashboard-editor-container">
|
||||
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<el-col :span="12">
|
||||
<el-card style="height: 500px;">
|
||||
<FlowTable />
|
||||
</el-card>
|
||||
<statistic-group />
|
||||
|
||||
<AllApplications />
|
||||
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="18">
|
||||
<flow-table />
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<mini-calendar />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AllApplications from '@/views/components/AllApplications.vue';
|
||||
import OrderDashboard from '@/views/components/OrderDashboard.vue';
|
||||
import FlowTable from '@/views/components/FlowTable.vue';
|
||||
import Greeting from '@/views/components/Greeting.vue';
|
||||
import StatisticGroup from '@/components/HomeModules/StatisticGroup.vue'
|
||||
import AllApplications from '@/components/HomeModules/AllApplications.vue'
|
||||
import FlowTable from '@/components/HomeModules/FlowTable.vue'
|
||||
import MiniCalendar from '@/components/HomeModules/MiniCalendar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AllApplications,
|
||||
OrderDashboard,
|
||||
FlowTable,
|
||||
Greeting
|
||||
const lineChartData = {
|
||||
newVisitis: {
|
||||
expectedData: [100, 120, 161, 134, 105, 160, 165],
|
||||
actualData: [120, 82, 91, 154, 162, 140, 145]
|
||||
},
|
||||
messages: {
|
||||
expectedData: [200, 192, 120, 144, 160, 130, 140],
|
||||
actualData: [180, 160, 151, 106, 145, 150, 130]
|
||||
},
|
||||
purchases: {
|
||||
expectedData: [80, 100, 121, 104, 105, 90, 100],
|
||||
actualData: [120, 90, 100, 138, 142, 130, 130]
|
||||
},
|
||||
shoppings: {
|
||||
expectedData: [130, 140, 141, 142, 145, 150, 160],
|
||||
actualData: [120, 82, 91, 154, 162, 140, 130]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Index',
|
||||
components: {
|
||||
// PanelGroup,
|
||||
StatisticGroup,
|
||||
AllApplications,
|
||||
FlowTable,
|
||||
MiniCalendar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lineChartData: lineChartData.newVisitis
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSetLineChartData(type) {
|
||||
this.lineChartData = lineChartData[type]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.dashboard-root {
|
||||
min-height: 100vh;
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-editor-container {
|
||||
padding: 32px;
|
||||
background-color: rgb(240, 242, 245);
|
||||
position: relative;
|
||||
|
||||
.chart-wrapper {
|
||||
background: #fff;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@media (max-width:1024px) {
|
||||
.chart-wrapper {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-container">
|
||||
<el-table :data="list" border stripe style="width: 100%; margin-top: 20px" @row-click="handleTableRowClick"
|
||||
<el-table max-height="400" :data="list" border stripe style="width: 100%; margin-top: 20px" @row-click="handleTableRowClick"
|
||||
row-class-name="table-row-hover">
|
||||
<!-- 仓库相关列:仅仓库统计时有效 -->
|
||||
<el-table-column v-if="queryParams.statType === '2'" prop="warehouseName" label="仓库名称" align="center"
|
||||
@@ -95,17 +95,17 @@
|
||||
</template>
|
||||
|
||||
<!-- 钻取表格 -->
|
||||
<el-table v-loading="drillDownLoading" :data="drillDownList" border stripe style="width: 100%"
|
||||
<el-table max-height="400" v-loading="drillDownLoading" :data="drillDownList" border stripe style="width: 100%"
|
||||
v-if="!drillDownLoading">
|
||||
<el-table-column prop="warehouseName" label="仓库名称" align="center" min-width="150"></el-table-column>
|
||||
<el-table-column prop="currentCoilNo" label="当前卷号" align="center" min-width="120"></el-table-column>
|
||||
<el-table-column prop="enterCoilNo" label="入场卷号" align="center" min-width="180"></el-table-column>
|
||||
<el-table-column label="库区" align="center" prop="itemType">
|
||||
<el-table-column label="物料类型" align="center" prop="itemType">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.itemType == 'product' ? '成品' : '原料' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物料信息" align="center" min-width="250">
|
||||
<el-table-column label="产品类型" align="center" min-width="250">
|
||||
<template slot-scope="scope">
|
||||
<ProductInfo v-if="scope.row.itemType === 'product'" :productId="scope.row.itemId">
|
||||
<template #default="{ product }">
|
||||
@@ -119,6 +119,7 @@
|
||||
</RawMaterialInfo>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" />
|
||||
<el-table-column prop="grossWeight" label="毛重(kg)" align="center" min-width="100"></el-table-column>
|
||||
<el-table-column prop="netWeight" label="净重(kg)" align="center" min-width="100"></el-table-column>
|
||||
</el-table>
|
||||
@@ -144,6 +145,7 @@ import MaterialSelect from "@/components/KLPService/MaterialSelect";
|
||||
import * as echarts from 'echarts';
|
||||
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
||||
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
|
||||
import { findItemWithBom } from "@/store/modules/category";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -531,8 +533,11 @@ export default {
|
||||
// 物料统计钻取
|
||||
this.drillDownParams.itemType = data.itemType;
|
||||
this.drillDownParams.itemId = data.itemId;
|
||||
this.drillDownParams.itemName = data.name;
|
||||
this.dialogTitle = `${data.itemType === 'product' ? '成品' : '原材料'}库存明细 - ${data.name}`;
|
||||
// 从store中获取物料名称
|
||||
const item = findItemWithBom(data.itemType, data.itemId);
|
||||
console.log('item', item, data);
|
||||
this.drillDownParams.itemName = item ? item.itemName : data.name;
|
||||
this.dialogTitle = `${data.itemType === 'product' ? '成品' : '原材料'}库存明细 - ${this.drillDownParams.itemName}`;
|
||||
} else if (data.warehouseId && data.warehouseName) {
|
||||
// 仓库统计钻取
|
||||
this.drillDownParams.warehouseId = data.warehouseId;
|
||||
|
||||
@@ -13,7 +13,8 @@ export default {
|
||||
return {
|
||||
qrcode: true,
|
||||
querys: {
|
||||
dataType: 0
|
||||
dataType: 0,
|
||||
itemType: 'raw_material'
|
||||
},
|
||||
labelType: '2'
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ export default {
|
||||
return {
|
||||
qrcode: true,
|
||||
querys: {
|
||||
dataType: 1
|
||||
dataType: 1,
|
||||
itemType: 'raw_material'
|
||||
},
|
||||
labelType: '2'
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@
|
||||
<el-input v-model="queryParams.supplierCoilNo" placeholder="请输入厂家原料卷号" clearable
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="班组" prop="team">
|
||||
<el-input v-model="queryParams.team" placeholder="请输入班组" clearable @keyup.enter.native="handleQuery" />
|
||||
<el-form-item label="更新时间" prop="updateTime">
|
||||
<el-date-picker v-model="queryParams.updateTime" type="daterange" value-format="yyyy-MM-dd HH:mm:ss"
|
||||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
@@ -50,14 +51,14 @@
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo" />
|
||||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo" />
|
||||
<el-table-column label="厂家原料卷号" align="center" prop="supplierCoilNo" />
|
||||
<el-table-column label="库区" align="center" prop="itemType">
|
||||
<el-table-column label="厂家卷号" align="center" prop="supplierCoilNo" />
|
||||
<el-table-column label="仓库" align="center" prop="warehouseName" />
|
||||
<el-table-column label="物料类型" align="center" prop="itemType">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.itemType == 'product' ? '成品' : '原料' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="仓库" align="center" prop="warehouseName" />
|
||||
<el-table-column label="物品" align="center" prop="itemName">
|
||||
<el-table-column label="产品类型" align="center" prop="itemName">
|
||||
<template slot-scope="scope">
|
||||
<ProductInfo v-if="scope.row.itemType == 'product'" :productId="scope.row.itemId">
|
||||
<template slot-scope="{ product }">
|
||||
@@ -76,9 +77,10 @@
|
||||
{{ scope.row.dataType == 0 ? '历史数据' : '当前数据' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" />
|
||||
<el-table-column label="二维码" v-if="qrcode">
|
||||
<template slot-scope="scope">
|
||||
<QRCode v-if="scope.row.dataType == 1" :content="scope.row.qrcodeRecordId" :size="50" />
|
||||
<QRCode :content="scope.row.qrcodeRecordId" :size="50" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="班组" align="center" prop="team" />
|
||||
@@ -122,17 +124,18 @@
|
||||
<el-form-item label="班组" prop="team">
|
||||
<el-input v-model="form.team" placeholder="请输入班组" />
|
||||
</el-form-item>
|
||||
<el-form-item label="库区" prop="itemType">
|
||||
<el-select v-model="form.itemType" placeholder="请选择库区">
|
||||
<el-form-item label="物料类型" prop="itemType">
|
||||
<el-select v-model="form.itemType" placeholder="请选择库区" @change="form.itemId = undefined">
|
||||
<el-option label="成品" value="product" />
|
||||
<el-option label="原料" value="raw_material" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物品ID" prop="itemId">
|
||||
<el-form-item label="产品类型" prop="itemId">
|
||||
<product-select v-if="form.itemType == 'product'" v-model="form.itemId" placeholder="请选择成品ID"
|
||||
style="width: 100%;" clearable />
|
||||
<raw-material-select v-else-if="form.itemType == 'raw_material'" v-model="form.itemId" placeholder="请选择原料ID"
|
||||
style="width: 100%;" clearable />
|
||||
<div v-else>请先选择产品类型</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
@@ -249,6 +252,7 @@ export default {
|
||||
parentCoilNos: undefined,
|
||||
itemId: undefined,
|
||||
status: undefined,
|
||||
updateTime: undefined,
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
@@ -282,7 +286,12 @@ export default {
|
||||
/** 查询钢卷物料列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listMaterialCoil(this.queryParams).then(response => {
|
||||
const { updateTime ,...query } = {
|
||||
...this.queryParams,
|
||||
startTime: this.queryParams.updateTime?.[0],
|
||||
endTime: this.queryParams.updateTime?.[1],
|
||||
}
|
||||
listMaterialCoil(query).then(response => {
|
||||
this.materialCoilList = response.rows;
|
||||
this.total = response.total;
|
||||
this.loading = false;
|
||||
@@ -305,9 +314,16 @@ export default {
|
||||
/** 预览标签 */
|
||||
handlePreviewLabel(row) {
|
||||
this.labelRender.visible = true;
|
||||
const item = findItemWithBom(row.itemType, row.itemId)
|
||||
// 寻找boms中bom键名为'材质'的
|
||||
const material = item?.boms?.find(bom => bom.attrKey === '材质')
|
||||
// 查找boms中bom键名为'规格'的
|
||||
const specification = item?.boms?.find(bom => bom.attrKey === '规格')
|
||||
this.labelRender.data = {
|
||||
...row,
|
||||
itemName: findItemWithBom(row.itemType, row.itemId)?.itemName || '',
|
||||
itemName: item?.itemName || '',
|
||||
material: material?.attrValue || '',
|
||||
specification: specification?.attrValue || '',
|
||||
};
|
||||
},
|
||||
/** 下载二维码 */
|
||||
|
||||
@@ -13,7 +13,8 @@ export default {
|
||||
return {
|
||||
qrcode: false,
|
||||
querys: {
|
||||
itemType: 'product'
|
||||
itemType: 'product',
|
||||
// dataType: 0
|
||||
},
|
||||
labelType: '3'
|
||||
}
|
||||
|
||||
@@ -144,12 +144,12 @@
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
<el-button
|
||||
<!-- <el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-document"
|
||||
@click="goLedger(scope.row)"
|
||||
>台账</el-button>
|
||||
>台账</el-button> -->
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
@@ -172,28 +172,28 @@
|
||||
<el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<!-- <el-divider>基础信息</el-divider> -->
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<!-- <el-row :gutter="20">
|
||||
<el-col :span="12"> -->
|
||||
<el-form-item label="产品编号" prop="productCode">
|
||||
<el-input v-model="form.productCode" placeholder="请输入产品编号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- </el-col>
|
||||
<el-col :span="12"> -->
|
||||
<el-form-item label="产品名称" prop="productName">
|
||||
<el-input v-model="form.productName" placeholder="请输入产品名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- </el-col>
|
||||
<el-col :span="12"> -->
|
||||
<el-form-item label="负责人" prop="owner">
|
||||
<el-input v-model="form.owner" :multiple="false" placeholder="请填写负责人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<!-- </el-col>
|
||||
<el-col :span="12"> -->
|
||||
<el-form-item label="计量单位" prop="unit">
|
||||
<el-input v-model="form.unit" placeholder="请输入计量单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- </el-col>
|
||||
</el-row> -->
|
||||
|
||||
<!-- <el-divider>分类信息</el-divider>
|
||||
<el-row :gutter="20">
|
||||
@@ -263,7 +263,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProduct, getProduct, delProduct, addProduct, updateProduct } from "@/api/wms/product";
|
||||
import { listProduct, getProduct, delProduct, addProduct, updateProduct, addProductWithBom } from "@/api/wms/product";
|
||||
import CategorySelect from '@/components/KLPService/CategorySelect';
|
||||
import CategoryRenderer from '@/components/KLPService/Renderer/CategoryRenderer.vue';
|
||||
import UserSelect from '@/components/KLPService/UserSelect';
|
||||
@@ -448,7 +448,7 @@ export default {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addProduct(this.form).then(response => {
|
||||
addProductWithBom(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
|
||||
@@ -153,12 +153,12 @@
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
<el-button
|
||||
<!-- <el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-document"
|
||||
@click="goLedger(scope.row)"
|
||||
>台账</el-button>
|
||||
>台账</el-button> -->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
@@ -297,7 +297,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listRawMaterial, getRawMaterial, delRawMaterial, addRawMaterial, updateRawMaterial } from "@/api/wms/rawMaterial";
|
||||
import { listRawMaterial, getRawMaterial, delRawMaterial, addRawMaterial, updateRawMaterial, addRawMaterialWithBom } from "@/api/wms/rawMaterial";
|
||||
import CategorySelect from "@/components/KLPService/CategorySelect/index.vue";
|
||||
import CategoryRenderer from '@/components/KLPService/Renderer/CategoryRenderer.vue';
|
||||
import BomPanel from '@/views/wms/bom/components/BomPanel.vue';
|
||||
@@ -504,7 +504,7 @@ export default {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addRawMaterial(this.form).then(response => {
|
||||
addRawMaterialWithBom(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
|
||||
@@ -28,12 +28,12 @@
|
||||
<KLPTable v-loading="loading" :data="stockList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="仓库" align="center" prop="warehouseName" />
|
||||
<el-table-column label="物品类型" align="center" prop="itemType">
|
||||
<el-table-column label="物料类型" align="center" prop="itemType">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.stock_item_type" :value="scope.row.itemType" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物品" align="center" prop="itemName">
|
||||
<el-table-column label="产品类型" align="center" prop="itemName">
|
||||
<template slot-scope="scope">
|
||||
<ProductInfo v-if="scope.row.itemType == 'product' || scope.row.itemType == 'semi'" :productId="scope.row.itemId">
|
||||
<template #default="{ product }">
|
||||
|
||||
Reference in New Issue
Block a user