This commit is contained in:
houjunxiang
2025-10-09 18:19:55 +08:00
parent f2ffc65094
commit 386f1e7466
1553 changed files with 284685 additions and 32820 deletions

View File

@@ -0,0 +1,122 @@
<template>
<view class="container">
<uni-section type="line" title="基础信息选择"> </uni-section>
<uni-forms label-position="top">
<uni-forms-item label="区域" name="areaCode">
<uni-data-select
:clear="false"
v-model="areaCode"
:localdata="areaCodeList"
@change="handleAreaChange"
></uni-data-select>
</uni-forms-item>
<uni-forms-item v-if="areaCode" label="岗位" name="postCode">
<uni-data-select
:clear="false"
v-model="postCode"
:localdata="postCodeList"
@change="handlePostChange"
></uni-data-select>
</uni-forms-item>
<uni-forms-item v-if="postCode && postCode === weighingPostCode" label="计量点" name="scaleNo">
<uni-data-select :clear="false" v-model="scaleNo" :localdata="scaleNoList"></uni-data-select>
</uni-forms-item>
</uni-forms>
<u-button type="primary" @click="submitForm">保存</u-button>
<u-loading-page :loading="loadingPage"></u-loading-page>
</view>
</template>
<script>
// import { getAreaCodeConfig, getScaleNoConfig, getPostList } from '@/nxTemp/apis/sys.api'
export default {
data() {
return {
weighingPostCode: '监磅',
areaCode: '',
scaleNo: '',
postCode: '',
areaCodeList: [],
scaleNoList: [],
postCodeList: [],
loadingPage: false
}
},
async onLoad() {
this.loadingPage = true
try {
this.areaCodeList = (await getAreaCodeConfig()).map(item => ({ text: item.areaName, value: item.areaCode }))
this.postCodeList = (await getPostList()).map(item => ({ text: item.name, value: item.name }))
if (this.areaCode) {
this.getScaleNoList()
}
this.loadingPage = false
} catch (error) {
this.loadingPage = false
}
},
mounted() {
this.areaCode = this.$store.state.areaCode
this.scaleNo = this.$store.state.scaleNo
this.postCode = this.$store.state.postCode
},
methods: {
async getScaleNoList() {
if (this.postCode && this.postCode === this.weighingPostCode) {
// this.scaleNo = ''
this.scaleNoList = (await getScaleNoConfig({ areaCode: this.areaCode })).map(item => ({
text: item.pointName,
value: item.pointCode
}))
}
},
async handleAreaChange() {
this.postCode = ''
this.scaleNo = ''
},
async handlePostChange() {
this.scaleNo = ''
this.getScaleNoList()
},
async goIndex() {
await this.$store.dispatch('getRoleMenus', this.$store.state.postCode)
uni.reLaunch({
url: 'pages/lims/index/index'
})
},
submitForm() {
if (this.areaCode && this.postCode && this.postCode !== this.weighingPostCode) {
this.$store.commit('SET_AREA_CODE', this.areaCode)
this.$store.commit('SET_POST_CODE', this.postCode)
this.goIndex()
} else if (this.postCode && this.postCode === this.weighingPostCode) {
if (this.scaleNo) {
this.$store.commit('SET_AREA_CODE', this.areaCode)
this.$store.commit('SET_POST_CODE', this.postCode)
this.$store.commit('SET_SCALE_NO', this.scaleNo)
this.goIndex()
} else {
uni.showToast({
title: '请选择',
icon: 'none'
})
}
} else {
uni.showToast({
title: '请选择',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 30rpx;
}
::v-deep .uni-section-header__decoration {
background-color: $uni-color-primary !important;
}
</style>

109
pages/setting/UrlConfig.vue Normal file
View File

@@ -0,0 +1,109 @@
<template>
<view class="container">
<uni-section type="line" title="请求地址和租户ID配置" @click="handleClick"> </uni-section>
<uni-forms label-position="top" label-width="100">
<uni-forms-item label="系统请求地址">
<uni-easyinput v-model="baseUrl" placeholder="请输入系统请求地址"></uni-easyinput>
</uni-forms-item>
<uni-forms-item v-if="showContent" label="租户ID">
<uni-easyinput v-model="tenantId" placeholder="请输入租户ID"></uni-easyinput>
</uni-forms-item>
<uni-forms-item v-if="showContent" label="app更新地址">
<uni-easyinput v-model="upgradeBaseUrl" placeholder="请输入"></uni-easyinput>
</uni-forms-item>
</uni-forms>
<u-button type="primary" @click="submitForm">保存</u-button>
<u-button v-if="showContent" type="primary" @click="clearCache">清除缓存</u-button>
</view>
</template>
<script>
export default {
data() {
return {
baseUrl: '',
tenantId: '',
upgradeBaseUrl: '',
clickCount: 0, // 初始化点击次数为0
threshold: 5, //设置点击次数的阈值
thresholdTime: 2, // 设置连续点击的时间阈值(秒)
timer: null
}
},
computed: {
showContent() {
return this.clickCount >= this.threshold
}
},
mounted() {
this.baseUrl = uni.getStorageSync('base_url')
this.tenantId = uni.getStorageSync('tenant_id')
this.upgradeBaseUrl = uni.getStorageSync('upgradeBaseUrl')
},
methods: {
clearCache() {
uni.showModal({
title: '提示',
content: '确定要清空缓存?',
success: function (res) {
if (res.confirm) {
try {
uni.clearStorageSync()
plus.runtime.restart()
} catch (e) {}
}
}
})
},
submitForm() {
if (!this.baseUrl) {
uni.showToast({
title: '请输入地址和租户',
icon: 'none'
})
return
}
uni.setStorageSync('base_url', this.baseUrl)
uni.setStorageSync('tenant_id', this.tenantId)
uni.setStorageSync('upgradeBaseUrl', this.upgradeBaseUrl)
uni.showToast({
title: '保存成功',
icon: 'none'
})
uni.navigateBack()
},
handleClick() {
// 如果达到阈值,显示内容并重置计数
if (this.showContent) {
clearTimeout(this.timer)
return
}
// 增加点击次数
this.clickCount++
uni.showToast({
title: `再点击${this.threshold - this.clickCount}次可显示内容`,
icon: 'none',
duration: 1000
})
clearTimeout(this.timer)
// 清除之前的定时器(如果有),设置新的定时器
this.timer = setTimeout(() => {
this.resetClickCount()
}, this.thresholdTime * 1000)
},
resetClickCount() {
if (!this.showContent) {
this.clickCount = 0
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 30px;
}
</style>

View File

@@ -0,0 +1,507 @@
<template>
<view class="mask flex-center">
<view class="content botton-radius">
<view class="content-top">
<text class="content-top-text">{{ title }}</text>
<image
class="content-top"
style="top: 0"
width="100%"
height="100%"
src="../../static/images/app_update_bg_top.png"
>
</image>
</view>
<view class="content-header"></view>
<view class="content-body">
<view class="title">
<text>{{ subTitle }}</text>
<!-- <text style="padding-left:20rpx;font-size: 0.5em;color: #666;">v.{{version}}</text> -->
</view>
<view class="body">
<scroll-view class="box-des-scroll" scroll-y="true">
<text class="box-des">
{{ contents }}
</text>
</scroll-view>
</view>
<view class="footer flex-center">
<template v-if="isiOS">
<button class="content-button" style="border: none; color: #fff" plain @click="jumpToAppStore">
{{ downLoadBtnTextiOS }}
</button>
</template>
<template v-else>
<template v-if="!downloadSuccess">
<view class="progress-box flex-column" v-if="downloading">
<progress
class="progress"
border-radius="35"
:percent="downLoadPercent"
activeColor="#3DA7FF"
show-info
stroke-width="10"
/>
<view style="width: 100%; font-size: 14px; display: flex; justify-content: space-around">
<text>{{ downLoadingText }}</text>
<text>({{ downloadedSize }}/{{ packageFileSize }}M)</text>
</view>
</view>
<button v-else class="content-button" style="border: none; color: #fff" plain @click="downloadPackage">
{{ downLoadBtnText }}
</button>
</template>
<button
v-else-if="downloadSuccess"
class="content-button"
style="border: none; color: #fff"
plain
:loading="installing"
:disabled="installing"
@click="installPackage"
>
{{ installing ? '正在安装……' : '下载完成,立即安装' }}
</button>
<button
v-if="installed && isWGT"
class="content-button"
style="border: none; color: #fff"
plain
@click="restart"
>
安装完毕点击重启
</button>
</template>
</view>
</view>
<image
v-if="!is_mandatory"
class="close-img"
src="../../static/images/app_update_close.png"
@click.stop="closeUpdate"
></image>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue'
import { onLoad, onBackPress } from '@dcloudio/uni-app'
const localFilePathKey = '__localFilePath__'
const platform_iOS = 'iOS'
let downloadTask = null
// 工具函数保持原样
function compare(v1 = '0', v2 = '0') {
v1 = String(v1).split('.')
v2 = String(v2).split('.')
const minVersionLens = Math.min(v1.length, v2.length)
let result = 0
for (let i = 0; i < minVersionLens; i++) {
const curV1 = Number(v1[i])
const curV2 = Number(v2[i])
if (curV1 > curV2) {
result = 1
break
} else if (curV1 < curV2) {
result = -1
break
}
}
if (result === 0 && v1.length !== v2.length) {
const v1BiggerThenv2 = v1.length > v2.length
const maxLensVersion = v1BiggerThenv2 ? v1 : v2
for (let i = minVersionLens; i < maxLensVersion.length; i++) {
const curVersion = Number(maxLensVersion[i])
if (curVersion > 0) {
v1BiggerThenv2 ? (result = 1) : (result = -1)
break
}
}
}
return result
}
// 响应式状态
const installForBeforeFilePath = ref('')
const installed = ref(false)
const installing = ref(false)
const downloadSuccess = ref(false)
const downloading = ref(false)
const downLoadPercent = ref(0)
const downloadedSize = ref(0)
const packageFileSize = ref(0)
const tempFilePath = ref('')
const title = ref('更新日志')
const contents = ref('')
const is_mandatory = ref(false)
const subTitle = ref('发现新版本')
const downLoadBtnTextiOS = ref('立即跳转更新')
const downLoadBtnText = ref('立即下载更新')
const downLoadingText = ref('安装包下载中,请稍后')
const version = ref('')
const url = ref('')
const type = ref('')
const platform = ref('')
// 计算属性
const isWGT = computed(() => type.value === 'wgt')
const isiOS = computed(() => !isWGT.value && platform.value.includes(platform_iOS))
// 方法
function checkLocalStoragePackage() {
const localFilePathRecord = uni.getStorageSync(localFilePathKey)
if (localFilePathRecord) {
const { version: recordVersion, savedFilePath, installed: recordInstalled } = localFilePathRecord
if (!recordInstalled && compare(recordVersion, version.value) === 0) {
downloadSuccess.value = true
installForBeforeFilePath.value = savedFilePath
tempFilePath.value = savedFilePath
} else {
deleteSavedFile(savedFilePath)
}
}
}
async function closeUpdate() {
if (downloading.value) {
if (is_mandatory.value) {
uni.showToast({ title: '下载中,请稍后……', icon: 'none', duration: 500 })
return
}
uni.showModal({
title: '是否取消下载?',
cancelText: '否',
confirmText: '是',
success: res => {
if (res.confirm) {
downloadTask?.abort()
uni.navigateBack()
}
}
})
return
}
if (downloadSuccess.value && tempFilePath.value) {
await saveFile(tempFilePath.value, version.value)
uni.navigateBack()
return
}
uni.navigateBack()
}
function downloadPackage() {
downloading.value = true
downloadTask = uni.downloadFile({
url: url.value,
success: res => {
if (res.statusCode === 200) {
downloadSuccess.value = true
tempFilePath.value = res.tempFilePath
// 强制更新
if (is_mandatory.value) {
installPackage()
}
}
},
complete: () => {
downloading.value = false
downLoadPercent.value = 0
downloadedSize.value = 0
packageFileSize.value = 0
downloadTask = null
}
})
downloadTask.onProgressUpdate(res => {
downLoadPercent.value = res.progress
downloadedSize.value = (res.totalBytesWritten / 1024 ** 2).toFixed(2)
packageFileSize.value = (res.totalBytesExpectedToWrite / 1024 ** 2).toFixed(2)
})
}
function installPackage() {
// #ifdef APP-PLUS
if (isWGT.value) {
installing.value = true
}
plus.runtime.install(
tempFilePath.value,
{
force: false
},
async () => {
installing.value = false
installed.value = true
if (isWGT.value) {
if (is_mandatory.value) {
uni.showLoading({ icon: 'none', title: '安装成功,正在重启……' })
setTimeout(() => {
uni.hideLoading()
restart()
}, 1000)
}
} else {
const localFilePathRecord = uni.getStorageSync(localFilePathKey)
uni.setStorageSync(localFilePathKey, {
...localFilePathRecord,
installed: true
})
}
},
async err => {
if (installForBeforeFilePath.value) {
await deleteSavedFile(installForBeforeFilePath.value)
installForBeforeFilePath.value = ''
}
installing.value = false
installed.value = false
uni.showModal({
title: `更新失败${isWGT.value ? '' : 'APK文件不存在'},请重新下载`,
content: err.message,
showCancel: false
})
}
)
if (!isWGT.value) {
uni.navigateBack()
}
// #endif
}
function restart() {
installed.value = false
// #ifdef APP-PLUS
plus.runtime.restart()
// #endif
}
async function saveFile(tempFilePath, version) {
try {
const res = await uni.saveFile({ tempFilePath })
uni.setStorageSync(localFilePathKey, {
version,
savedFilePath: res.savedFilePath
})
} catch (err) {
console.error('保存文件失败:', err)
}
}
async function deleteSavedFile(filePath) {
try {
await uni.removeSavedFile({ filePath })
uni.removeStorageSync(localFilePathKey)
} catch (err) {
console.error('删除文件失败:', err)
}
}
function jumpToAppStore() {
plus.runtime.openURL(url.value)
}
// 生命周期
onLoad(params => {
const { local_storage_key } = params
if (!local_storage_key) {
console.error('local_storage_key为空')
// uni.navigateBack()
return
}
const localPackageInfo = uni.getStorageSync(local_storage_key)
if (!localPackageInfo) {
console.error('安装包信息为空')
uni.navigateBack()
return
}
const requiredKeys = ['version', 'url', 'type']
for (const key of requiredKeys) {
if (!localPackageInfo[key]) {
console.error(`参数 ${key} 必填`)
uni.navigateBack()
return
}
}
// 更新响应式状态
version.value = localPackageInfo.version
url.value = localPackageInfo.url
type.value = localPackageInfo.type
platform.value = localPackageInfo.platform || ''
title.value = localPackageInfo.title || '更新日志'
contents.value = localPackageInfo.contents || ''
is_mandatory.value = localPackageInfo.is_mandatory || false
subTitle.value = localPackageInfo.subTitle || '发现新版本'
downLoadBtnTextiOS.value = localPackageInfo.downLoadBtnTextiOS || '立即跳转更新'
downLoadBtnText.value = localPackageInfo.downLoadBtnText || '立即下载更新'
downLoadingText.value = localPackageInfo.downLoadingText || '安装包下载中,请稍后'
checkLocalStoragePackage()
})
onBackPress(() => {
if (is_mandatory.value) return true
if (downloadTask) downloadTask.abort()
return false
})
</script>
<style>
page {
background: transparent;
}
.flex-center {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
}
.mask {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.65);
}
.botton-radius {
border-bottom-left-radius: 15px;
border-bottom-right-radius: 15px;
}
.content {
position: relative;
top: 0;
width: 400px;
background-color: #fff;
box-sizing: border-box;
padding: 0 30px;
font-family: Source Han Sans CN;
max-height: 80vh;
overflow: hidden;
border-radius: 20px;
}
.content-top {
position: absolute;
top: -55px;
left: 0;
width: 400px;
height: 180px;
}
.content-top-text {
font-size: 24px;
font-weight: bold;
color: #f8f8fa;
position: absolute;
top: 80px;
left: 30px;
z-index: 1;
}
.content-header {
padding-top: 80px;
height: 40px;
}
.content-body {
padding-bottom: 20px;
}
.title {
font-size: 20px;
font-weight: bold;
color: #3da7ff;
line-height: 1.5;
margin-bottom: 15px;
}
.footer {
height: 90px;
display: flex;
align-items: center;
justify-content: space-around;
margin-top: 15px;
}
.box-des-scroll {
box-sizing: border-box;
padding: 0 20px;
height: 50px;
text-align: left;
margin-bottom: 15px;
}
.box-des {
font-size: 16px;
color: #000000;
line-height: 1.5;
}
.progress-box {
width: 100%;
}
.progress {
width: 90%;
height: 20px;
border-radius: 10px;
margin-bottom: 10px;
}
.close-img {
width: 40px;
height: 40px;
z-index: 1000;
position: absolute;
bottom: -70px;
left: calc(50% - 20px);
}
.content-button {
text-align: center;
flex: 1;
font-size: 18px;
font-weight: 400;
color: #ffffff;
border-radius: 20px;
margin: 0 10px;
height: 50px;
line-height: 50px;
background: linear-gradient(to right, #1785ff, #3da7ff);
min-width: 160px;
}
.flex-column {
display: flex;
flex-direction: column;
align-items: center;
}
</style>