初始化仓库

This commit is contained in:
tao
2025-12-18 14:11:48 +08:00
parent e96f277a68
commit 54ec472bd4
1107 changed files with 158756 additions and 0 deletions

90
utils/audio.ts Normal file
View File

@@ -0,0 +1,90 @@
/**
* 这是Fnaudio方法的必选参数约束
*/
type FunTypeAudioRequired = {
/**
* 音频的数据链接,用于直接播放。
*/
readonly src : string,
/**
* 是否自动开始播放,默认 true
*/
readonly autoplay ?:boolean ,
/**
* 是否遵循系统静音开关,
* 当此参数为 false 时,即使用户打开了静音开关,也能继续发出声音,
* 默认值 true
*/
readonly obeyMuteSwitch ?:boolean,
/**
* 开始播放的位置单位s默认 0
*/
readonly startTime ?: number,
/**
* 是否循环播放,默认 false
*/
readonly loop ?: boolean,
/**
* 音量。范围 0~1
*/
readonly volume ?: number,
/**
* 播放的倍率。可取值0.5/0.8/1.0/1.25/1.5/2.0默认值为1.0
*/
readonly playbackRate ?: 0.5|0.8|1.0|1.25|1.5|2.0
}
/**
* 封装提示音的方法类
*/
class Audio {
constructor(required : FunTypeAudioRequired ){
if (required?.volume != undefined && (required.volume < 0 || required.volume > 1)) {
throw new Error('提供的volume值不符合规范');
}
let innerAudioContext = uni.createInnerAudioContext();
innerAudioContext = Object.assign(innerAudioContext,required)
innerAudioContext.onPlay(() => {
console.log('开始播放');
});
setTimeout(() => {
innerAudioContext.stop()
innerAudioContext.destroy()
console.log(',销毁实例')
}, 900);
innerAudioContext.onError((res) => {
console.error(res.errMsg);
console.error(res.errCode);
});
}
}
/**
* 成功提示音
* @return
*/
export function autioSuccess():void {
let audio = null;
audio = new Audio({
src:'/static/audio/success.mp3',
playbackRate:2,
autoplay : true,
volume : 1,
})
audio = null
}
/**
* 失败提示音
* @return
*/
export function autioError():void {
let audio = null;
audio = new Audio({
src:'/static/audio/error.mp3',
playbackRate:2,
autoplay : true,
volume : 1,
})
audio = null
}

13
utils/auth.js Normal file
View File

@@ -0,0 +1,13 @@
const TokenKey = 'App-Token'
export function getToken() {
return uni.getStorageSync(TokenKey)
}
export function setToken(token) {
return uni.setStorageSync(TokenKey, token)
}
export function removeToken() {
return uni.removeStorageSync(TokenKey)
}

55
utils/common.js Normal file
View File

@@ -0,0 +1,55 @@
/**
* 显示消息提示框
* @param content 提示的标题
*/
export function toast(content) {
uni.showToast({
icon: 'none',
title: content,
duration: 2000,
})
}
/**
* 显示模态弹窗
* @param content 提示的标题
*/
export function showConfirm(content) {
return new Promise((resolve, reject) => {
uni.showModal({
title: '提示',
content: content,
cancelText: '取消',
confirmText: '确定',
success: function(res) {
resolve(res)
}
})
})
}
/**
* 参数处理
* @param params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
var part = encodeURIComponent(propName) + "="
if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']'
var subPart = encodeURIComponent(params) + "="
result += subPart + encodeURIComponent(value[key]) + "&"
}
}
} else {
result += part + encodeURIComponent(value) + "&"
}
}
}
return result
}

14
utils/constant.js Normal file
View File

@@ -0,0 +1,14 @@
const constant = {
avatar: 'vuex_avatar',
name: 'vuex_name',
code: 'vuex_code',
roles: 'vuex_roles',
permissions: 'vuex_permissions',
empId: 'vuex_emp_id',
empName: 'vuex_emp_name',
empCode: 'vuex_emp_code',
empDeptId: 'vuex_emp_dept_id',
empDeptName: 'vuex_emp_dept_name',
}
export default constant

6
utils/errorCode.js Normal file
View File

@@ -0,0 +1,6 @@
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}

28
utils/judge.ts Normal file
View File

@@ -0,0 +1,28 @@
/**
* 判断传入的值是否有值(不为null,'',undefined)
* 有则返回true没有则返回false
* @param {number | string | object} value
* @return boolean
*/
export function hasValue(value : number | string | { [key: string]: any}):boolean{
if(typeof value == 'number' || typeof value == 'string'){
if(value != null && value != '' && value != undefined) return true
}
if(typeof value === 'object'){
for(let i in value){
if(value[i] != null && value[i] != '' && value[i] != undefined) return true
}
}
return false
}
/**
* 获取当前北京时间
* @return
*/
export function getBeijingTime():string{
//获取当前北京时间的时间戳(单位为毫秒)
const stamp= new Date().getTime() + 8 * 60 * 60 * 1000;
const beijingTime = new Date(stamp).toISOString().replace(/T/, ' ').replace(/\..+/, '').substring(0, 19);
return beijingTime
}

