wms-pda迁移

This commit is contained in:
2025-05-09 17:15:16 +08:00
parent 6a09472e86
commit e8b07fcece
580 changed files with 75351 additions and 133 deletions

16
static/js/directive.js Normal file
View File

@@ -0,0 +1,16 @@
export default {
//自定义节流操作
preventReClick: {
mounted(el, binding) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 2000) //2000ms间隔时间
}
})
}
}
}

View File

@@ -0,0 +1,5 @@
const BaseApi = 'https://api.wms.test.f2b211.com/api' //测试
//const BaseApi = 'https://wmsapi.f2b211.com/api' // 正式
export {
BaseApi
}

114
static/js/http/index.js Normal file
View File

@@ -0,0 +1,114 @@
import http from './interface'
export const $http = (url, method, data, json) => {
//设置请求前拦截器
http.interceptor.request = (config) => {
uni.showLoading({
title: '加载中...'
})
config.header = {
'content-type': json ? 'application/json' : 'application/x-www-form-urlencoded',
"Authorization": uni.getStorageSync('token')
}
}
//设置请求结束后拦截器
http.interceptor.response = async (response) => {
//判断返回状态 执行相应操作
uni.hideLoading()
// 请根据后端规定的状态码判定
if (response.data.status === 401) { //token失效
console.log('请根据后端规定的状态码判定', response.data.status, response.data.message)
uni.showToast({
title: response.data.message,
icon: 'none',
duration: 1500
})
// return response.data = await doRequest(response, url)//动态刷新token,并重新完成request请求
// 登录失效,退回登录也面重新登录
uni.reLaunch({
url: "/pages/login"
})
} else {
if (response.data.status !== 200 && response.data.message) {
uni.showToast({
title: response.data.message,
icon: 'none',
duration: 1500
})
}
}
return response.data;
}
return http.request({
method: method,
url: url,
dataType: 'json',
data,
})
}
async function login() {
//返回环宇token所需的login code
return new Promise(resolve => {
uni.login({
provider: 'weixin',
success(loginRes) {
resolve(loginRes.code)
},
fail() {}
});
})
}
async function doRequest(response, url) {
var code = await login()
var res = await post('/Login/RefreshToken', {})
if (res && res.data.data.token) {
let config = response.config
uni.setStorageSync("token", res.data.data.token);
config.header['Authorization'] = res.data.data.token
let json = config.header["Content-Type"] === 'application/json'
const resold = await $http(url, config.method, {
...config.data
}, json)
return resold
} else {
uni.clearStorage()
uni.showToast({
title: "授权失效,请重新登录",
duration: 1000,
})
uni.redirectTo({
url: '/pages/login'
})
return false
}
}
function postJson(url, data) {
return $http(url, 'POST', data)
}
function get(url, data) {
return $http(url, 'GET', data)
}
function post(url, data) {
return $http(url, 'POST', data, true)
}
function put(url, data) {
return $http(url, 'PUT', data, true)
}
function del(url, data) {
return $http(url, 'DELETE', data, true)
}
export default {
postJson,
get,
post,
put,
del
}

114
static/js/http/interface.js Normal file
View File

