Browse Source

pages mycomponents 文件迁移Vue2升级Vue3 8/2-10/25

pull/1/head
test 3 months ago
parent
commit
c1e7fcd245
  1. 479
      src/mycomponents/scan/winComScanBalance.vue
  2. 1248
      src/pages/issue/record/directIssue2.vue
  3. 372
      src/pages/point/index.vue
  4. 7
      src/pages/productPutaway/job/semiProductPutawayJob.vue

479
src/mycomponents/scan/winComScanBalance.vue

@ -1,6 +1,6 @@
<template> <template>
<view> <view>
<uni-popup ref="popup" :mask-click="false"> <u-popup v-model="show" mode="bottom">
<view class="popup_box"> <view class="popup_box">
<view class="pop_title uni-flex space-between"> <view class="pop_title uni-flex space-between">
<view class="" style="font-size: 35rpx;"> <view class="" style="font-size: 35rpx;">
@ -19,13 +19,13 @@
</view> </view>
</view> </view>
</view> </view>
</uni-popup> </u-popup>
<balance-select ref="balanceSelect" @onSelectItem='selectBalanceItem'></balance-select> <balance-select ref="balanceSelect" @onSelectItem='selectBalanceItem'></balance-select>
</view> </view>
<comMessage ref="comMessage"></comMessage> <comMessage ref="comMessage"></comMessage>
</template> </template>
<script> <script setup lang="ts">
import winComScan from '@/mycomponents/scan/winComScan.vue' import winComScan from '@/mycomponents/scan/winComScan.vue'
import balanceSelect from '@/mycomponents/balance/balanceSelect.vue' import balanceSelect from '@/mycomponents/balance/balanceSelect.vue'
import { import {
@ -47,275 +47,260 @@ import {
getListItemTypeDesc, getListItemTypeDesc,
getItemTypeInfo getItemTypeInfo
} from '@/common/directory.js'; } from '@/common/directory.js';
export default {
name: 'winScanPack', import { ref, onMounted, watch } from 'vue'
emits: ["getBalance"],
components: { const props = defineProps({
winComScan, title: {
balanceSelect type: String,
default: '箱标签'
}, },
props: { isShowHistory: {
title: { type: Boolean,
type: String, default: false
default: '箱标签'
},
isShowHistory: {
type: Boolean,
default: false
},
headerType: {
type: String,
default: "HPQ,HMQ"
},
balanceFromInventoryStatuses: { //fromInventoryStatuses
type: Boolean,
default: true
},
bussinessCode: {
type: String,
default: ''
},
verifyCategory: {
type: Boolean,
default: false
},
isCheckLocationBalance: {
type: Boolean,
default: true
}
}, },
data() { headerType: {
return { type: String,
scanResult: {}, default: "HPQ,HMQ"
show: false,
scanList: [],
expand: false,
showScanResult: {},
expendIcon: 'arrow-down',
fromLocationCode: '',
fromLocation: '',
fromLocationList: [],
fromLocationAreaTypeList: [],
toLocationAreaTypeList: [],
locationOnFocus: false,
businessType: {},
inventoryStatus: [],
managementPrecision: '',
fromInventoryStatuses: [],
itemTypesList: [],
isCheck: false,
resultData: {}
}
}, },
created() { balanceFromInventoryStatuses: { // fromInventoryStatuses
type: Boolean,
default: true
}, },
methods: { bussinessCode: {
openScanPopup(businessType) { type: String,
this.businessType = businessType default: ''
this.fromInventoryStatuses = getDirectoryItemArray(businessType.outInventoryStatuses) },
this.fromLocationAreaTypeList = getDirectoryItemArray(businessType.outAreaTypes) verifyCategory: {
this.toLocationAreaTypeList = getDirectoryItemArray(businessType.inAreaTypes) type: Boolean,
this.itemTypesList = getDirectoryItemArray(businessType.itemTypes) default: false
this.$refs.popup.open('bottom') },
setTimeout(res=>{ isCheckLocationBalance: {
this.getfocus() type: Boolean,
},500) default: true
}, }
})
getScanResult(result) {
this.resultData = result;
if (!result.package) {
this.showErrorMessage(result.label.code + "包装信息为空")
return;
}
this.getItemCodeType(result.package.itemCode, callBack => {
if(this.isCheckLocationBalance){
this.queryBalance(this.resultData);
}else {
this.queryBalance(this.resultData)
}
//this.queryBalance(this.resultData)
})
},
// const scanResult = ref({})
getToLocationBalance(result) { const show = ref(false)
uni.showLoading({ const scanList = ref([])
title: '查询中', const expand = ref(false)
mask: true const expendIcon = ref('arrow-down')
}) const fromLocationCode = ref('')
var filters = [] const fromLocation = ref('')
if (result.package.parentNumber) { const fromLocationList = ref([])
var packingNumber = result.package.parentNumber + "," + result.package.number; const fromLocationAreaTypeList = ref([])
filters.push({ const toLocationAreaTypeList = ref([])
column: "packingNumber", const businessType = ref({})
action: "in", const inventoryStatus = ref([])
value: packingNumber const fromInventoryStatuses = ref([])
}) const itemTypesList = ref([])
} else { const resultData = ref({})
filters.push({
column: "packingNumber",
action: "==",
value: result.package.number
})
}
filters.push({ const popup = ref(null)
column: "itemCode", const comMessage = ref(null)
action: "==", const comscan = ref(null)
value: result.package.itemCode const balanceSelect = ref(null)
})
filters.push({
column: "batch",
action: "==",
value: result.package.batch
})
filters.push({ //
column: "areaType", const openScanPopup = (businessTypeValue) => {
action: "in", businessType.value = businessTypeValue
value: this.toLocationAreaTypeList.join(',') fromInventoryStatuses.value = getDirectoryItemArray(businessTypeValue.outInventoryStatuses)
}) fromLocationAreaTypeList.value = getDirectoryItemArray(businessTypeValue.outAreaTypes)
toLocationAreaTypeList.value = getDirectoryItemArray(businessTypeValue.inAreaTypes)
itemTypesList.value = getDirectoryItemArray(businessTypeValue.itemTypes)
show.value = true
setTimeout(() => {
getfocus()
}, 500)
}
const getScanResult = (result) => {
resultData.value = result
if (!result.package) {
showErrorMessage(result.label.code + "包装信息为空")
return
}
getItemCodeType(result.package.itemCode, () => {
if (props.isCheckLocationBalance) {
queryBalance(resultData.value)
} else {
queryBalance(resultData.value)
}
})
}
var params = { const getToLocationBalance = (result) => {
filters: filters, uni.showLoading({
pageNo: 1, title: '查询中',
pageSize: 100, mask: true
} })
getBalanceByFilter(params).then(res => { const filters = []
uni.hideLoading() if (result.package.parentNumber) {
if (res.data.list.length > 0) { const packingNumber = result.package.parentNumber + "," + result.package.number
this.showErrorMessage("包装在库位【" + res.data.list[0].locationCode + "】已有库存余额"); filters.push({
} else { column: "packingNumber",
this.queryBalance(this.resultData); action: "in",
} value: packingNumber
// callback(res.data) })
}).catch(err => { } else {
this.showErrorMessage(err.message); filters.push({
}) column: "packingNumber",
}, action: "==",
value: result.package.number
})
}
queryBalance(result) { filters.push({
var params = { column: "itemCode",
itemCode: result.package.itemCode, action: "==",
batch: result.label.batch, value: result.package.itemCode
packingNumber: result.label.packingNumber, })
parentPackingNumber: result.package.parentNumber, filters.push({
inventoryStatus: this.fromInventoryStatuses, column: "batch",
areaType: this.fromLocationAreaTypeList, action: "==",
bussinessCode: this.bussinessCode value: result.package.batch
} })
uni.showLoading({ filters.push({
title: '查询中', column: "areaType",
mask: true action: "in",
}) value: toLocationAreaTypeList.value.join(',')
getBalanceByParams(params).then(res => { })
uni.hideLoading()
if (res.data.length == 0) {
var status = getInventoryStatusDesc(params.inventoryStatus)
var areaType = getListLocationAreaTypeDesc(params.areaType)
var hint =
"按物料号 [" + params.itemCode + "] \n" +
"包装号 [" + params.packingNumber + "] \n" +
"批次 [" + params.batch + "] \n" +
"状态 [" + status + "] \n" +
"库区 [" + areaType + "] \n" +
"未查找到库存余额"
this.showErrorMessage(hint)
} else if (res.data.length == 1) {
result.balance = res.data[0] const params = {
if (result.label.packingNumber != result.balance.packingNumber) { filters: filters,
result.balance.lableQty = result.label.qty pageNo: 1,
} pageSize: 100,
this.$emit("getBalance", result) }
// this.closeScanPopup() getBalanceByFilter(params).then(res => {
} else { uni.hideLoading()
// if (res.data.list.length > 0) {
this.$refs.balanceSelect.openPopup(res.data); showErrorMessage("包装在库位【" + res.data.list[0].locationCode + "】已有库存余额")
} } else {
queryBalance(resultData.value)
}
}).catch(err => {
showErrorMessage(err.message)
})
}
}).catch(error => { const queryBalance = (result) => {
uni.hideLoading() const params = {
this.showErrorMessage(error) itemCode: result.package.itemCode,
}) batch: result.label.batch,
}, packingNumber: result.label.packingNumber,
parentPackingNumber: result.package.parentNumber,
inventoryStatus: fromInventoryStatuses.value,
areaType: fromLocationAreaTypeList.value,
bussinessCode: props.bussinessCode
}
uni.showLoading({
title: '查询中',
mask: true
})
getBalanceByParams(params).then(res => {
uni.hideLoading()
if (res.data.length === 0) {
const status = getInventoryStatusDesc(params.inventoryStatus)
const areaType = getListLocationAreaTypeDesc(params.areaType)
const hint =
"按物料号 [" + params.itemCode + "] \n" +
"包装号 [" + params.packingNumber + "] \n" +
"批次 [" + params.batch + "] \n" +
"状态 [" + status + "] \n" +
"库区 [" + areaType + "] \n" +
"未查找到库存余额"
showErrorMessage(hint)
} else if (res.data.length === 1) {
result.balance = res.data[0]
if (result.label.packingNumber !== result.balance.packingNumber) {
result.balance.lableQty = result.label.qty
}
emit('getBalance', result)
} else {
balanceSelect.value.openPopup(res.data)
}
}).catch(error => {
uni.hideLoading()
showErrorMessage(error)
})
}
getItemCodeType(itemCode, callBack) { const getItemCodeType = (itemCode, callBack) => {
uni.showLoading({ uni.showLoading({
title: "加载中", title: "加载中",
mask: true mask: true
}) })
getBasicItemByCode(itemCode).then(res => { getBasicItemByCode(itemCode).then(res => {
if (res.data != null && res.data.list.length > 0) { if (res.data && res.data.list.length > 0) {
var result = res.data.list[0]; const result = res.data.list[0]
var status = result.available; const status = result.available
var type = result.type; const type = result.type
if (status == "TRUE") { if (status === "TRUE") {
if (checkDirectoryItemExist(this.itemTypesList, type)) { if (checkDirectoryItemExist(itemTypesList.value, type)) {
if (this.verifyCategory) { if (props.verifyCategory) {
if (result.category == 'LCJ' || result.category == 'BJ') { if (result.category === 'LCJ' || result.category === 'BJ') {
callBack() callBack()
} else {
this.showErrorMessage("扫描物料的种类不是【量产件】或者【备件】")
}
} else {
callBack()
}
} else { } else {
var hint = getListItemTypeDesc(this.itemTypesList); showErrorMessage("扫描物料的种类不是【量产件】或者【备件】")
uni.hideLoading()
this.showErrorMessage("扫描物料[" + itemCode + "]是[" +
getItemTypeInfo(type).label + "],需要的物料类型是[" + hint + "]")
} }
} else { } else {
uni.hideLoading() callBack()
this.showErrorMessage('物料【' + itemCode + '】不可用');
} }
} else { } else {
const hint = getListItemTypeDesc(itemTypesList.value)
uni.hideLoading() uni.hideLoading()
this.showErrorMessage('未查找到物料【' + itemCode + '】'); showErrorMessage("扫描物料[" + itemCode + "]是[" +
} getItemTypeInfo(type).label + "],需要的物料类型是[" + hint + "]")
}).catch(error => {
uni.hideLoading();
this.showErrorMessage(error)
})
},
showErrorMessage(message) {
this.losefocus()
this.$refs.comMessage.showErrorMessage(message, res => {
if (res) {
if (this.$refs.comscan) {
this.$refs.comscan.getfocus()
}
} }
}); } else {
}, uni.hideLoading()
showErrorMessage('物料【' + itemCode + '】不可用')
selectBalanceItem(item) {
this.resultData.balance = item
this.$emit("getBalance", this.resultData)
// this.closeScanPopup()
},
closeScanPopup() {
this.losefocus();
this.$refs.popup.close()
},
getfocus() {
if (this.$refs.comscan) {
this.$refs.comscan.getfocus()
} }
}, } else {
losefocus() { uni.hideLoading()
if (this.$refs.comscan) { showErrorMessage('未查找到物料【' + itemCode + '】')
this.$refs.comscan.losefocus() }
}).catch(error => {
uni.hideLoading()
showErrorMessage(error)
})
}
const showErrorMessage = (message) => {
losefocus()
comMessage.value.showErrorMessage(message, res => {
if (res) {
if (comscan.value) {
comscan.value.getfocus()
} }
} }
})
}
const selectBalanceItem = (item) => {
resultData.value.balance = item
emit('getBalance', resultData.value)
}
const closeScanPopup = () => {
losefocus()
show.value = false
}
const getfocus = () => {
if (comscan.value) {
comscan.value.getfocus()
}
}
const losefocus = () => {
if (comscan.value) {
comscan.value.losefocus()
} }
} }
const emit = defineEmits(['getBalance'])
</script> </script>
<style lang="scss"> <style lang="scss">