94
utils/loding/loding.vue Normal file
View File

@@ -0,0 +1,94 @@
<template>
<div class="ring">
加载中
<span></span>
</div>
</template>
<script>
</script>
<style>
body{
margin:0;
padding:0;
background:#262626;
font-family:sans-serif;
font-size:20px;
}
.ring{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%, -50%);
width:150px;
height:150px;
border:3px solid #3d3d3d;
border-radius:50%;
text-align:center;
line-height:150px;
letter-spacing:4px;
text-transform:uppercase;
color:#fff000;
text-shadow:0 0 15px #fff000;
box-shadow:0 0 20px rgba(0,0,0,.5);
}
.ring:before{
content:'';
display:block;
position:absolute;
top:-3px;
left:-3px;
width:100%;
height:100%;
border:3px solid transparent;
border-top:3px solid #fff000;
border-left:3px solid transparent;
border-right:3px solid #fff000;
border-radius:50%;
animation:ani-cyle 2s linear infinite;
}
span{
position:absolute;
width:50%;
height:4px;
display:block;
top:calc(50% - 2px);
left:50%;
background:none;
animation:animate 2s linear infinite;
transform-origin:left;
}
span:after{
content:'';
width:16px;
height:16px;
background:#fff000;
border-radius:50%;
box-shadow: 0 0 20px #fff000;
position:absolute;
right:-8px;
top:calc(50% - 8px);
}
@keyframes ani-cyle{
0%{
transform:rotate(0deg);
}
100%{
transform:rotate(360deg);
}
}
@keyframes animate{
0%{
transform:rotate(45deg);
}
100%{
transform:rotate(405deg);
}
}
</style>

109
utils/parseRelease.js Normal file
View File

@@ -0,0 +1,109 @@
function getBeijingTime(date = new Date()) {
const f = n => String(n).padStart(2, '0');
const t = new Date(date.toLocaleString('en-US', { timeZone: 'Asia/Shanghai' }));
return `${t.getFullYear()}-${f(t.getMonth()+1)}-${f(t.getDate())} ${f(t.getHours())}:${f(t.getMinutes())}:${f(t.getSeconds())}`;
}
/**
* 获取最新发布版本信息
* @param {Array} releases - 发布版本数组
* @param {Object} options - 配置项
* @param {boolean} options.includePrerelease - 是否包含预发布版(默认 true
* @returns {Object|null} 最新版本信息
*/
export function getLatestRelease(releases, options = {}) {
const { includePrerelease = true } = options;
try {
if (!Array.isArray(releases)) {
throw new Error("参数错误releases 必须是数组");
}
if (releases.length === 0) {
throw new Error("没有可用的版本数据");
}
// 过滤掉预发布(如果不包含)
let filtered = releases;
if (!includePrerelease) {
filtered = releases.filter(r => !r.prerelease);
if (filtered.length === 0) {
throw new Error("没有找到正式版版本数据");
}
}
// 按发布时间排序,取最新的
const latest = filtered.sort((a, b) =>
new Date(b.published_at) - new Date(a.published_at)
)[0];
if (!latest) {
throw new Error("无法找到最新版本");
}
return {
latestVersion: latest.tag_name.replace('v', '') || null,
download_url: latest.assets?.[0]?.browser_download_url.replace('192.168.1.132:3000', '223.94.45.156:10830') ||
null,
prerelease: latest.prerelease,
published_at: latest.published_at || null,
title: latest.name || "",
description: latest.body || ""
};
} catch (error) {
console.error("获取最新版本出错:", error.message);
return null;
}
}
export function getReleases(releases, options = {}) {
const { includePrerelease = true } = options;
try {
if (!Array.isArray(releases)) {
throw new Error("参数错误releases 必须是数组");
}
if (releases.length === 0) {
throw new Error("没有可用的版本数据");
}
// 过滤掉预发布(如果不包含)
let filtered = releases;
if (!includePrerelease) {
filtered = releases.filter(r => !r.prerelease);
if (filtered.length === 0) {
throw new Error("没有找到正式版版本数据");
}
}
// 按发布时间排序
filtered.sort((a, b) =>
new Date(b.published_at) - new Date(a.published_at)
);
let renderedReleases = [];
filtered.forEach(item => {
renderedReleases.push({
version: item.tag_name.replace('v', '') || null,
download_url: item.assets?.[0]?.browser_download_url.replace('192.168.1.132:3000',
'223.94.45.156:10830') ||
null,
prerelease: item.prerelease,
published_at: getBeijingTime(new Date(item.published_at || null)) || null,
title: item.name || "",
description: item.body || ""
})
});
console.log(filtered);
console.log(renderedReleases);
return renderedReleases;
} catch (error) {
uni.showToast({
title: "获取版本列表出错",
icon: 'none'
});
console.error("获取版本列表出错:", error);
return null;
}
}