@@ -0,0 +1,114 @@
import {
BaseApi
} from './baseApi.js'
export default {
config: {
baseUrl: BaseApi,
header: {
'Content-Type':'application/json;charset=UTF-8',
'Content-Type':'application/x-www-form-urlencoded'
},
data: {},
method: "GET",
dataType: "json", /* 如设为json会对返回的数据做一次 JSON.parse */
responseType: "text",
success() {},
fail() {},
complete() {}
},
interceptor: {
request: null,
response: null
},
request(options) {
if (!options) {
options = {}
}
options.baseUrl = options.baseUrl || this.config.baseUrl
options.dataType = options.dataType || this.config.dataType
options.url = options.baseUrl + options.url
options.data = options.data || {}
options.method = options.method || this.config.method
return new Promise((resolve, reject) => {
let _config = null
options.complete = (response) => {
let statusCode = response.statusCode
response.config = _config
if (process.env.NODE_ENV === 'development') {
if (statusCode === 200) {
////console.log("【" + _config.requestId + "】 结果:" + JSON.stringify(response.data))
}
}
if (this.interceptor.response) {
let newResponse = this.interceptor.response(response)
if (newResponse) {
response = newResponse
}
}
// 统一的响应日志记录
//_reslog(response)
if (statusCode === 200) { //成功
resolve(response);
} else {
reject(response)
}
}
_config = Object.assign({}, this.config, options)
_config.requestId = new Date().getTime()
if (this.interceptor.request) {
this.interceptor.request(_config)
}
// 统一的请求日志记录
//_reqlog(_config)
if (process.env.NODE_ENV === 'development') {
//console.log("【" + _config.requestId + "】 地址:" + _config.url)
if (_config.data) {
//console.log("【" + _config.requestId + "】 参数:" + JSON.stringify(_config.data))
}
}
uni.request(_config);
});
}
}
/**
* 请求接口日志记录
*/
function _reqlog(req) {
if (process.env.NODE_ENV === 'development') {
//console.log("【" + req.requestId + "】 地址:" + req.url)
if (req.data) {
//console.log("【" + req.requestId + "】 请求参数:" + JSON.stringify(req.data))
}
}
//TODO 调接口异步写入日志数据库
}
/**
* 响应接口日志记录
*/
function _reslog(res) {
let _statusCode = res.statusCode;
if (process.env.NODE_ENV === 'development') {
//console.log("【" + res.config.requestId + "】 地址:" + res.config.url)
if (res.config.data) {
//console.log("【" + res.config.requestId + "】 请求参数:" + JSON.stringify(res.config.data))
}
//console.log("【" + res.config.requestId + "】 响应结果:" + JSON.stringify(res))
}
//TODO 除了接口服务错误外,其他日志调接口异步写入日志数据库
switch(_statusCode){
case 200:
break;
case 401:
break;
case 404:
break;
default:
break;
}
}

374
static/js/public.js Normal file
View File

