库存盘点和项目的初版
This commit is contained in:
@@ -24,9 +24,18 @@
|
||||
</view>
|
||||
<view class="entry-item" @click="goExpress">
|
||||
<image class="entry-icon" src="/static/images/express.svg" mode="aspectFit"></image>
|
||||
<text class="entry-text">快递信息</text>
|
||||
<text class="entry-text">快递信息</text>
|
||||
</view>
|
||||
<view class="entry-item" @click="goProject">
|
||||
<image class="entry-icon" src="/static/images/project.png" mode="aspectFit"></image>
|
||||
<text class="entry-text">项目中心</text>
|
||||
</view>
|
||||
<view class="entry-item" @click="goStock">
|
||||
<image class="entry-icon" src="/static/images/stock.png" mode="aspectFit"></image>
|
||||
<text class="entry-text">库存盘点</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -81,7 +90,17 @@ export default {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/express/express'
|
||||
})
|
||||
}
|
||||
},
|
||||
goProject() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/project/project'
|
||||
})
|
||||
},
|
||||
goStock() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/wms/wms'
|
||||
})
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
139
pages/workbench/project/add.vue
Normal file
139
pages/workbench/project/add.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<view class="add-project-container">
|
||||
<uni-forms ref="form" :model="form" label-width="100" class="form-box">
|
||||
<uni-forms-item label="项目名称" name="projectName" required>
|
||||
<uni-easyinput v-model="form.projectName" placeholder="请输入项目名称" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目编号" name="projectNum" required>
|
||||
<uni-easyinput v-model="form.projectNum" placeholder="请输入项目编号" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目类型" name="projectType" required>
|
||||
<oa-dict-select v-model="form.projectType" dict-type="sys_project_type" placeholder="请选择项目类型" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="贸易类型" name="tradeType" required>
|
||||
<uni-data-select v-model="form.tradeType" :localdata="tradeTypeList" placeholder="请选择贸易类型" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="代号类型" name="projectCode" required>
|
||||
<oa-dict-select v-model="form.projectCode" dict-type="sys_project_code" placeholder="请选择代号类型" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="优先级" name="projectGrade" required>
|
||||
<oa-dict-select v-model="form.projectGrade" dict-type="sys_sort_grade" placeholder="请选择优先级" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="负责人" name="functionary" required>
|
||||
<uni-easyinput v-model="form.functionary" placeholder="请输入负责人" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目地址" name="address">
|
||||
<uni-easyinput v-model="form.address" placeholder="请输入项目地址" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目总金额" name="funds" required>
|
||||
<uni-easyinput v-model="form.funds" placeholder="请输入项目总金额" type="number" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="交货期" name="delivery" required>
|
||||
<uni-easyinput v-model="form.delivery" placeholder="请输入交货期" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目周期" name="period" required>
|
||||
<uni-datetime-picker v-model="form.period" type="daterange" rangeSeparator="至" start-placeholder="开始日期"
|
||||
end-placeholder="结束日期" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="质保期" name="guarantee">
|
||||
<uni-easyinput v-model="form.guarantee" placeholder="请输入质保期" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="预付款" name="prePay">
|
||||
<uni-easyinput v-model="form.prePay" placeholder="请输入预付款" type="number" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="项目介绍" name="introduction">
|
||||
<uni-easyinput v-model="form.introduction" type="textarea" placeholder="请输入项目介绍" />
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="备注" name="remark">
|
||||
<uni-easyinput v-model="form.remark" type="textarea" placeholder="请输入备注" />
|
||||
</uni-forms-item>
|
||||
<!-- <uni-forms-item label="附件" name="accessory">
|
||||
<uni-file-picker v-model="form.accessory" file-extname=".jpg,.png,.pdf,.doc,.docx" :limit="5" />
|
||||
</uni-forms-item> -->
|
||||
<view class="form-actions">
|
||||
<button type="primary" @click="submitForm">保存</button>
|
||||
</view>
|
||||
</uni-forms>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addProject } from '@/api/oa/project';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
projectName: '',
|
||||
projectNum: '',
|
||||
projectType: '',
|
||||
tradeType: '',
|
||||
projectCode: '',
|
||||
projectGrade: '',
|
||||
functionary: '',
|
||||
address: '',
|
||||
funds: '',
|
||||
delivery: '',
|
||||
period: [],
|
||||
guarantee: '',
|
||||
prePay: '',
|
||||
introduction: '',
|
||||
remark: '',
|
||||
accessory: []
|
||||
},
|
||||
tradeTypeList: [
|
||||
{ value: 0, text: '内贸' },
|
||||
{ value: 1, text: '外贸' }
|
||||
// TODO: 替换为实际字典数据
|
||||
],
|
||||
projectGradeList: [
|
||||
{ value: 'high', text: '高' },
|
||||
{ value: 'middle', text: '中' },
|
||||
{ value: 'low', text: '低' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm() {
|
||||
// 校验并提交表单
|
||||
this.$refs.form.validate().then(res => {
|
||||
if (res) {
|
||||
// TODO: 调用新增项目API
|
||||
console.log(res);
|
||||
const payload = {
|
||||
...res,
|
||||
beginTime: res.period[0] + ' 00:00:00',
|
||||
finishTime: res.period[1] + ' 00:00:00',
|
||||
accessory: ''
|
||||
}
|
||||
addProject(payload).then(_ => {
|
||||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||||
uni.navigateBack()
|
||||
})
|
||||
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.showToast({ title: '请完善信息', icon: 'none' });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.add-project-container {
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.form-box {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
box-shadow: 0 2rpx 12rpx #eee;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
margin-top: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
197
pages/workbench/project/detail.vue
Normal file
197
pages/workbench/project/detail.vue
Normal file
@@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<view class="detail-page">
|
||||
<view class="detail-header">
|
||||
<text class="header-title">{{ projectDetail.projectName }}</text>
|
||||
<text class="header-subtitle">{{ projectDetail.projectNum }}</text>
|
||||
</view>
|
||||
<view class="detail-content">
|
||||
<view style="display: flex; justify-content: flex-start; gap: 10rpx">
|
||||
<uni-tag v-if="projectDetail.projectStatus == 1" size="normal" type="success" text="进度完成"></uni-tag>
|
||||
<uni-tag v-else-if="projectDetail.projectStatus == 0" size="normal" type="warning" text="进行中"></uni-tag>
|
||||
<uni-tag v-if="projectDetail.tradeType == 0" size="normal" type="warning" text="内贸"></uni-tag>
|
||||
<uni-tag v-else-if="projectDetail.tradeType == 1" size="normal" type="success" text="外贸"></uni-tag>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">项目类型:</text>
|
||||
<text class="info-value">{{ projectDetail.projectType || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">项目地址:</text>
|
||||
<text class="info-value">{{ projectDetail.address || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">项目总金额:</text>
|
||||
<text class="info-value">{{ projectDetail.funds || '-' }}元</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">负责人:</text>
|
||||
<text class="info-value">{{ projectDetail.functionary || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">项目周期:</text>
|
||||
<text class="info-value">{{ projectDetail.beginTime || '-' }} 至 {{ projectDetail.finishTime || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">交付时间:</text>
|
||||
<text class="info-value">{{ projectDetail.delivery || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">保证期:</text>
|
||||
<text class="info-value">{{ projectDetail.guarantee || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">备注:</text>
|
||||
<text class="info-value">{{ projectDetail.remark || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">延期原因:</text>
|
||||
<text class="info-value">{{ projectDetail.postponeReason || '无' }}</text>
|
||||
</view>
|
||||
<view class="info-item" v-if="projectDetail.prePay > 0">
|
||||
<text class="info-label">预付款:</text>
|
||||
<text class="info-value">{{ projectDetail.prePay }}元</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 合同管理 -->
|
||||
<view class="contract-management">
|
||||
<text class="contract-title">合同管理</text>
|
||||
<view v-if="contractDetail && contractDetail.length > 0">
|
||||
<view class="info-item">
|
||||
<text class="info-label">合同类型:</text>
|
||||
<text class="info-value">{{ getContractType(contractDetail.contractType) }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">合同编号:</text>
|
||||
<text class="info-value">{{ contractDetail.contractNum || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text class="info-label">合同金额:</text>
|
||||
<text class="info-value">{{ contractDetail.amount || '-' }}元</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else>
|
||||
暂无合同
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="projectDetail.projectStatus == 0" style="margin-top: 20px; text-align: center;">
|
||||
<button @click="handleClosure">结项</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getProject, updateProject } from '@/api/oa/project.js'; // 确保导入正确的 API 方法
|
||||
import { selectContractByProjectId } from '@/api/oa/oaContract.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
projectDetail: {}, // 存储项目详情
|
||||
contractDetail: null, // 存储合同详情
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
this.fetchProjectDetail(options.id); // 获取项目 ID
|
||||
},
|
||||
methods: {
|
||||
fetchProjectDetail(projectId) {
|
||||
getProject(projectId).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.projectDetail = res.data; // 将返回的数据存储到 projectDetail 中
|
||||
this.fetchContractDetail(projectId); // 获取合同信息
|
||||
} else {
|
||||
console.error('获取项目详情失败:', res.msg);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取项目详情失败:', error);
|
||||
});
|
||||
},
|
||||
handleClosure() {
|
||||
// uniapp二次确认
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要结项吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
updateProject({...this.projectDetail, projectStatus: 1}).then(res => {
|
||||
this.fetchProjectDetail(this.projectDetail.projectId);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
fetchContractDetail(projectId) {
|
||||
selectContractByProjectId({ projectId }).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.contractDetail = res.data; // 将返回的合同信息存储到 contractDetail 中
|
||||
} else {
|
||||
console.error('获取合同信息失败:', res.msg);
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取合同信息失败:', error);
|
||||
});
|
||||
},
|
||||
getContractType(contractType) {
|
||||
const contractTypes = {
|
||||
1: '采购合同',
|
||||
2: '项目合同',
|
||||
};
|
||||
return contractTypes[contractType] || '未知类型';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-page {
|
||||
padding: 20px; /* 添加内边距 */
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
margin-bottom: 15px; /* 下边距 */
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 24px; /* 标题字号 */
|
||||
font-weight: bold; /* 加粗 */
|
||||
}
|
||||
|
||||
.header-subtitle {
|
||||
font-size: 18px; /* 副标题字号 */
|
||||
color: #666; /* 较淡的字体颜色 */
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
border: 1px solid #ccc; /* 边框 */
|
||||
border-radius: 10px; /* 圆角 */
|
||||
padding: 15px; /* 内边距 */
|
||||
background-color: #f9f9f9; /* 背景色 */
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex; /* 使用 Flexbox 布局 */
|
||||
justify-content: space-between; /* 在一行内均匀分布 */
|
||||
margin-top: 10px; /* 上边距 */
|
||||
}
|
||||
|
||||
.info-label {
|
||||
color: #333; /* 标签颜色 */
|
||||
font-weight: bold; /* 标签加粗 */
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: #666; /* 值的颜色 */
|
||||
}
|
||||
|
||||
.contract-management {
|
||||
margin-top: 20px; /* 上边距 */
|
||||
}
|
||||
|
||||
.contract-title {
|
||||
font-size: 20px; /* 合同标题字号 */
|
||||
font-weight: bold; /* 加粗 */
|
||||
margin-bottom: 10px; /* 下边距 */
|
||||
}
|
||||
</style>
|
||||
254
pages/workbench/project/project.vue
Normal file
254
pages/workbench/project/project.vue
Normal file
@@ -0,0 +1,254 @@
|
||||
<template>
|
||||
<view class="project-page">
|
||||
<!-- 新增按钮 -->
|
||||
<view class="add-btn-row">
|
||||
<view class="button-group">
|
||||
<uni-icons
|
||||
type="gift"
|
||||
size="30"
|
||||
@click="toggleQualityFilter"
|
||||
:color="qualityFilter ? '#ffcc00' : '#333'"
|
||||
/>
|
||||
<!-- <uni-icons
|
||||
type="gear"
|
||||
size="30"
|
||||
@click="openSettingsPopup"
|
||||
color="#333"
|
||||
/> -->
|
||||
<uni-icons
|
||||
type="plus"
|
||||
size="30"
|
||||
@click="handleAdd"
|
||||
color="#333"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 项目列表 -->
|
||||
<scroll-view scroll-y @scrolltolower="loadMore" :style="{ height: scrollHeight + 'px' }">
|
||||
<view class="project-grid">
|
||||
<view
|
||||
class="project-card"
|
||||
v-for="item in projectList"
|
||||
:key="item.projectId"
|
||||
@click="handleDetail(item)"
|
||||
>
|
||||
<view class="project-title">{{ item.projectName }}</view>
|
||||
<view class="project-info">
|
||||
<text>负责人:{{ item.functionary }}</text>
|
||||
<text :style="getRemainTimeStyle(item.remainTime)">
|
||||
剩余时间:{{ item.remainTime }}天
|
||||
</text>
|
||||
<text>项目总金额:{{ item.funds }}元</text>
|
||||
<text v-if="item.prePay > 0" style="color: #ffcc00;">预付款:{{ item.prePay }}元</text>
|
||||
<view style="display: flex; justify-content: flex-start; gap: 10rpx; position: absolute; bottom: 20rpx; margin-top: 10rpx;">
|
||||
<uni-tag v-if="item.projectStatus == 1" size="mini" type="success" text="进度完成"></uni-tag>
|
||||
<uni-tag v-else-if="item.projectStatus == 0" size="mini" type="warning" text="进行中"></uni-tag>
|
||||
<uni-tag v-if="item.tradeType == 0" size="mini" type="warning" text="内贸"></uni-tag>
|
||||
<uni-tag v-else-if="item.tradeType == 1" size="mini" type="success" text="外贸"></uni-tag>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 加载更多组件 -->
|
||||
<uni-load-more :status="loadMoreStatus"></uni-load-more>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listProject, addProject, updateProject, delProject, getProject } from '@/api/oa/project.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
projectList: [],
|
||||
form: {},
|
||||
editType: '', // add/edit
|
||||
page: 1, // 当前页码
|
||||
pageSize: 10, // 每页项目数量
|
||||
selectedProject: {}, // 选中的项目
|
||||
loadMoreStatus: 'more', // 加载更多状态
|
||||
scrollHeight: 0, // 滚动区域高度
|
||||
qualityFilter: false, // 优质筛选开关
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
this.getList();
|
||||
this.calculateScrollHeight();
|
||||
},
|
||||
methods: {
|
||||
calculateScrollHeight() {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const tabHeight = 75; // tab高度
|
||||
const containerPadding = 40; // 容器padding
|
||||
this.scrollHeight = systemInfo.windowHeight - tabHeight - containerPadding + 80;
|
||||
},
|
||||
getList() {
|
||||
const params = { pageNum: this.page, pageSize: this.pageSize };
|
||||
if (this.qualityFilter) {
|
||||
params.prePay = 0.1; // 添加优质筛选参数
|
||||
}
|
||||
listProject(params).then(res => {
|
||||
const newProjects = (res.rows || []).map(row => ({
|
||||
...row,
|
||||
projectTypeLabel: row.projectType,
|
||||
projectStatusLabel: row.projectStatus,
|
||||
}));
|
||||
this.projectList = [...this.projectList, ...newProjects];
|
||||
|
||||
if (newProjects.length < this.pageSize) {
|
||||
this.loadMoreStatus = 'noMore'; // 没有更多数据
|
||||
} else {
|
||||
this.loadMoreStatus = 'more'; // 还有更多数据
|
||||
}
|
||||
});
|
||||
},
|
||||
loadMore() {
|
||||
if (this.loadMoreStatus === 'more') {
|
||||
console.log('加载更多');
|
||||
this.page++;
|
||||
this.getList();
|
||||
}
|
||||
},
|
||||
handleAdd() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/project/add'
|
||||
})
|
||||
},
|
||||
handleDetail(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/project/detail?id=' + item.projectId
|
||||
})
|
||||
},
|
||||
toggleQualityFilter() {
|
||||
this.qualityFilter = !this.qualityFilter; // 切换优质筛选状态
|
||||
this.page = 1; // 重置页码
|
||||
this.projectList = []; // 清空当前项目列表
|
||||
this.getList(); // 重新获取项目列表
|
||||
},
|
||||
openEditPopup(item) {
|
||||
this.editType = 'edit';
|
||||
getProject(item.projectId).then(res => {
|
||||
this.form = { ...res.data };
|
||||
this.$refs.editPopup.open();
|
||||
});
|
||||
},
|
||||
closePopup() {
|
||||
this.$refs.editPopup.close();
|
||||
},
|
||||
submitForm() {
|
||||
if (this.editType === 'add') {
|
||||
addProject(this.form).then(() => {
|
||||
this.getList();
|
||||
this.closePopup();
|
||||
});
|
||||
} else {
|
||||
updateProject(this.form).then(() => {
|
||||
this.getList();
|
||||
this.closePopup();
|
||||
});
|
||||
}
|
||||
},
|
||||
handleClosure(item) {
|
||||
const update = { ...item, projectStatus: '1' };
|
||||
updateProject(update).then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
handleDelete(item) {
|
||||
delProject(item.projectId).then(() => {
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
openDetailPopup(item) {
|
||||
this.selectedProject = item;
|
||||
this.$refs.detailPopup.open();
|
||||
},
|
||||
closeDetailPopup() {
|
||||
this.$refs.detailPopup.close();
|
||||
},
|
||||
getRemainTimeStyle(remainTime) {
|
||||
if (remainTime > 10) {
|
||||
return { color: '#3c763d' }; // 绿色
|
||||
} else if (remainTime > 5) {
|
||||
return { color: '#8a6d3b' }; // 黄色
|
||||
} else {
|
||||
return { color: '#a94442' }; // 红色
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.add-btn-row {
|
||||
display: flex;
|
||||
justify-content: flex-end; /* 右对齐 */
|
||||
align-items: center;
|
||||
margin: 20rpx;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
gap: 10px; /* 按钮之间的间距 */
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background-color: #fff; /* 设置纯白背景 */
|
||||
padding: 20px; /* 添加内边距 */
|
||||
border-radius: 8px; /* 圆角 */
|
||||
}
|
||||
|
||||
.close-button {
|
||||
display: flex;
|
||||
justify-content: flex-end; /* 右对齐 */
|
||||
margin-bottom: 10px; /* 底部间距 */
|
||||
}
|
||||
|
||||
.project-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
border: 1px solid #ccc; /* 边框 */
|
||||
border-radius: 10px; /* 圆角 */
|
||||
background-color: #fff; /* 背景色 */
|
||||
margin: 10px;
|
||||
box-sizing: border-box;
|
||||
width: calc(50% - 20px); /* 每行两个卡片 */
|
||||
padding: 20px 15px; /* 添加内边距 */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 20px; /* 项目名称字号 */
|
||||
font-weight: bold; /* 加粗 */
|
||||
color: #333; /* 主字体颜色 */
|
||||
margin-bottom: 5px; /* 下边距 */
|
||||
}
|
||||
|
||||
.project-info text {
|
||||
display: block; /* 每个信息占一行 */
|
||||
margin-top: 5px; /* 上边距 */
|
||||
color: #666; /* 较淡的字体颜色 */
|
||||
font-size: 16px; /* 信息字号 */
|
||||
line-height: 1.5; /* 行间距 */
|
||||
}
|
||||
|
||||
.project-info {
|
||||
margin-top: 10px; /* 项目信息与标题之间的间距 */
|
||||
}
|
||||
|
||||
/* 新增的样式 */
|
||||
.horizontal-actions {
|
||||
display: flex;
|
||||
justify-content: space-between; /* 在一行内均匀分布 */
|
||||
margin-top: 10px; /* 添加顶部间距 */
|
||||
}
|
||||
.horizontal-actions button {
|
||||
flex: 1; /* 按钮均分宽度 */
|
||||
margin: 0 5px; /* 按钮之间的间距 */
|
||||
}
|
||||
</style>
|
||||
385
pages/workbench/wms/wms.vue
Normal file
385
pages/workbench/wms/wms.vue
Normal file
@@ -0,0 +1,385 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 筛选表单 一行展示 -->
|
||||
<view class="filter-form-row">
|
||||
<!-- 型号筛选 -->
|
||||
<view :class="['filter-item', activeFilter === 'model' ? 'filter-item-expand' : 'filter-item-collapse']">
|
||||
<template v-if="activeFilter === 'model'">
|
||||
<view class="input-clear-wrap">
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="queryParams.model"
|
||||
placeholder="型号"
|
||||
@blur="onFilterBlur('model')"
|
||||
:style="{ color: queryParams.model ? '#2979ff' : '#999' }"
|
||||
/>
|
||||
<view v-if="queryParams.model" class="clear-icon" @click="clearFilter('model')">
|
||||
<uni-icons type="closeempty" color="#bbb" size="18" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="filter-icon" @click="toggleFilter('model')">
|
||||
<uni-icons type="cart" :color="queryParams.model ? '#2979ff' : '#bbb'" size="24" />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<!-- 物料名称筛选 -->
|
||||
<view :class="['filter-item', activeFilter === 'name' ? 'filter-item-expand' : 'filter-item-collapse']">
|
||||
<template v-if="activeFilter === 'name'">
|
||||
<view class="input-clear-wrap">
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="queryParams.name"
|
||||
placeholder="物料名称"
|
||||
@blur="onFilterBlur('name')"
|
||||
:style="{ color: queryParams.name ? '#2979ff' : '#999' }"
|
||||
/>
|
||||
<view v-if="queryParams.name" class="clear-icon" @click="clearFilter('name')">
|
||||
<uni-icons type="closeempty" color="#bbb" size="18" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="filter-icon" @click="toggleFilter('name')">
|
||||
<uni-icons type="search" :color="queryParams.name ? '#2979ff' : '#bbb'" size="24" />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<!-- 品牌筛选 -->
|
||||
<view :class="['filter-item', activeFilter === 'brand' ? 'filter-item-expand' : 'filter-item-collapse']">
|
||||
<template v-if="activeFilter === 'brand'">
|
||||
<view class="input-clear-wrap">
|
||||
<input
|
||||
class="filter-input"
|
||||
v-model="queryParams.brand"
|
||||
placeholder="品牌"
|
||||
@blur="onFilterBlur('brand')"
|
||||
:style="{ color: queryParams.brand ? '#2979ff' : '#999' }"
|
||||
/>
|
||||
<view v-if="queryParams.brand" class="clear-icon" @click="clearFilter('brand')">
|
||||
<uni-icons type="closeempty" color="#bbb" size="18" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="filter-icon" @click="toggleFilter('brand')">
|
||||
<uni-icons type="circle" :color="queryParams.brand ? '#2979ff' : '#bbb'" size="24" />
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<button class="filter-btn" @click="resetQuery">重置</button>
|
||||
</view>
|
||||
|
||||
<!-- 列表展示,下拉加载更多 -->
|
||||
<scroll-view class="list" scroll-y @scrolltolower="loadMore">
|
||||
<view v-for="(item, index) in oaWarehouseList" :key="item.id" class="list-item">
|
||||
<view class="row">
|
||||
<text class="index">{{ index + 1 }}</text>
|
||||
<text class="name">{{ item.name }}</text>
|
||||
<text class="model">{{ item.model }}</text>
|
||||
<text class="brand">{{ item.brand }}</text>
|
||||
</view>
|
||||
<view class="row">
|
||||
<text class="price">单价:{{ item.price }}</text>
|
||||
<text :class="['inventory', item.inventory < item.threshold ? 'low' : '']">
|
||||
库存:{{ item.inventory }}
|
||||
<text v-if="item.taskInventory !== null">({{ item.taskInventory }})</text>
|
||||
</text>
|
||||
<text class="unit">{{ item.unit }}</text>
|
||||
<text class="specifications">{{ item.specifications }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="oaWarehouseList.length === 0" class="empty">暂无数据</view>
|
||||
<view v-if="loadingMore" class="loading-more">加载中...</view>
|
||||
<view v-if="!hasMore && oaWarehouseList.length > 0" class="no-more">没有更多了</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listStock } from '@/api/oa/wms/stock.js'
|
||||
import uniIcons from '@/uni_modules/uni-icons/components/uni-icons/uni-icons.vue'
|
||||
import uniEasyinput from '@/uni_modules/uni-easyinput/components/uni-easyinput/uni-easyinput.vue'
|
||||
export default {
|
||||
components: {
|
||||
uniIcons
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
oaWarehouseList: [],
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
model: '',
|
||||
name: '',
|
||||
brand: ''
|
||||
},
|
||||
total: 0,
|
||||
loadingMore: false,
|
||||
hasMore: true,
|
||||
activeFilter: 'model' // 当前展开的筛选项
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList(isLoadMore = false) {
|
||||
if (!isLoadMore) {
|
||||
this.queryParams.pageNum = 1
|
||||
this.oaWarehouseList = []
|
||||
this.hasMore = true
|
||||
}
|
||||
listStock(this.queryParams).then(res => {
|
||||
const rows = res.rows || []
|
||||
this.total = res.total || 0
|
||||
if (isLoadMore) {
|
||||
this.oaWarehouseList = this.oaWarehouseList.concat(rows)
|
||||
} else {
|
||||
this.oaWarehouseList = rows
|
||||
}
|
||||
// 判断是否还有更多
|
||||
this.hasMore = this.oaWarehouseList.length < this.total
|
||||
this.loadingMore = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.getList(false)
|
||||
},
|
||||
toggleFilter(type) {
|
||||
this.activeFilter = type
|
||||
},
|
||||
onFilterBlur(type) {
|
||||
// 输入框失焦后自动筛选
|
||||
this.handleQuery()
|
||||
},
|
||||
clearFilter(type) {
|
||||
this.queryParams[type] = ''
|
||||
this.handleQuery()
|
||||
},
|
||||
resetQuery() {
|
||||
this.queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
model: '',
|
||||
name: '',
|
||||
brand: ''
|
||||
}
|
||||
this.getList(false)
|
||||
},
|
||||
loadMore() {
|
||||
if (!this.hasMore || this.loadingMore) return
|
||||
this.loadingMore = true
|
||||
this.queryParams.pageNum++
|
||||
this.getList(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.input-clear-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.clear-icon {
|
||||
position: absolute;
|
||||
right: 10rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
padding: 4rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.filter-form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 8rpx #eee;
|
||||
padding: 8rpx 16rpx;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 56rpx;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.filter-item-expand {
|
||||
flex: 1 1 0%;
|
||||
margin-right: 16rpx;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
.filter-item-collapse {
|
||||
flex: 0 0 48rpx;
|
||||
margin-right: 8rpx;
|
||||
min-width: 48rpx;
|
||||
max-width: 48rpx;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 8rpx 12rpx;
|
||||
border: 1rpx solid #eee;
|
||||
border-radius: 6rpx;
|
||||
background: #f8f8f8;
|
||||
font-size: 28rpx;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.filter-input {
|
||||
width: 100%;
|
||||
padding: 8rpx 12rpx;
|
||||
border: 1rpx solid #eee;
|
||||
border-radius: 6rpx;
|
||||
background: #f8f8f8;
|
||||
font-size: 28rpx;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
margin-right: 12rpx;
|
||||
padding: 8rpx 24rpx;
|
||||
background: #2979ff;
|
||||
color: #fff;
|
||||
border-radius: 6rpx;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.list {
|
||||
background: #fff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 8rpx #eee;
|
||||
height: 90vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
margin: 16rpx 16rpx 0 16rpx;
|
||||
padding: 24rpx 20rpx 16rpx 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 12rpx #e5e5e5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.index {
|
||||
width: 48rpx;
|
||||
color: #bbb;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #2979ff;
|
||||
margin-right: 24rpx;
|
||||
max-width: 220rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.model {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-right: 20rpx;
|
||||
max-width: 160rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.brand {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-right: 20rpx;
|
||||
max-width: 120rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 28rpx;
|
||||
color: #faad14;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.inventory {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
margin-right: 20rpx;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.inventory.low {
|
||||
color: #ff4d4f !important;
|
||||
background: #fff2f0;
|
||||
border-radius: 6rpx;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.specifications {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-right: 16rpx;
|
||||
max-width: 120rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
.loading-more {
|
||||
text-align: center;
|
||||
color: #2979ff;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
color: #bbb;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user