50
utils/permission.js Normal file
View File

@@ -0,0 +1,50 @@
import store from '@/store'
/**
* 字符权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkPermi(value) {
if (value && value instanceof Array && value.length > 0) {
const permissions = store.getters && store.getters.permissions
const permissionDatas = value
const all_permission = "*:*:*"
const hasPermission = permissions.some(permission => {
return all_permission === permission || permissionDatas.includes(permission)
})
if (!hasPermission) {
return false
}
return true
} else {
console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
return false
}
}
/**
* 角色权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkRole(value) {
if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles
const permissionRoles = value
const super_admin = "admin"
const hasRole = roles.some(role => {
return super_admin === role || permissionRoles.includes(role)
})
if (!hasRole) {
return false
}
return true
} else {
console.error(`need roles! Like checkRole="['admin','editor']"`)
return false
}
}

91
utils/request.js Normal file
View File

@@ -0,0 +1,91 @@
import store from '@/store'
import config from '@/config'
import {
getToken
} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import {
toast,
showConfirm,
tansParams
} from '@/utils/common'
let timeout = 60 * 2 * 1000
const baseUrl = config.baseUrl
const request = config => {
// let baseUrlTemp = (uni.getStorageSync("base_url") || config.baseUrl || baseUrl)
//双菱
let baseUrlTemp = (uni.getStorageSync("base_url") || config.baseUrl || baseUrl) + '/wc-mes'
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
config.header = config.header || {}
if (getToken() && !isToken) {
config.header['Authorization'] = 'Bearer ' + getToken()
}
// get请求映射params参数
if (config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.url = url
}
return new Promise((resolve, reject) => {
uni.request({
method: config.method || 'get',
timeout: config.timeout || timeout,
url: baseUrlTemp + config.url,
data: config.data,
header: config.header,
dataType: 'json'
}).then(response => {
let [error, res] = response
if (error) {
toast('后端接口连接异常')
reject('后端接口连接异常')
return
}
const code = res.data.code || 200
const msg = errorCode[code] || res.data.msg || errorCode['default']
if (code === 401) {
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
if (res.confirm) {
store.dispatch('LogOut').then(res => {
uni.reLaunch({
url: '/pages/login'
})
})
}
})
reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
toast(msg)
reject({
code: 500,
msg
})
} else if (code !== 200) {
toast(msg)
reject(code)
}
resolve(res.data)
})
.catch(error => {
let {
message
} = error
if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
toast(message)
reject(error)
})
})
}
export default request

44
utils/storage.js Normal file
View File

@@ -0,0 +1,44 @@
import constant from './constant'
// 存储变量名
let storageKey = 'storage_data'
// 存储节点变量名
let storageNodeKeys = [
constant.avatar,
constant.name,
constant.code,
constant.roles,
constant.permissions,
constant.empId,
constant.empName,
constant.empCode,
constant.empDeptId,
constant.empDeptName,
]
// 存储的数据
let storageData = uni.getStorageSync(storageKey) || {}
const storage = {
set: function(key, value) {
if (storageNodeKeys.indexOf(key) != -1) {
let tmp = uni.getStorageSync(storageKey)
tmp = tmp ? tmp : {}
tmp[key] = value
uni.setStorageSync(storageKey, tmp)
}
},
get: function(key) {
return storageData[key] || ""
},
remove: function(key) {
delete storageData[key]
uni.setStorageSync(storageKey, storageData)
},
clean: function() {
uni.removeStorageSync(storageKey)
}
}
export default storage

View File

@@ -0,0 +1,278 @@
<template>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{titleText}}</text>
</view>
<view v-if="mode === 'base'" class="uni-dialog-content">
<slot>
<text class="uni-dialog-content-text">{{content}}</text>
</slot>
</view>
<view v-else class="uni-dialog-content">
<slot>
<input class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholderText" :focus="focus">
</slot>
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="closeDialog" v-if="showClose">
<text class="uni-dialog-button-text">{{closeText}}</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">{{okText}}</text>
</view>
</view>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import popup from '@/uni_modules/uni-popup/components/uni-popup/popup.js'
import messages from '@/uni_modules/uni-popup/components/uni-popup/i18n/index.js'
const {
t
} = initVueI18n(messages)
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式、
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
* @event {Boolean} showClose 是否显示取消按钮
*/
export default {
name: "uniPopupDialog",
mixins: [popup],
emits: ['confirm', 'close'],
props: {
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: [String, Number],
default: ''
},
type: {
type: String,
default: 'error'
},
mode: {
type: String,
default: 'base'
},
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
beforeClose: {
type: Boolean,
default: false
},
cancelText: {
type: String,
default: ''
},
confirmText: {
type: String,
default: ''
},
showClose:{
type: Boolean,
default: false
}
},
data() {
return {
dialogType: 'error',
focus: false,
val: ""
}
},
computed: {
okText() {
return this.confirmText || t("uni-popup.ok")
},
closeText() {
return this.cancelText || t("uni-popup.cancel")
},
placeholderText() {
return this.placeholder || t("uni-popup.placeholder")
},
titleText() {
return this.title || t("uni-popup.title")
}
},
watch: {
type(val) {
this.dialogType = val
},
mode(val) {
if (val === 'input') {
this.dialogType = 'info'
}
},
value(val) {
this.val = val
}
},
created() {
// 对话框遮罩不可点击
this.popup.disableMask()
// this.popup.closeMask()
if (this.mode === 'input') {
this.dialogType = 'info'
this.val = this.value
} else {
this.dialogType = this.type
}
},
mounted() {
this.focus = true
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
if (this.mode === 'input') {
this.$emit('confirm', this.val)
} else {
this.$emit('confirm')
}
if (this.beforeClose) return
// this.popup.close()
},
/**
* 点击取消按钮
*/
closeDialog() {
this.$emit('close')
if (this.beforeClose) return
this.popup.close()
},
close() {
this.popup.close()
}
}
}
</script>
<style lang="scss">
.uni-popup-dialog {
width: 300px;
border-radius: 11px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 25px;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 20px;
}
.uni-dialog-content-text {
font-size: 14px;
color: #6C6C6C;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #f5f5f5;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 45px;
}
.uni-border-left {
border-left-color: #f0f0f0;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
font-size: 16px;
color: #333;
}
.uni-button-color {
color: #007aff;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
border: 1px #eee solid;
height: 40px;
padding: 0 10px;
border-radius: 5px;
color: #555;
}
.uni-popup__success {
color: #4cd964;
}
.uni-popup__warn {
color: #f0ad4e;
}
.uni-popup__error {
color: #dd524d;
}
.uni-popup__info {
color: #909399;
}
</style>