@@ -0,0 +1,374 @@
function setObjectArry(object) {
let arry = []
for (let i in object) {
arry.push({
id: i,
name: object[i]
})
}
return arry
}
//判断两个数组是否完全相等:
function arraysHaveSameElements(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
arr1.sort();
arr2.sort();
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false;
}
}
return true;
}
//判断一个数组是否包含另一个数组的所有元素
function arrayContainsArray(arr1, arr2) {
return arr2.every(val => arr1.includes(val));
}
//判断两个数组是否完全不相等
function arraysAreNotEqual(arr1, arr2) {
// 如果数组长度相等,检查是否有元素不相等
if (arr1.length === arr2.length) {
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return true;
}
}
return false; // 如果所有元素都相等返回false
} else {
return true; // 如果数组长度不等返回true
}
}
// 计算对象数组某个对象值的总和
function sumObjectArrayValues(array, valueProperty) {
return array.reduce((accumulator, currentObject) => {
const value = currentObject[valueProperty];
if (value != null && value >= 0) {
accumulator += parseInt(value)
}
return accumulator
console.log('总和', accumulator)
}, 0);
}
// 计算对象数组包含对象数组,某个值的总和
function sumNestedObjectValues(objArray, outerKey, innerKey, defaultValue = 0) {
return objArray.reduce((sum, obj) => {
if (obj.hasOwnProperty(outerKey) && Array.isArray(obj[outerKey])) {
obj[outerKey].forEach((innerObj) => {
if (innerObj.hasOwnProperty(innerKey)) {
sum += parseInt(innerObj[innerKey]);
} else {
sum += defaultValue; // 当值不存在时,加上默认值
}
});
}
return sum;
}, 0);
}
// 判断物料在数组那个位置数组detail那个位置
function findMaterialCodePosition(objectArray, materialNumber) {
for (let objectIndex = 0; objectIndex < objectArray.length; objectIndex++) {
const details = objectArray[objectIndex].details;
for (let detailIndex = 0; detailIndex < details.length; detailIndex++) {
if (details[detailIndex].materialNumber === materialNumber) {
return {
objectIndex: objectIndex,
detailIndex: detailIndex
};
}
}
}
return null; // 如果没有找到返回null
};
// 存在相同物料相同规格相同组织的非采购箱数据进行明细分配
function distributeStockForOrder(orderDetails, boxContents, boxTotal) {
// 创建一个副本,避免直接修改原始数据
const updatedDetails = [...orderDetails];
// 遍历订单明细
for (let detail of updatedDetails) {
const {
material,
quantity
} = detail;
// 如果箱子里的该物料数量小于订单明细中的数量,则提示并不再进行分配
if (boxContents[material] < quantity) {
console.warn(`警告:箱子里的${material}物料数量不足,无法进行分配!`);
continue;
}
// 计算可以分配的上架数量
const availableToDistribute = Math.min(boxTotal, boxContents[material]);
const distributeQuantity = Math.min(availableToDistribute, quantity);
// 更新上架数量和箱子里的物料数量
detail.stockAvailable = distributeQuantity;
boxTotal -= distributeQuantity;
boxContents[material] -= distributeQuantity;
}
return updatedDetails;
}
//获取明细数据相同物料id不同数量的总和
function sumByField(data, fieldName) {
if (!data || data.length === 0) {
return [];
}
const map = new Map();
data.forEach(item => {
const {
materialNumber
} = item;
const value = item[fieldName];
if (value !== null && value !== undefined && value !== '') {
map.set(materialNumber, (map.get(materialNumber) || 0) + value);
}
});
return Array.from(map.entries()).map(([materialNumber, value]) => ({
materialNumber,
'qty': value
}));
}
// 对比两个物料数据有没有数量大于的情况,有就提示
function checkQtyExceedsLimit(mxArray, boxArray, materialCodeField, qtyField) {
const mxMap = new Map();
mxArray.forEach(item => mxMap.set(item[materialCodeField], item[qtyField]));
for (const boxItem of boxArray) {
const boxMaterialCode = boxItem[materialCodeField];
const boxQty = boxItem[qtyField];
const mxQty = mxMap.get(boxMaterialCode);
if (mxQty !== undefined && boxQty > mxQty) {
console.log(
`Warning: Material ID ${boxMaterialCode} in box has a higher quantity (${boxQty}) than in mx (${mxQty}).`
);
return true;
}
}
return false;
}
// 非采购分配
function allocateQty(box, details) {
console.log('更配的公共方法', box, details)
const boxMap = new Map();
for (const item of box) {
boxMap.set(item.materialNumber, item.qty);
}
const allocationLog = []; // 记录每个箱子分配给了哪一条明细以及分配的数量
for (const detail of details) {
if (boxMap.has(detail.materialNumber) && boxMap.get(detail.materialNumber) > 0) {
const availableBoxQty = boxMap.get(detail.materialNumber);
const qtyToAllocate = Math.min(availableBoxQty, detail.availableQty - detail.qty);
detail.qty += qtyToAllocate;
boxMap.set(detail.materialNumber, availableBoxQty - qtyToAllocate);
allocationLog.push({
materialNumber: detail.materialNumber,
erpDetailId: detail.erpDetailId,
qty: qtyToAllocate
});
}
}
return {
updatedDetails: details,
allocationLog
};
}
// 箱子数量对比以上架的数量进行相减,然后在去判断数量是否有超过
function subtractQty(mxArray, boxArray) {
const result = [];
const materialMap = new Map();
// 创建物料ID与数量的映射关系
mxArray.forEach(item => {
const {
materialNumber,
qty
} = item;
materialMap.set(materialNumber, qty);
});
boxArray.forEach(item => {
const {
materialNumber,
qty
} = item;
const mxQty = materialMap.get(materialNumber);
if (mxQty !== undefined) {
const subtractedQty = mxQty - qty; // mx的数量减去box的数量
result.push({
materialNumber,
qty: subtractedQty
});
} else {
result.push(item); // 如果box中的物料在mx中不存在则直接添加到结果中
}
});
return result;
}
//按照产品分配序列号
function scanAndAllocate(arr, materialNumber, serialNumber) {
// 遍历数组,按顺序分配序列号
for (const item of arr) {
if (item.materialNumber === materialNumber) {
if (item.xlhList.length == 0) {
item.xlhList.push(serialNumber)
item.qty = item.xlhList.length
return arr
break
}
if (item.xlhList.length > 0) {
if (item.xlhList.length < item.availableQty) {
item.xlhList.push(serialNumber)
item.qty = item.xlhList.length
return arr
break
}
}
}
}
return arr
}
function doScanQrCode() {
return new Promise((resolve, reject) => {
uni.scanCode({
onlyFromCamera: true,
success: function(res) {
//去除空格
let space_str = '\u0000'
let code = res.result.replace(space_str, "")
res.result = code
resolve(res)
},
fail() {
reject('失败')
},
complete() {
console.log("扫码结束,无论失败还是成功都会回调");
}
})
})
}
//计算列表的高度
function setlistHeight(topclass, bottomclass) {
let aa = {
top: 0,
body: 0
}
uni.getSystemInfo({
success(res) {
let screenHeight = res.screenHeight
let listheight = 0
// console.log('系统高度',screenHeight)
//.box获取class为box的元素如果使用的id= 'box' 则使用'#box'
uni.createSelectorQuery().select(topclass).boundingClientRect(data => {
aa.top = data.height + 5
// console.log('top',aa.top)
}).exec()
uni.createSelectorQuery().select(bottomclass).boundingClientRect(data => {
aa.body = res.screenHeight - aa.top + 5 - data.height - 95
// console.log('bottom',aa.body)
}).exec()
// console.log('系统高度,最终列表高度',screenHeight, aa)
}
})
return aa
}
// 防止处理多次点击
function notMoreTap(means, clickName, ...data) {
// means是点击后需要执行的方法
// clickName是一个变量的名字控制是否是第一次点击
// data是点击需要传的参数:用逗号隔开就可以,...为剩余运算符除去前两位传的参数剩下的传的参数都会留在data里
let that = this;
console.log(this, that[clickName])
if (that[clickName]) {
// 第一次点击
console.log('第一次点击')
that[clickName] = false;
if (data && data.length > 0) {
if (data.length != 0 && data[0] != '') {
means(...data);
}
} else {
means();
}
setTimeout(() => {
that[clickName] = true;
}, 2000)
} else {
uni.showToast({
title: '请不要重复点击',
icon: 'none'
})
}
}
// app物理键返回
function appgoBack(e, type) {
// 这里可以写自定义的逻辑表示来源是安卓手机的返回键
if (e.from == 'backbutton' && type == 'warehousIndex') {
uni.navigateTo({
url: "/pages/warehous/index"
})
console.log('物理键返回', e.from, type)
}
if (e.from == 'backbutton' && type == 'login') {
console.log('物理键返回', e.from, type)
// 执行自定义操作,比如弹出提示框
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: function(res) {
if (res.confirm) {
// 用户点击确定,执行返回操作
uni.navigateTo({
url: "/pages/login"
});
} else if (res.cancel) {
// 用户点击取消,不执行返回操作
return true; // 阻止页面返回
}
}
});
}
if (e.from == 'backbutton' && type == 'index') {
console.log('物理键返回', e.from, type)
uni.navigateTo({
url: "/pages/index"
})
}
if (e.from == 'backbutton' && type == 'otherUnderwearIndex') {
console.log('物理键返回', e.from, type)
uni.navigateTo({
url: "/pages/otherUnderwear/index"
})
}
}
export {
setObjectArry,
arraysHaveSameElements,
arrayContainsArray,
arraysAreNotEqual,
sumObjectArrayValues,
sumNestedObjectValues,
findMaterialCodePosition,
distributeStockForOrder,
sumByField,
checkQtyExceedsLimit,
allocateQty,
subtractQty,
scanAndAllocate,
doScanQrCode,
setlistHeight,
notMoreTap, //禁止多次点击
appgoBack,
}