1248
src/pages/issue/record/directIssue2.vue

File diff suppressed because it is too large

372
src/pages/point/index.vue

@ -77,219 +77,195 @@
</view> </view>
</template> </template>
<script> <script setup>
// //
const htmlFileUrl = '/hybrid/html/point.html'; const htmlFileUrl = '/hybrid/html/point.html';
import { import {
pathToBase64 pathToBase64
} from "../../api/img-to-base64.js" //js } from "../../api/img-to-base64.js" //js
// #ifdef APP // #ifdef APP
var testModule = uni.requireNativePlugin("TestModule") let testModule = uni.requireNativePlugin("TestModule")
// #endif // #endif
import { ref, watch } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
export default { const timer = ref(null)
name: 'point', const originData = ref([])
data() { const data = ref([])
return { const newHtmlContent = ref('')
timer: null, const isLoadFinish = ref(false)
originData: [], const picIndex = ref(0)
data: [], const picUrl = ref([])
newHtmlContent: '', //html
isLoadFinish: false,
picIndex: 0,
picUrl: []
}
},
methods: {
success(img, item) {
item.barcodeBase641 = img
uni.hideLoading()
this.isLoadFinish = true
// #ifdef APP
plus.io.resolveLocalFileSystemURL(item.barcodeBase641, (entry) => {
// entrytest.html
entry.file((file) => {
let fileReader = new plus.io.FileReader();
fileReader.onloadend = (evt) => {
console.log("文件路径" + evt.target.result)
item.barcodeBase64 = evt.target.result
}
fileReader.readAsDataURL(file);
});
}, (e) => {
console.log("失败" + e)
});
// #endif
},
setHtmlData() {
let str = ''
this.readFile(htmlFileUrl, (htmlContent) => {
this.newHtmlContent = htmlContent
this.data.forEach(item => {
str += `<div class="box" style="page-break-before:always;"><br />
<div class="left">
<div class="left-item">
<div class="label bold-label">物品代码</div>
<div class="value bold-font font-30" id="name1">${item.itemCode}</div>
</div>
<div class="left-item">
<div class="label">物品名称</div>
<div class="value font-30" id="name2">${item.itemName}</div>
</div>
<div class="left-item">
<div class="label">包装名称</div>
<div class="value font-20">${item.packName}</div>
</div>
<div class="left-item">
<div class="label">包装号</div>
<div class="value font-20">${item.packageCode}</div>
</div>`
if (item.productionLineCode && item.productionLineCode.length > 0) {
str += `
<div class="left-item">
<div class="label">生产线</div>
<div class="value font-20">${item.productionLineCode}</div>
</div>
`
} else {
str += `
<div class="left-item">
<div class="label bold-label">父包装号</div>
<div class="value bold-font font-20">${item.parentNumber}</div>
</div>
<div class="left-item">
<div class="label">ASN</div>
<div class="value font-20">${item.asnNumber}</div>
</div>
`
}
str += `
<div class="left-item">
<div class="label">数量</div>
<div class="value bold-font font-30">${item.qty}</div>
</div>`
if (item.fromLocationCode && item.fromLocationCode.length > 0) {
str += `
<div class="left-item">
<div class="label">来源库位</div>
<div class="value font-20">${item.fromLocationCode}</div>
</div>
</div>`
}
str += `
<div class="right">
<div class="image">
<img id='image1' src="${item.barcodeBase64}" alt="" />
</div>
<div class="left-item">
<div class="label">批次</div>
<div class="value font-20">${item.batch}</div>
</div>
<div class="left-item">
<div class="label">物料类型</div>
<div class="value font-20">${item.itemType}</div>
</div>`
if (!(item.productionLineCode && item.productionLineCode.length > 0)) {
str += `
<div class="left-item">
<div class="label">供应商</div>
<div class="value font-20">${item.supplierCode}</div>
</div>
`
}
str += `
<div class="left-item"> const success = (img, item) => {
<div class="label">打印时间</div> item.barcodeBase641 = img
<div class="value font-20">${item.printTimes}</div> uni.hideLoading()
</div> isLoadFinish.value = true
` // #ifdef APP
if (item.fromLocationCode && item.fromLocationCode.length > 0) { plus.io.resolveLocalFileSystemURL(item.barcodeBase641, (entry) => {
str += ` entry.file((file) => {
<div class="left-item"> const fileReader = new plus.io.FileReader()
<div class="label"></div> fileReader.onloadend = (evt) => {
<div class="value"></div> console.log("文件路径" + evt.target.result)
</div> item.barcodeBase64 = evt.target.result
</div> }
</div>` fileReader.readAsDataURL(file)
} }, (e) => {
console.log("失败" + e)
}) })
})
// #endif
}
console.log('str', str) const setHtmlData = () => {
this.newHtmlContent = this.newHtmlContent.replace( let str = ''
"mainBody", str); // readFile(htmlFileUrl, (htmlContent) => {
}); newHtmlContent.value = htmlContent
}, data.value.forEach(item => {
printImage() { str += `<div class="box" style="page-break-before:always;"><br />
uni.showLoading({ <div class="left">
title: "加载中", <div class="left-item">
mask: true <div class="label bold-label">物品代码</div>
}) <div class="value bold-font font-30" id="name1">${item.itemCode}</div>
this.setHtmlData() </div>
let clearInt = setInterval(() => { <div class="left-item">
if (!this.newHtmlContent.mainBody) { <div class="label">物品名称</div>
// #ifdef APP <div class="value font-30" id="name2">${item.itemName}</div>
testModule.doHTMLPrint(this.newHtmlContent) </div>
// #endif <div class="left-item">
clearInterval(clearInt) <div class="label">包装名称</div>
uni.hideLoading() <div class="value font-20">${item.packName}</div>
} </div>
}, 1000) <div class="left-item">
}, <div class="label">包装号</div>
<div class="value font-20">${item.packageCode}</div>
</div>`
if (item.productionLineCode && item.productionLineCode.length > 0) {
str += `
<div class="left-item">
<div class="label">生产线</div>
<div class="value font-20">${item.productionLineCode}</div>
</div>
`
} else {
str += `
<div class="left-item">
<div class="label bold-label">父包装号</div>
<div class="value bold-font font-20">${item.parentNumber}</div>
</div>
<div class="left-item">
<div class="label">ASN</div>
<div class="value font-20">${item.asnNumber}</div>
</div>
`
}
str += `
<div class="left-item">
<div class="label">数量</div>
<div class="value bold-font font-30">${item.qty}</div>
</div>`
if (item.fromLocationCode && item.fromLocationCode.length > 0) {
str += `
<div class="left-item">
<div class="label">来源库位</div>
<div class="value font-20">${item.fromLocationCode}</div>
</div>
</div>`
}
str += `
<div class="right">
<div class="image">
<img id='image1' src="${item.barcodeBase64}" alt="" />
</div>
<div class="left-item">
<div class="label">批次</div>
<div class="value font-20">${item.batch}</div>
</div>
<div class="left-item">
<div class="label">物料类型</div>
<div class="value font-20">${item.itemType}</div>
</div>`
if (!(item.productionLineCode && item.productionLineCode.length > 0)) {
str += `
<div class="left-item">
<div class="label">供应商</div>
<div class="value font-20">${item.supplierCode}</div>
</div>
`
}
str += `
<div class="left-item">
<div class="label">打印时间</div>
<div class="value font-20">${item.printTimes}</div>
</div>
`
if (item.fromLocationCode && item.fromLocationCode.length > 0) {
str += `
<div class="left-item">
<div class="label"></div>
<div class="value"></div>
</div>
</div>
</div>`
}
})
// #ifdef APP console.log('str', str)
// html newHtmlContent.value = newHtmlContent.value.replace("mainBody", str) //
readFile(path, callback) { })
plus.io.resolveLocalFileSystemURL(path, function (entry) { }
entry.file(function (file) {
var reader = new plus.io.FileReader();
reader.onloadend = function (e) {
callback(e.target.result);
};
reader.readAsText(file);
}, function (e) {
console.log("读取文件失败:" + e.message);
});
}, function (e) {
console.log("获取图片资源失败:" + e.message);
});
}
// #endif
},
onLoad(option) { const printImage = () => {
uni.showLoading({ uni.showLoading({
title: '加载中...', title: "加载中",
mask: true mask: true
}); })
if (option.points) { setHtmlData()
this.originData = JSON.parse(option.points); let clearInt = setInterval(() => {
if (newHtmlContent.value && newHtmlContent.value.mainBody) {
// #ifdef APP
testModule.doHTMLPrint(newHtmlContent.value)
// #endif
clearInterval(clearInt)
uni.hideLoading()
} }
this.data = this.originData }, 1000)
}
// this.data = [ // #ifdef APP
// { // html
// "itemCode": "250.832-02", const readFile = (path, callback) => {
// "itemName": "线1ZH", plus.io.resolveLocalFileSystemURL(path, function (entry) {
// "packName": "", entry.file(function (file) {
// "packageCode": "PN20240906-0000000001", const reader = new plus.io.FileReader()
// "batch": "20240719", reader.onloadend = function (e) {
// "parentNumber": null, callback(e.target.result)
// "itemType": "", }
// "asnNumber": "ASNS20240731-0002", reader.readAsText(file)
// "supplierCode": "49000599", }, function (e) {
// "qty": 90, console.log("读取文件失败:" + e.message)
// "printTimes": "2024-09-06+09:29:37", })
// "productionLineCode": null, }, function (e) {
// "fromLocationCode": "C01-190-10", console.log("获取图片资源失败:" + e.message)
// "barcodeString": "HPQ;V1.0;B20240719;AASNS20240731-0002;Q90.000000;I250.832-02;L;PPN20240906-0000000001;S49000599;O49000599;L12;E;UPC;", })
// "barcodeBase64": ""
// }
// ]
},
} }
// #endif
onLoad((option) => {
uni.showLoading({
title: '加载中...',
mask: true
})
if (option.points) {
originData.value = JSON.parse(option.points)
}
data.value = originData.value
})
watch(isLoadFinish, (newVal, oldVal) => {
if (newVal === true) {
}
}, { immediate: true })
</script> </script>
<style> <style>

7
src/pages/productPutaway/job/semiProductPutawayJob.vue

@ -5,13 +5,11 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, getCurrentInstance, nextTick } from 'vue' import { ref, nextTick } from 'vue'
import { import {
onLoad, onLoad,
onShow, onShow,
onNavigationBarButtonTap, onNavigationBarButtonTap,
onReady,
onBackPress,
onReachBottom, onReachBottom,
onPullDownRefresh, onPullDownRefresh,
onHide, onUnload onHide, onUnload
@ -35,9 +33,6 @@ onHide(()=>{
productPutawayJobRef.value.stopRefresh() productPutawayJobRef.value.stopRefresh()
} }
}) })
const onReachBottom = ()=> {
productPutawayJobRef.value.onReach();
}
onUnload(()=>{ onUnload(()=>{
if (productPutawayJobRef.value) { if (productPutawayJobRef.value) {
productPutawayJobRef.value.stopRefresh() productPutawayJobRef.value.stopRefresh()

Loading…
Cancel
Save