606
utils/uniapp/utilsInput.vue Normal file
View File

@@ -0,0 +1,606 @@
<template>
<view class="uni-easyinput" :class="{'uni-easyinput-error':msg}" :style="boxStyle">
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc"
@click="onClickIcon('prefix')" size="22"></uni-icons>
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea"
:class="{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder"
:placeholderStyle="placeholderStyle" :disabled="disabled"
placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused"
:autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm"></textarea>
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input"
:style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'"
:placeholder="placeholder" :placeholderStyle="placeholderStyle"
placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength"
:focus="focused" :confirmType="confirmType" @focus="_Focus" @blur="_Blur" @input="onInput"
@confirm="onConfirm" @click="clickInput" />
<template v-if="type === 'password' && passwordIcon">
<!-- 开启密码时显示小眼睛 -->
<uni-icons v-if="isVal" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}"
:type="showPassword?'eye-slash-filled':'eye-filled'" :size="22"
:color="focusShow?'#2979ff':'#c0c4cc'" @click="onEyes">
</uni-icons>
</template>
<template v-else-if="suffixIcon">
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc"
@click="onClickIcon('suffix')" size="22"></uni-icons>
</template>
<template v-else>
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon"
:class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
:color="msg?'#dd524d':(focusShow?'#2979ff':'#c0c4cc')" @click="onClear"></uni-icons>
</template>
<slot name="right"></slot>
</view>
</view>
</template>
<script>
/**
* Easyinput 输入框
* @description 此组件可以实现表单的输入与校验,包括 "text" 和 "textarea" 类型。
* @tutorial https://ext.dcloud.net.cn/plugin?id=3455
* @property {String} value 输入内容
* @property {String } type 输入框的类型默认text password/text/textarea/..
* @value text 文本输入键盘
* @value textarea 多行文本输入键盘
* @value password 密码输入键盘
* @value number 数字输入键盘注意iOS上app-vue弹出的数字键盘并非9宫格方式
* @value idcard 身份证输入键盘信、支付宝、百度、QQ小程序
* @value digit 带小数点的数字键盘 App的nvue页面、微信、支付宝、百度、头条、QQ小程序支持
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件点击可清空输入框内容默认true
* @property {Boolean} autoHeight 是否自动增高输入区域type为textarea时有效默认true
* @property {String } placeholder 输入框的提示文字
* @property {String } placeholderStyle placeholder的样式(内联样式,字符串),如"color: #ddd"
* @property {Boolean} focus 是否自动获得焦点默认false
* @property {Boolean} disabled 是否禁用默认false
* @property {Number } maxlength 最大输入长度,设置为 -1 的时候不限制最大长度默认140
* @property {String } confirmType 设置键盘右下角按钮的文字仅在type="text"时生效默认done
* @property {Number } clearSize 清除图标的大小单位px默认15
* @property {String} prefixIcon 输入框头部图标
* @property {String} suffixIcon 输入框尾部图标
* @property {Boolean} trim 是否自动去除两端的空格
* @value both 去除两端空格
* @value left 去除左侧空格
* @value right 去除右侧空格
* @value start 去除左侧空格
* @value end 去除右侧空格
* @value all 去除全部空格
* @value none 不去除空格
* @property {Boolean} inputBorder 是否显示input输入框的边框默认true
* @property {Boolean} passwordIcon type=password时是否显示小眼睛图标
* @property {Object} styles 自定义颜色
* @event {Function} input 输入框内容发生变化时触发
* @event {Function} focus 输入框获得焦点时触发
* @event {Function} blur 输入框失去焦点时触发
* @event {Function} confirm 点击完成按钮时触发
* @event {Function} iconClick 点击图标时触发
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
*/
function obj2strClass(obj) {
let classess = ''
for (let key in obj) {
const val = obj[key]
if (val) {
classess += `${key} `
}
}
return classess
}
function obj2strStyle(obj) {
let style = ''
for (let key in obj) {
const val = obj[key]
style += `${key}:${val};`
}
return style
}
export default {
name: 'uni-easyinput',
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change'],
model: {
prop: 'modelValue',
event: 'update:modelValue'
},
options: {
virtualHost: true
},
inject: {
form: {
from: 'uniForm',
default: null
},
formItem: {
from: 'uniFormItem',
default: null
},
},
props: {
name: String,
value: [Number, String],
modelValue: [Number, String],
type: {
type: String,
default: 'text'
},
clearable: {
type: Boolean,
default: true
},
autoHeight: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: ' '
},
placeholderStyle: String,
focus: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
maxlength: {
type: [Number, String],
default: 140
},
confirmType: {
type: String,
default: 'done'
},
clearSize: {
type: [Number, String],
default: 24
},
inputBorder: {
type: Boolean,
default: true
},
prefixIcon: {
type: String,
default: ''
},
suffixIcon: {
type: String,
default: ''
},
trim: {
type: [Boolean, String],
default: true
},
passwordIcon: {
type: Boolean,
default: true
},
styles: {
type: Object,
default () {
return {
color: '#333',
disableColor: '#F7F6F6',
borderColor: '#e5e5e5'
}
}
},
errorMessage: {
type: [String, Boolean],
default: ''
},
},
data() {
return {
focused: false,
val: '',
showMsg: '',
border: false,
isFirstBorder: false,
showClearIcon: false,
showPassword: false,
focusShow: false,
localMsg: '',
};
},
computed: {
// 输入框内是否有值
isVal() {
const val = this.val
// fixed by mehaotian 处理值为0的情况字符串0不在处理范围
if (val || val === 0) {
return true
}
return false
},
msg() {
// console.log('computed', this.form, this.formItem);
// if (this.form) {
// return this.errorMessage || this.formItem.errMsg;
// }
// TODO 处理头条 formItem 中 errMsg 不更新的问题
return this.localMsg || this.errorMessage
},
// 因为uniapp的input组件的maxlength组件必须要数值这里转为数值用户可以传入字符串数值
inputMaxlength() {
return Number(this.maxlength);
},
// 处理外层样式的style
boxStyle() {
return `color:${this.inputBorder && this.msg?'#e43d33':this.styles.color};`
},
// input 内容的类和样式处理
inputContentClass() {
return obj2strClass({
'is-input-border': this.inputBorder,
'is-input-error-border': this.inputBorder && this.msg,
'is-textarea': this.type === 'textarea',
'is-disabled': this.disabled
})
},
inputContentStyle() {
const focusColor = this.focusShow ? '#2979ff' : this.styles.borderColor
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor
return obj2strStyle({
'border-color': borderColor || '#e5e5e5',
'background-color': this.disabled ? this.styles.disableColor : '#fff'
})
},
// input右侧样式
inputStyle() {
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px'
return obj2strStyle({
'padding-right': paddingRight,
'padding-left': this.prefixIcon ? '' : '10px'
})
}
},
watch: {
value(newVal) {
this.val = newVal
},
modelValue(newVal) {
this.val = newVal
},
focus(newVal) {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
})
}
},
created() {
this.init()
// TODO 处理头条vue3 computed 不监听 inject 更改的问题formItem.errMsg
if (this.form && this.formItem) {
this.$watch('formItem.errMsg', (newVal) => {
this.localMsg = newVal
})
}
},
mounted() {
this.$nextTick(() => {
this.focused = this.focus
this.focusShow = this.focus
this.val = ''
})
},
methods: {
/**
* 初始化变量值
*/
init() {
if (this.value || this.value === 0) {
this.val = this.value
} else if (this.modelValue || this.modelValue === 0) {
this.val = this.modelValue
} else {
this.val = null
}
},
/**
* 点击图标时触发
* @param {Object} type
*/
onClickIcon(type) {
this.$emit('iconClick', type)
},
/**
* 显示隐藏内容,密码框时生效
*/
onEyes() {
this.showPassword = !this.showPassword
this.$emit('eyes', this.showPassword)
},
/**
* 输入时触发
* @param {Object} event
*/
onInput(event) {
let value = event.detail.value;
// 判断是否去除空格
if (this.trim) {
if (typeof(this.trim) === 'boolean' && this.trim) {
value = this.trimStr(value)
}
if (typeof(this.trim) === 'string') {
value = this.trimStr(value, this.trim)
}
};
if (this.errMsg) this.errMsg = ''
this.val = value
// TODO 兼容 vue2
this.$emit('input', value);
// TODO 兼容 vue3
this.$emit('update:modelValue', value)
},
/**
* 外部调用方法
* 获取焦点时触发
* @param {Object} event
*/
onFocus() {
this.$nextTick(() => {
this.focused = true
})
this.$emit('focus', null);
},
_Focus(event) {
this.focusShow = true
this.$emit('focus', event);
},
/**
* 外部调用方法
* 失去焦点时触发
* @param {Object} event
*/
onBlur() {
this.focused = false
this.$emit('focus', null);
},
_Blur(event) {
let value = event.detail.value;
this.focusShow = false
this.$emit('blur', event);
// 根据类型返回值在event中获取的值理论上讲都是string
this.$emit('change', this.val)
// 失去焦点时参与表单校验
if (this.form && this.formItem) {
const {
validateTrigger
} = this.form
if (validateTrigger === 'blur') {
this.formItem.onFieldChange()
}
}
},
/**
* 按下键盘的发送键
* @param {Object} e
*/
onConfirm(e) {
this.$emit('confirm', this.val);
this.$emit('change', this.val)
},
/**
* 清理内容
* @param {Object} event
*/
onClear(event) {
this.val = '';
// TODO 兼容 vue2
this.$emit('input', '');
// TODO 兼容 vue2
// TODO 兼容 vue3
this.$emit('update:modelValue', '')
// 点击叉号触发
this.$emit('clear')
},
/**
* 去除空格
*/
trimStr(str, pos = 'both') {
if (pos === 'both') {
return str.trim();
} else if (pos === 'left') {
return str.trimLeft();
} else if (pos === 'right') {
return str.trimRight();
} else if (pos === 'start') {
return str.trimStart()
} else if (pos === 'end') {
return str.trimEnd()
} else if (pos === 'all') {
return str.replace(/\s+/g, '');
} else if (pos === 'none') {
return str;
}
return str;
},
/**
* 输入框点击事件
*/
clickInput(){
this.$emit('click')
},
}
};
</script>
<style lang="scss">
$uni-error: #e43d33;
$uni-border-1: #DCDFE6 !default;
.uni-easyinput {
/* #ifndef APP-NVUE */
width: 100%;
/* #endif */
flex: 1;
position: relative;
text-align: left;
color: #333;
font-size: 16px;
}
.uni-easyinput__content {
flex: 1;
/* #ifndef APP-NVUE */
width: 100%;
display: flex;
box-sizing: border-box;
// min-height: 36px;
/* #endif */
flex-direction: row;
align-items: center;
// 处理border动画刚开始显示黑色的问题
border-color: #fff;
transition-property: border-color;
transition-duration: 0.3s;
}
.uni-easyinput__content-input {
/* #ifndef APP-NVUE */
width: auto;
/* #endif */
position: relative;
overflow: hidden;
flex: 1;
line-height: 1;
font-size: 16px;
height: 35px;
// min-height: 36px;
}
.uni-easyinput__placeholder-class {
color: #999;
font-size: 16px;
// font-weight: 200;
}
@media screen and (min-width: 600px) {
.uni-easyinput__content-input {
height: 50px;
}
}
.is-textarea {
align-items: flex-start;
}
.is-textarea-icon {
margin-top: 5px;
}
.uni-easyinput__content-textarea {
position: relative;
overflow: hidden;
flex: 1;
line-height: 1.5;
font-size: 16px;
margin: 6px;
margin-left: 0;
height: 80px;
min-height: 80px;
/* #ifndef APP-NVUE */
min-height: 80px;
width: auto;
/* #endif */
}
.input-padding {
padding-left: 10px;
}
.content-clear-icon {
padding: 0 5px;
}
.label-icon {
margin-right: 5px;
margin-top: -1px;
}
// 显示边框
.is-input-border {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
flex-direction: row;
align-items: center;
border: 1px solid $uni-border-1;
border-radius: 4px;
/* #ifdef MP-ALIPAY */
overflow: hidden;
/* #endif */
}
.uni-error-message {
position: absolute;
bottom: -17px;
left: 0;
line-height: 12px;
color: $uni-error;
font-size: 12px;
text-align: left;
}
.uni-error-msg--boeder {
position: relative;
bottom: 0;
line-height: 22px;
}
.is-input-error-border {
border-color: $uni-error;
.uni-easyinput__placeholder-class {
color: mix(#fff, $uni-error, 50%);
;
}
}
.uni-easyinput--border {
margin-bottom: 0;
padding: 10px 15px;
// padding-bottom: 0;
border-top: 1px #eee solid;
}
.uni-easyinput-error {
padding-bottom: 0;
}
.is-first-border {
/* #ifndef APP-NVUE */
border: none;
/* #endif */
/* #ifdef APP-NVUE */
border-width: 0;
/* #endif */
}
.is-disabled {
background-color: #F7F6F6;
color: #D5D5D5;
.uni-easyinput__placeholder-class {
color: #D5D5D5;
font-size: 16px;
}
}
</style>

81
utils/upload.js Normal file
View File

@@ -0,0 +1,81 @@
import store from '@/store'
import config from '@/config'
import {
getToken
} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import {
toast,
showConfirm,
tansParams
} from '@/utils/common'
let timeout = 10000
const baseUrl = config.baseUrl
const upload = config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
config.header = config.header || {}
if (getToken() && !isToken) {
config.header['Authorization'] = 'Bearer ' + getToken()
}
// get请求映射params参数
if (config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.url = url
}
return new Promise((resolve, reject) => {
uni.uploadFile({
timeout: config.timeout || timeout,
url: (uni.getStorageSync("base_url") || baseUrl) + '/wc-mes' + config.url,
// url: (uni.getStorageSync("base_url") || baseUrl) + config.url,
filePath: config.filePath,
name: config.name || 'file',
header: config.header,
formData: config.formData,
success: (res) => {
let result = JSON.parse(res.data)
const code = result.code || 200
const msg = errorCode[code] || result.msg || errorCode['default']
if (code === 200) {
resolve(result)
} else if (code == 401) {
showConfirm("登录状态已过期,您可以继续留在该页面,或者重新登录?").then(res => {
if (res.confirm) {
store.dispatch('LogOut').then(res => {
uni.reLaunch({
url: '/pages/login/login'
})
})
}
})
reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
toast(msg)
reject('500')
} else if (code !== 200) {
toast(msg)
reject(code)
}
},
fail: (error) => {
let {
message
} = error
if (message == 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
toast(message)
reject(error)
}
})
})
}
export default upload

91
utils/version.js Normal file
View File

@@ -0,0 +1,91 @@
import store from '@/store'
import config from '@/config'
import errorCode from '@/utils/errorCode'
import {
toast,
showConfirm,
tansParams
} from '@/utils/common'
let timeout = 60 * 2 * 1000
const token = 'token 5793f8d09ea4b5cea097e3ed3704493009b52147';
const baseUrl = `${ config.giteaUrl }/api/v1/repos/Wance/rd_mes_uniapp`;
const request = config => {
config.header = config.header || {}
config.header['Authorization'] = token
// get请求映射params参数
if (config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.url = url
}
return new Promise((resolve, reject) => {
uni.request({
method: config.method || 'get',
timeout: config.timeout || timeout,
url: baseUrl + config.url,
data: config.data,
header: config.header,
dataType: 'json'
}).then(response => {
let [error, res] = response
if (error) {
toast('后端接口连接异常')
reject('后端接口连接异常')
return
}
console.log(res)
const code = res.statusCode || 200
const msg = res.errMsg || errorCode[code]
switch (code) {
case 200:
resolve(res.data);
break;
case 401:
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
if (res.confirm) {
store.dispatch('LogOut').then(() => {
uni.reLaunch({
url: '/pages/login'
})
})
}
})
reject('无效的会话,或者会话已过期,请重新登录')
break;
case 500:
toast(msg);
reject({
code: 500,
msg
})
break;
default:
toast(msg);
reject(code);
break;
}
})
.catch(error => {
let {
message
} = error
if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
toast(message)
reject(error)
})
})
}
export default request;