67
static/js/scanCode.js Normal file
View File

@@ -0,0 +1,67 @@
let main;
let filter;
let receiver;
let tag = false;
/**
* 开始广播监听扫码
*/
const start = () => {
/* #ifdef APP-PLUS */
main.registerReceiver(receiver, filter);
// console.log('开始广播监听扫码init')
/* #endif */
}
/**
* 停止广播监听扫码
* that传this
*/
const stop = () => {
/* #ifdef APP-PLUS */
main.unregisterReceiver(receiver);
// console.log('停止广播监听扫码init')
/* #endif */
}
/** 剩余下个变量已经做了全局变量
*
* 定义广播
* that传this
*/
const init = (onReceive) => {
/* #ifdef APP-PLUS */
//获取activity
main = plus.android.runtimeMainActivity();
const IntentFilter = plus.android.importClass('android.content.IntentFilter');
filter = new IntentFilter();
// 扫描设置的广播名称A(上面指代了)
filter.addAction("com.android.server.scannerservice.broadcast");
receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
onReceive: function (context, intent) {
plus.android.importClass(intent);
// 扫描设置的标签名称B(上面指代了)
const code = intent.getStringExtra("scannerdata");
if (tag) return;
tag = true;
setTimeout(function () {
tag = false;
}, 150);
uni.$emit('xwscan', {
code: code
})
//到这里扫描成功了可以调用自己的业务逻辑code就是扫描的结果 return出code进行业务处理
onReceive
}
});
/* #endif */
}
export const broadcastScan = {
init,
start,
stop,
};