88
utils/wms-request.js Normal file
View File

@@ -0,0 +1,88 @@
import store from '@/store'
import config from '@/config'
import {
getToken
} from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import {
toast,
showConfirm,
tansParams
} from '@/utils/common'
let timeout = 60 * 2 * 1000
// const baseUrl = config.wmsUrl
//双菱
const baseUrl = config.baseUrl
const request = config => {
// let baseUrlTemp = (uni.getStorageSync("wms_url") || config.baseUrl || baseUrl);
//双菱
let baseUrlTemp = (uni.getStorageSync("base_url") || config.baseUrl || baseUrl) + '/wc-wms';
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
config.header = config.header || {}
if (getToken() && !isToken) {
config.header['Authorization'] = 'Bearer ' + getToken()
}
// get请求映射params参数
if (config.params) {
let url = config.url + '?' + tansParams(config.params)
url = url.slice(0, -1)
config.url = url
}
return new Promise((resolve, reject) => {
uni.request({
method: config.method || 'get',
timeout: config.timeout || timeout,
url: baseUrlTemp + config.url,
data: config.data,
header: config.header,
dataType: 'json'
}).then(response => {
let [error, res] = response
if (error) {
toast('后端接口连接异常')
reject('后端接口连接异常')
return
}
const code = res.data.code || 200
const msg = errorCode[code] || res.data.msg || errorCode['default']
if (code === 401) {
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
if (res.confirm) {
store.dispatch('LogOut').then(res => {
uni.reLaunch({
url: '/pages/login'
})
})
}
})
reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
toast(msg)
reject({code:500,msg})
} else if (code !== 200) {
toast(msg)
reject(code)
}
resolve(res.data)
})
.catch(error => {
let {
message
} = error
if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substr(message.length - 3) + '异常'
}
toast(message)
reject(error)
})
})
}
export default request