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

142
.gitignore vendored
View File

@@ -1,132 +1,10 @@
# ---> Node .project
# Logs .DS_Store
logs */.DS_Store
*.log /.git/
npm-debug.log* /.idea
yarn-debug.log* /.hbuilderx
yarn-error.log* /.unpackage
lerna-debug.log* /unpackage
.pnpm-debug.log* unpackage/
/.rar
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

39
App.vue Normal file
View File

@@ -0,0 +1,39 @@
<script>
export default {
onLaunch: function() {
let _this = this;
let token = uni.getStorageSync('token')
console.log('判断登录状态',token)
if (token) {
//存在则关闭启动页进入首页
// #ifdef APP-PLUS
plus.navigator.closeSplashscreen()
// #endif
} else {
//不存在则跳转至登录页
uni.reLaunch({
url: "/pages/index/login",
success: () => {
// #ifdef APP-PLUS
plus.navigator.closeSplashscreen()
// #endif
}
})
}
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
uni-toast{
z-index: 10080;
}
</style>

View File

@@ -1,3 +1,3 @@
# orico-wms-pda # orico-wms-pda
wms-pda(移动端) 仓储系统PDA端

View File

@@ -0,0 +1,72 @@
#### props
|名称 |类型 |默认值 |说明 |
|- |- |- |- |
|width |string |'200px' |选择框宽度 |
|height |string |'30px' |选择框高度 |
|bgColor |string |'#fff' |选择框背景颜色 |
|round |boolean|true |是否开启圆角 |
|defaultValue |string |'请选择'|默认显示的名称| |
|valueName |string |'label' |显示的内容字段名,必传 |
|keyName |string |'value' |绑定的内容字段名,必传 |
|list |array |[] |展示的内容列表 |
|showClose |boolean|true |是否显示删除按钮 |
|multiple |boolean|false |是否开启多选 |
|filterable |boolean|false |是否开启搜索功能,开启后直接输入值不选择也可以保存内容 |
#### events
|事件名|说明|
|-|-|
|change|选择的内容改变时触发返回的参数为列表的item|
#### 使用举例
需要绑定的值通过`v-model`绑定,如下面的`chooseValue`需要获取item的值可以监听`@change`事件
开启多选`multiple`双向绑定的值为数组类型在change事件中根据自己需求进行处理。
`valueName`属性必须传,告知组件需要显示的是什么值
```html
<template>
<view class="login">
<w-select
style="margin-left: 20rpx;"
v-model='chooseValue'
defaultValue="所有审批人"
:list='list'
valueName='content'
keyName="id"
@change='change'
>
</w-select>
</view>
</template>
<script>
export default {
data() {
return {
chooseValue: "",
list: [{
id: 1,
content: '张三'
}, {
id: 2,
content: '李四'
}, {
id: 3,
content: '王五'
}],
};
},
methods: {
change(e) {
console.log('chooseValue', this.chooseValue)
}
},
}
</script>
```

View File

@@ -0,0 +1,630 @@
<template>
<view class="w-select" id="wSelect" :style="{
'--select-wrap-width': width,
'--select-wrap-height': height,
'--select-bg-color': bgColor
}">
<view :class="isShow ? 'select-wrap-active' : ''" class="select-wrap" @click.stop="changeShow">
<view v-if="multiple" class="select-content">
<view class="select-content-item-default" v-if="multiSelectList.length === 0">
{{ defaultValue }}
</view>
<view class="select-content-item" v-if="multiSelectList.length > 0">
{{ multiSelectList[0][valueName] }}
</view>
<view class="select-content-item" v-if="multiSelectList.length > 1">
{{ multiLength }}
</view>
</view>
<input v-if="!multiple || filterable" type="text" @input="inputChange" :placeholder="defaultValue"
:disabled="!filterable" v-model="inputData" @focus="myselectFocus" :focus="inputFocus" />
<view @click.stop="refreshValue" class="close-icon" v-if="showClose && inputData.length > 0">
<image :src="refreshUrl" mode=""></image>
</view>
<view v-if="inputData.length <= 0 || !showClose" :class="isShow ? 'w-select-arrow-up' : ''"
class="w-select-arrow " />
<!-- 下拉框options -->
<scroll-view scroll-y v-show="optionsShow" :class="[
isShow
? showPosition === 'bottom'
? 'animation-bottom-in'
: 'animation-top-in'
: showPosition === 'bottom'
? 'animation-bottom-out'
: 'animation-top-out',
showPosition === 'bottom'
? 'position-bottom'
: 'position-top'
]" class="select-options" @scrolltolower="onBottom">
<!--自定义option -->
<view v-for="item in filterList">
<view class="n_myselect" @click.stop="handleClickItem(item)"
v-if="((optionType=='order'&& item.availableQty>0)||(optionType=='order-cg' &&item.waitSlefQty>0)) ">
<text class="nmyt1">{{item.sourceBillNo}}</text>
<text class="nmyt2">{{item.specifications}}</text>
<view class="nmyt3">
<text>{{item.materialNumber}}</text>
<text class="nmyt4">数量{{optionType=='order' ?item.availableQty:item.waitSlefQty}}</text>
</view>
</view>
</view>
<!--自定义option 非采购 -->
<view class="n_myselect" @click.stop="handleClickItem(item)" v-for="item in filterList"
v-if="optionType=='order-fcg'">
<text class="nmyt1">{{item.sourceBillNo}}</text>
<view v-for="(cit,index) in item.details">
<view class="" style="background: #fff;margin-bottom: 5px;padding: 5px;border-radius: 6px;"
v-if="cit.availableQty">
<text class="nmyt2">{{cit.specifications}}</text>
<view class="nmyt3">
<text>{{cit.materialNumber}}</text>
<text class="nmyt4">数量{{cit.availableQty}}</text>
</view>
</view>
</view>
</view>
<!--strat原始的 -->
<view @click.stop="handleClickItem(item)" :class="
multiple &&
multiSelectList.find(
res => res[keyName] === item[keyName]
)
? 'item-active'
: value === item[keyName]
? 'item-active'
: ''
" v-for="item in filterList" class="select-option-item myitem" v-if="optionType=='default'">
{{ item[valueName] }}
</view>
<!--end原始的 -->
<view class="options-no-data" v-if="loadingFlag == 2||filterList.length < 1">
没有更多数据了
</view>
<view v-else>
<view class="options-no-data" v-if="loadingFlag == 1 && filterList.length !==wselectTotal">上拉加载更多...
</view>
<view class="options-no-data" v-if="loadingFlag == 1 && filterList.length ==wselectTotal">没有更多数据了
</view>
</view>
</scroll-view>
</view>
<view v-if="isShow" @click.stop="closeContentSelect" class="contentMask"></view>
</view>
</template>
<script>
export default {
props: {
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '30px'
},
bgColor: {
type: String,
default: 'inherit'
},
//是否多选
multiple: {
type: Boolean,
default: false
},
//是否可搜索
filterable: {
type: Boolean,
default: false
},
//是否显示关闭按钮
showClose: {
type: Boolean,
default: false
},
//渲染列表
list: {
type: Array,
default: () => [],
required: true
},
//双向绑定的值
value: {
type: [Array, String, Number],
default: ''
},
//默认显示的内容
defaultValue: {
type: String,
default: '请选择'
},
//显示的内容
valueName: {
type: String,
default: 'label',
required: true
},
// 绑定的内容
keyName: {
type: String,
default: 'value',
required: true
},
//判断下拉数据结构是什么类型的
optionType: {
type: String,
default: 'default'
},
//是否开启上拉加载
pagingSet: {
type: Boolean,
default: false
},
//是否聚焦
focus: {
type: Boolean,
default: false
},
//分页页码
pageNo: {
type: Number,
default: 1
},
//分页页码
loadingFlag: {
type: Number,
default: 0
},
wselectTotal: {
type: Number,
default: 0
},
//判斷清楚的是那個選擇款
selectTag: {
type: String,
default: ''
},
},
watch: {
value: {
handler(newVal, oldVal) {
// console.log('下拉组件111',newVal,oldVal)
}
},
focus: {
handler(newVal, oldVal) {
this.inputFocus = newVal
}
},
pageNo: {
handler(newVal, oldVal) {
this.wselectPageNo = newVal
console.log('分页111', newVal, oldVal)
}
},
list: {
immediate: true,
deep: true,
handler(news) {
if(news.length) {
this.filterList = news
const findItem = news.find(
item => item[this.keyName] === this.value
)
if (findItem) {
this.inputData = findItem[this.valueName]
}
}
}
}
},
computed: {
multiLength() {
const length = this.multiSelectList.length - 1
return '+' + length
},
bottomDistance() {
return (
this.windowHeight -
this.distanceTop -
this.curHeight
) // 当前元素距离可视屏幕底部的距离
},
},
data() {
return {
wselectPageNo: this.pageNo,
inputFocus: this.focus,
inputData: this.value,
multiSelectList: this.multiple ? this.value : [],
isShow: false,
optionsShow: false,
windowHeight: null,
curHeight: 0,
distanceTop: 0,
showPosition: 'bottom',
filterList: [],
refreshUrl: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDQ4IDQ4IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgZmlsbD0id2hpdGUiIGZpbGwtb3BhY2l0eT0iMC4wMSIvPjxwYXRoIGQ9Ik0yNCA0NEMzNS4wNDU3IDQ0IDQ0IDM1LjA0NTcgNDQgMjRDNDQgMTIuOTU0MyAzNS4wNDU3IDQgMjQgNEMxMi45NTQzIDQgNCAxMi45NTQzIDQgMjRDNCAzNS4wNDU3IDEyLjk1NDMgNDQgMjQgNDRaIiBmaWxsPSJub25lIiBzdHJva2U9IiM3YzZlNmUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxwYXRoIGQ9Ik0yOS42NTY5IDE4LjM0MzFMMTguMzQzMiAyOS42NTY4IiBzdHJva2U9IiM3YzZlNmUiIHN0cm9rZS13aWR0aD0iNCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhdGggZD0iTTE4LjM0MzIgMTguMzQzMUwyOS42NTY5IDI5LjY1NjgiIHN0cm9rZT0iIzdjNmU2ZSIgc3Ryb2tlLXdpZHRoPSI0IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4='
}
},
mounted() {
this.$nextTick(() => {
const res = uni.getSystemInfoSync()
this.windowHeight = res.windowHeight // 当前设备屏幕高度
uni.createSelectorQuery().in(this).select('#wSelect').boundingClientRect(data => {
if(!data) {
return;
}
this.distanceTop = data.top // 当前元素距离顶部的距离
this.curHeight = data.height
}).exec()
})
},
methods: {
// 上拉加载
onBottom(val) {
if (this.pagingSet) {
this.$emit('onBottomPage', ++this.wselectPageNo)
}
// console.log('触底')
},
// 判断input是否聚焦
myselectFocus(val) {
// console.log(val)
// uni.$emit('focus',222)
this.$emit('focus', val)
},
showPositon() {
this.showPosition = 'bottom'
if (this.bottomDistance < this.windowHeight / 3) {
this.showPosition = 'top'
}
},
changeShow() {
this.isShow = !this.isShow
if (this.isShow === false) {
this.filterList = this.list
setTimeout(() => {
this.optionsShow = false
}, 200)
} else {
this.showPositon()
this.optionsShow = this.isShow
}
},
closeContentSelect() {
this.isShow = false
setTimeout(() => {
this.optionsShow = false
}, 200)
},
inputChange(e) {
// 输入的时候打开框
const value = e.detail.value
if (value) {
this.isShow = true
setTimeout(() => {
this.optionsShow = true
}, 200)
} else {
this.isShow = false
setTimeout(() => {
this.optionsShow = false
}, 200)
this.filterList = []
}
this.$emit('input', value)
this.filterList = this.list.filter(item =>
item[this.valueName].includes(value)
)
},
refreshValue() {
this.$emit('input', '')
this.$emit('clearnFn', this.selectTag)
this.inputData = ''
// this.$emit('change', '')
this.filterList = this.list
if (this.multiple) {
this.multiSelectList = []
}
},
handleClickItem(e) {
if (this.multiple) {
this.multiSelect(e)
} else {
this.$emit('input', e[this.keyName])
this.inputData = e[this.valueName]
this.$emit('change', e)
this.changeShow()
}
},
multiSelect(item) {
let index = this.multiSelectList.findIndex(
res => res[this.valueName] === item[this.valueName]
)
if (index > -1) {
this.multiSelectList.splice(index, 1)
} else {
this.multiSelectList.push(item)
}
this.inputData = ''
this.filterList = this.list
this.$emit('input', this.multiSelectList)
this.$emit('change', item)
}
}
}
</script>
<style lang="scss" scoped>
.n_myselect {
padding: 5px 10px;
background: #F3F6FA;
border-radius: 6px;
margin: 0 10px;
margin-top: 5px;
display: flex;
flex-direction: column;
color: #222;
.nmyt1,
.nmyt2,
.nmyt3,
.nmyt4 {
font-size: 12px;
}
.nmyt1 {
font-weight: bold;
padding-bottom: 2px;
border-bottom: 1px dashed #BBBDC1;
}
.nmyt2 {
padding-top: 2px;
}
.nmyt3 {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
.w-select {
--select-wrap-width: 200px;
--select-wrap-height: 30px;
--select-border-radius: 4px;
--select-border: 1px solid #dcdfe6;
--select-active-border: 1px solid #409eff;
// --select-options-max-height: 150px;
--select-options-max-height: 220px;
--select-option-item-font-size: 14px;
--select-input-font-size: 14px;
--no-data-default-color: #999999;
--select-options-box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
// --select-bg-color: #fff;
display: flex;
.select-wrap {
// position: relative;
width: var(--select-wrap-width);
height: var(--select-wrap-height);
border-radius: var(--select-border-radius);
transition: all 0.2s;
border: var(--select-border);
background-color: var(--select-bg-color);
display: flex;
justify-content: space-between;
align-items: center;
input {
flex: 1;
min-width: 0;
width: 100%;
height: 100%;
padding: 0 2px;
font-size: var(--select-input-font-size);
}
.select-content {
font-size: var(--select-option-item-font-size);
display: flex;
align-items: center;
.select-content-item {
background-color: #f4f4f5;
border-radius: var(--select-border-radius);
color: #aa93b1;
margin-left: 5px;
padding: 2px 6px;
}
.select-content-item-default {
color: var(--no-data-default-color);
margin-left: 5px;
}
}
.close-icon {
width: 15px;
height: 15px;
position: absolute;
right: 7px;
top: 46%;
z-index: 1000;
transform: translateY(-50%);
image {
width: 100%;
height: 100%;
}
}
.position-bottom {
top: calc(var(--select-wrap-height) + 10px);
}
.position-top {
bottom: calc(var(--select-wrap-height) + 10px);
}
.select-options {
position: absolute;
left: 0;
right: 0;
box-shadow: 1px 4px 14px #919191 !important;
border-radius: var(--select-border-radius);
background-color: #fff;
box-shadow: var(--select-options-box-shadow);
z-index: 999;
max-height: var(--select-options-max-height);
overflow: scroll;
overflow-x: hidden;
padding: 5px 0;
.select-option-item {
transition: background-color 0.2s;
padding: 5px;
font-size: var(--select-option-item-font-size);
margin-bottom: 5px;
}
.item-active {
background-color: #f5f7fa;
color: #409eff !important;
font-weight: 700;
}
.options-no-data {
color: var(--no-data-default-color);
text-align: center;
font-size: var(--select-option-item-font-size);
}
}
.w-select-arrow {
transition: all 0.3s;
border-left: 1px solid #999999;
border-bottom: 1px solid #999999;
height: 8px;
width: 8px;
margin: 3px 10px 0;
transform: translateY(-50%) rotate(-45deg);
-webkit-transform: translateY(-50%) rotate(-45deg);
border-right: 1px solid transparent;
border-top: 1px solid transparent;
display: inline-block;
}
.w-select-arrow-up {
transform: rotate(-225deg);
}
}
.select-wrap-active {
border: var(--select-active-border);
}
.animation-bottom-in {
animation-name: bottom-in;
animation-duration: 0.4s;
animation-timing-function: ease-out;
animation-fill-mode: both;
}
.animation-bottom-out {
animation-name: bottom-out;
animation-duration: 0.2s;
animation-timing-function: ease-out;
animation-fill-mode: both;
}
.animation-top-in {
animation-name: top-in;
animation-duration: 0.4s;
animation-timing-function: ease-out;
animation-fill-mode: both;
}
.animation-top-out {
animation-name: top-out;
animation-duration: 0.2s;
animation-timing-function: ease-out;
animation-fill-mode: both;
}
@keyframes bottom-in {
0% {
opacity: 0;
transform: translateY(-15%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes bottom-out {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(-20%);
}
}
@keyframes top-in {
0% {
opacity: 0;
transform: translateY(15%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes top-out {
0% {
opacity: 1;
transform: translateY(0);
}
100% {
opacity: 0;
transform: translateY(20%);
}
}
.contentMask {
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
z-index: 998;
}
}
.myitem {
border-bottom: 1px dashed #DADDDF;
margin: 0 24px;
}
.myitem:last-child {
border-bottom: none
}
</style>

20
index.html Normal file
View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>

39
main.js Normal file
View File

@@ -0,0 +1,39 @@
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
// 引入全局uView
import uView from '@/uni_modules/uview-ui'
import {broadcastScan} from '@/static/js/scanCode'
import api from '@/static/js/http'
import * as Util from "@/static/js/public.js";
import dir from '@/static/js/directive'
Vue.directive('preventReClick', dir.preventReClick)
//全局注入文件,方便在各个功能中直接使用
Vue.prototype.$broadcastScan=broadcastScan
Vue.config.productionTip = false
Vue.prototype.$api = api
Vue.prototype.$util = Util;
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
Vue.use(uView)
// #endif
// #ifdef VUE3
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif

108
manifest.json Normal file
View File

@@ -0,0 +1,108 @@
{
"name" : "wms",
"appid" : "__UNI__2420758",
"description" : "",
"versionName" : "1.0.6",
"versionCode" : 106,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2"
}

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"id": "cus-selects-fan",
"name": "下拉选择,单选,精准搜索,模糊搜索,清除选择",
"displayName": "下拉选择,单选,精准搜索,模糊搜索,清除选择",
"version": "1.0.11",
"description": "自定义下拉选择 可以清除选择,可以模糊搜素,可以精准搜索 (有问题请在评论区留言-我会收到邮件请各位可以给3-5颗小星星哦小星星就是我更新优化的动力哦)",
"keywords": [
"自定义下拉选择"
],
"dcloudext": {
"category": [
"前端组件",
"通用组件"
]
}
}

156
pages.json Normal file
View File

@@ -0,0 +1,156 @@
{
"pages": [ //pages数组中第一项表示应用启动页参考https://uniapp.dcloud.io/collocation/pages
{
//登录
"path": "pages/login",
"style": {
// 自定义导航栏
"navigationStyle":"custom",
"navigationBarTitleText": ""
}
},{
//拣货出库
"path" : "pages/outbound/index",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//采购上架
"path" : "pages/warehous/cgPutOnsale",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//首页
"path" : "pages/index",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//入库
"path": "pages/warehous/index",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//收货
"path" : "pages/warehous/takeDelivery",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//非采购上架
"path" : "pages/warehous/noCgPutOnsale",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//其他内库操作菜单
"path" : "pages/otherUnderwear/index",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//快速改箱/装箱
"path" : "pages/otherUnderwear/fastSetbox",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//整箱移货上架
"path" : "pages/otherUnderwear/moveBoxup",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//整箱移货上架
"path" : "pages/otherUnderwear/moveBoxDown",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//出库回退上架
"path" : "pages/otherUnderwear/outStockUp",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//入库回退下架
"path" : "pages/otherUnderwear/inStockDown",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//库存查询
"path" : "pages/otherUnderwear/inventory",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//出库箱信息
"path" : "pages/otherUnderwear/outbound",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
},{
//盘点
"path" : "pages/Inventory/index",
"style" :
{
"navigationBarTitleText": "",
"navigationStyle":"custom",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}

1091
pages/Inventory/index.vue Normal file

File diff suppressed because it is too large Load Diff

BIN
pages/WPS Office.lnk Normal file

Binary file not shown.

104
pages/index.vue Normal file
View File

@@ -0,0 +1,104 @@
<!-- 首页菜单 -->
<template>
<view class="sy">
<image src="../static/img/sybg.png" class="sybg" mode=""></image>
<view class="sy_info">
<view class="sy_txt">
<text class="t1">hello</text>
<text class="t2">你好,{{name}}</text>
</view>
<image src="../static/img/out.png" class="syoutico" mode="" @click="logoutfn"></image>
</view>
<view class="sy_meuns">
<view class="sy_item" @click="otherPage(1)">
<image src="../static/img/syico1.png" class="symeunico"></image>
<text class="t1">入库</text>
</view>
<view class="sy_item" @click="otherPage(2)">
<image src="../static/img/syico3.png" class="symeunico"></image>
<text class="t1">出库</text>
</view>
<view class="sy_item" @click="otherPage(3)">
<image src="../static/img/syico2.png" class="symeunico"></image>
<text class="t1">其他库内操作</text>
</view>
<view class="sy_item" @click="otherPage(4)">
<image src="../static/img/syico4.png" class="symeunico"></image>
<text class="t1">盘点</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello',
name: ''
}
},
onLoad() {
this.name = uni.getStorageSync('userInfo').nickname
this.getlxlist()
},
// 物理键盘的监听
onBackPress(e) {
this.$util.appgoBack(e, 'login')
return true
},
methods: {
//获取系统类型所需要下拉列表
getlxlist() {
this.$api.get("/SysConfig/GetStatus").then(res => {
if (res.status == 200) {
uni.setStorageSync('allTypelist', res.data)
}
})
},
// 跳转页面
otherPage(type) {
//入库
if (type == 1) {
uni.navigateTo({
url: "/pages/warehous/index"
})
}
//出库
if (type == 2) {
uni.navigateTo({
url: "/pages/outbound/index"
})
}
//其他内库操作
if (type == 3) {
uni.navigateTo({
url: "/pages/otherUnderwear/index"
})
}
//盘点
if (type == 4) {
uni.navigateTo({
url: "/pages/Inventory/index"
})
}
},
//退出
logoutfn() {
this.$api.post('/Login/LoginOut').then(res => {
if (res.status == 200) {
uni.reLaunch({
url: "/pages/login"
})
uni.clearStorageSync()
}
console.log("退出", res)
})
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
</style>

105
pages/login.vue Normal file
View File

@@ -0,0 +1,105 @@
<!-- 登录 -->
<template>
<view class="login">
<view class="logoPage">
<image src="../static/img/logo.png" class="imglogo" mode=""></image>
<view class="logo_from">
<view class="item">
<text class="loglabe">账号</text>
<u-input placeholder="请输入账号" border="bottom" clearable class="loginput" v-model="userName"
:focus='startfocus == "zh"'></u-input>
</view>
<view class="item">
<text class="loglabe">密码</text>
<u-input placeholder="请输入密码" border="bottom" clearable class="loginput" v-model="password"
:password="passwordtag">
<template slot="suffix">
<u-icon :name="passwordtag ? 'eye': 'eye-fill'" size="24" @click="handleShowPass"></u-icon>
</template>
</u-input>
</view>
<view class="dlbt" @click="loginfn">登录</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
smjg: '',
startfocus: 'zh', // 光标自动聚焦
userName: '', // 賬戶
password: '', // 密碼
passwordtag: true,
}
},
onLoad(option) {
this.$broadcastScan.init(this.getScancode);
// 缓存设备的像素比用来区分普通安卓还是pda
uni.setStorageSync('devicePixelRatio', uni.getDeviceInfo().devicePixelRatio <= 1.5 ? 'pad' : 'normalAnroid')
},
onUnload() {
this.$broadcastScan.stop();
},
onHide() {
this.$broadcastScan.stop();
},
onShow() {
this.$broadcastScan.start();
},
mounted() {
},
methods: {
handleShowPass() {
this.passwordtag = !this.passwordtag
},
bule(val) {
this.searchText = val.target.value
console.log('看看我在键盘模式下的触发bule', val.target.value)
},
submit(val) {
console.log('看看我在键盘模式下的触发', val.target.value)
},
getScancode(code) {
// 有些PDA会自带换行符trim函数处理下
code = code.trim()
this.v1 = code
this.searchText = code
//code就是扫描获取的值
console.log(code)
},
// 登录
loginfn() {
if (!this.userName) {
uni.$u.toast('请输入账户名')
return
}
if (!this.password) {
uni.$u.toast('请输入密码')
return
}
this.$api.post('/Login/LoginInPwd', {
userName: this.userName,
password: this.password
}).then(res => {
if (res.status == 200) {
uni.setStorageSync('token', res.data.tokenInfo.tokenType + " " + res.data.tokenInfo.token)
uni.setStorageSync('userInfo', res.data.userInfo)
uni.navigateTo({
url: "/pages/index"
})
} else {
uni.$u.toast(res.message)
}
console.log("登录", res)
})
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,650 @@
<!-- 入库回退下架 -->
<template>
<view class="shpage ckhtsxjpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">入库回退下架</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item itembg2">
<view class="it">
<text class="t1">仓库:</text>
<text class="t2">{{ warehouseName }}</text>
</view>
</view>
<view class="item" :class="{ itembg2: xlhstrList.length > 0 }" :style="{ 'pointer-events': xlhstrList.length > 0 ? 'none' : '' }">
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
箱号:
</text>
<input
v-model.trim="xhNo"
class="inpt1"
type="text"
@focus="inputfocus($event, 'box')"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'box')"
:focus="focusInput == 'box'"
/>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item" :class="{ itembg2: !xhNo }" :style="{ 'pointer-events': !xhNo ? 'none' : '' }">
<view class="it itsp">
<text class="t1">序列号:</text>
<input
v-model.trim="xlhVal"
class="inpt1"
type="text"
@focus="inputfocus($event, 'xlh')"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'xlh')"
:focus="focusInput == 'xlh'"
/>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('xlh')"></image>
</view>
</view>
<view class="item itembg2">
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
下架数量:
</text>
<input v-model.trim="xjNum" class="inpt1" type="number" :disabled="true" />
</view>
</view>
<view class="item item2">
<view class="it2 it50">
<text class="t1">{{ yxjTotalNum }}</text>
<text class="t2">已下架总数量</text>
</view>
<view class="it2 it50" @click="xhmodelOpen">
<text class="t1 rednum">{{ boxstrList.length }}</text>
<text class="t2">已扫描箱数</text>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb cgsjrklb f_cgsjrklb" :style="{ 'margin-top': heights.top + 'px', height: heights.body + 'px' }">
<view class="item" v-for="(item, index) in dataList" :key="item.boxBillNo">
<view class="it" style="border: none">
<text class="txt titstr">{{ item.boxBillNo }}</text>
<view class="cssj_it ckhtit" v-for="(it, indexs) in item.details" :key="it.specifications">
<view class="tlinb">
<text class="txt ntxtcolor">{{ it.specifications }}</text>
<view class="nwemxflex">
<text class="txt">{{ it.materialNumber }}</text>
<view class="fgline"></view>
<text class="txt">数量 {{ it.wuToatal }}</text>
</view>
</view>
<view class="txtNum nslbzflex">
<view class="n-sl-bz">
<view class="tinput">
<text class="ntxtcolor nbtxt">下架数量</text>
<u-input
v-model="it.qty"
border="surround"
clearable
class="inpt"
type="number"
:disabled="it.itxlhlist.length > 0 || dqXH !== item.boxBillNo"
@focus="inputfocus($event, 'xjNum', item.boxBillNo)"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'xjNum')"
@input="xjNumInput($event, 'xjNum', index, item.boxBillNo)"
></u-input>
</view>
<view class="tinput" @click="openRemarTk(it.remark,index,indexs)">
<text class="ntxtcolor nbtxt">备注</text>
<u-input v-model="it.remark" border="surround" clearable class="inpt" type="text" style="pointer-events: none"></u-input>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 已上架箱号-->
<u-modal :show="xhlistshow" title="已扫箱信息" @confirm="xhlistshow = false">
<view style="display: flex; flex-direction: column; overflow-y: auto; max-height: 60vh; overflow-y: auto">
<view v-for="(item, index) in boxstrList">{{ item }}</view>
</view>
</u-modal>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空下架数量</view>
<view class="bt bt2" @click="wcNxetFn">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content="qktkContent" @confirm="qktkconfirm" :showCancelButton="true" @cancel="qktkshow = false"></u-modal>
<!--备注弹框-->
<u-modal :show="remarkshow" title="备注" @confirm="remarkconfirm" :showCancelButton="true" @cancel="remarkshow = false">
<textarea v-model="dqremarkVal" auto-height :maxlength="100" class="remaktinpt" placeholder="请输入备注信息" />
</u-modal>
</view>
</template>
<script>
export default {
data() {
return {
heights: {
top: 0,
body: 0
},
xhlistshow: false,
focusInput: 'box', // 自动聚焦
focusTag: '', // 判斷聚焦
warehouseName: '', // 仓库名称
warehouseCode: '', // 仓库编码
cwNum: '', // 仓位的值
cwselectList: [], //仓位下拉集合
cwcode: '', // 仓位code
xhNo: '', // 箱号的值
boxstrList: [], // 缓存的箱号信息(多个)
xlhVal: '', // 序列号的值
xlhstrList: [], // 缓存的序列號信息(多个)
xjNum: '', // 上架数量
yxjTotalNum: 0, // 已上架总数量
filterable: true,
dataList: [], // 明细列表数据
dqBoxInfo: {}, // 扫描当前箱的物料信息
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空',
qktkContent: '是否清空当前页面已经扫描的箱号信息/序列号信息和统计数值?',
dqboxNO: '', //用来是否保存当前输入箱号的值
dqboxXlh: '', //用来是否保存当前输入xlh的值
erpOrgCode: '',
dqXH: '', // 点回车确认的当前箱号
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
remarkshow: false, // 当前备注弹框
dqremarkVal:'',//当前弹框显示备注内容
remarkidx:[],//记录当前编辑的是那个明细的备注
twoData:[],
scanTracker: {
lastScanTime: 0,
lastScanCode: null
} // 源头处理扫码段时间内重复扫
};
},
watch: {
xhNo(n) {
if (!n) {
this.dqboxNO = '';
}
},
xlhVal(n) {
if (!n) {
this.dqboxXlh = '';
}
}
},
onReady() {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts');
},
onLoad() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode);
this.$broadcastScan.start();
this.stopScanCode();
this.startScanCode();
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode();
},
onShow() {
this.$broadcastScan.start();
this.startScanCode();
},
onBackPress(e) {
this.$util.appgoBack(e, 'otherUnderwearIndex');
return true;
},
methods: {
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if (res.code === this.scanTracker.lastScanCode && timeSinceLastScan < 4000) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code);
}
});
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan');
},
// 打开当前明细行备注弹框
openRemarTk(remarkStr,index,indexs){
this.remarkshow=true
this.dqremarkVal = remarkStr
this.remarkidx=[index,indexs]
},
// 确认修改弹框备注
remarkconfirm(){
this.dataList[this.remarkidx[0]].details[this.remarkidx[1]].remark=this.dqremarkVal
this.remarkshow=false
},
// 打开查看箱号
xhmodelOpen() {
if (this.boxstrList.length > 0) {
this.xhlistshow = true;
}
},
//明细上架数量输入实时监听
xjNumInput(val, type, index, dqXH) {
if (val) {
this.yxjTotalNum = this.$util.sumNestedObjectValues(this.dataList, 'details', 'qty');
this.dqXH = dqXH;
this.setxjNUM();
}
},
// 完成
wcNxetFn() {
if (this.boxstrList.length == 0 || !this.yxjTotalNum) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1000
});
return;
}
let formdata = {
method: 2,
orgCode: this.erpOrgCode,
stockCode: this.warehouseCode,
subStockCode: this.cwcode,
details: []
};
console.log(this.dataList, '=this.dataList=');
this.dataList.forEach((it) => {
if (it.details && it.details.length > 0) {
it.details.forEach((k) => {
formdata.details.push({
boxId: k.boxId,
serialNumberBoxId: k.boxId,
materialNumber: k.materialNumber,
qty: k.qty,
subStockCode: k.subStockCode,
serialNumbers: k.itxlhlist,
remark: k.remark
});
});
}
});
console.log('入库回退下架1', this.dataList, formdata);
if (this.requestStatus) {
return false;
}
this.requestStatus = true;
this.$api.post('/BackRecord/OffShelf', formdata).then((res) => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1000
});
setTimeout(() => {
uni.navigateTo({
url: '/pages/otherUnderwear/inStockDown'
});
}, 200);
// this.$router.go(0)
}
});
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == 'normalAnroid') {
this.$util.doScanQrCode().then((res) => {
this.focusInput = type;
this.focusTag = type;
this.getScancode(res.result);
});
}
},
// 获取扫描的值
getScancode(code) {
console.log('获取扫描的值', this.focusTag, code);
if (this.focusTag == 'box') {
// 有些PDA会自带换行符trim函数处理下
this.xhNo = '';
this.xhNo = code.trim();
this.getboxinfo();
}
// 序列号
if (this.focusTag == 'xlh') {
this.xlhVal = '';
this.xlhVal = code.trim();
this.getXlhInfo();
//根据序列号去更新对应的明细规格型号的上架数量的值 扫描一个数量加一,重复扫描要提示
}
},
// 清空二次确认
qktkconfirm() {
this.boxstrList = [];
this.twoData=[]
this.xlhstrList = [];
this.dataList = [];
this.xhNo = '';
this.xlhVal = '';
this.yxjTotalNum = 0;
this.xjNum = null;
this.qktkshow = false;
this.warehouseCode = '';
this.warehouseName = '';
},
// 輸入失去焦點
inputblur(val, type) {},
// 输入聚焦
inputfocus(val, type, dqXH) {
this.focusTag = type;
if (type == 'xjNum') {
this.dqXH = dqXH;
// 统计当前箱子的下架数量总和
this.setxjNUM();
}
},
//当前限制 下架数量重新统计
setxjNUM() {
this.xjNum = 0;
this.dataList.forEach((it) => {
if (it.details && it.details.length > 0 && it.boxBillNo == this.dqXH) {
it.details.forEach((k) => {
this.xjNum = this.xjNum + parseInt(k.qty ? k.qty : 0);
});
}
});
},
// 区分不同的扫描数据、输入数据做处理显示 box
setSMstr(str) {
let lth = str.length - this.dqboxNO.length;
if (lth > 1) {
// 扫描的值
this.xhNo = str.substring(this.dqboxNO.length);
} else {
this.dqboxNO = str;
this.xhNo = str;
}
},
// 区分不同的扫描数据、输入数据做处理显示 xlh
setSMxlhstr(str) {
console.log('扫描的的值', str, this.xlhVal, this.dqboxXlh);
let lth = str.length - this.dqboxXlh.length;
if (lth > 1) {
// 扫描的值
this.xlhVal = str.substring(this.dqboxXlh.length);
console.log('处理扫描的的值', str, this.xlhVal, this.dqboxXlh);
} else {
this.dqboxXlh = str;
this.xlhVal = str;
}
},
// 输入确认
inputConfirm(val, type) {
if (val) {
if (this.focusTag == 'box') {
this.setSMstr(val.target.value);
this.getboxinfo();
}
if (this.focusTag == 'xlh') {
this.setSMxlhstr(val.target.value);
this.getXlhInfo();
}
}
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = '';
setTimeout(() => {
this.xhNo = '';
this.dqboxNO = '';
this.focusInput = 'box';
this.xlhVal = '';
this.dqboxXlh = '';
this.xjNum = '';
}, 200);
},
// 根据箱号获取箱信息
getboxinfo() {
if (!this.xhNo) {
this.setSMinputbox();
uni.showToast({
title: '请扫描或输入箱号',
icon: 'none',
duration: 1000
});
return;
}
if (this.boxstrList.includes(this.xhNo)) {
this.setSMinputbox();
uni.showToast({
title: '该箱号已扫描',
icon: 'none',
duration: 1000
});
return;
}
this.focusInput = '';
this.$api
.get('/SysConfig/GetBoxSynthesis', {
boxBillNo: this.xhNo
})
.then((res) => {
if (res.status == 200) {
// 如果查询的箱号正常返回数据,就缓存改箱号信息
if (res.data) {
if (!res.data.stock) {
this.setSMinputbox();
uni.showToast({
title: '该箱号未上架',
icon: 'none',
duration: 1000
});
return;
}
// 缓存当前箱的物料信息
res.data.details.forEach((it) => {
it.boxId = res.data.id;
});
this.dqBoxInfo = JSON.parse(JSON.stringify(res.data));
if (res.data.details) {
res.data.details = res.data.details.filter((detail) => detail.qty > 0);
}
res.data.details.forEach((it) => {
it.wuToatal = JSON.parse(JSON.stringify(it.qty));
it.itxlhlist = [];
it.stockCode = res.data.stockCode;
it.subStockCode = res.data.subStockCode;
it.boxId = it.boxId;
it.remark = '';
});
this.dataList = [res.data].concat(this.dataList);
// 上架数量 当前扫箱的数量
this.xjNum = res.data.totalQty;
// 计算已上架总数量
this.yxjTotalNum = this.$util.sumNestedObjectValues(this.dataList, 'details', 'qty');
// 仓库
this.warehouseCode = res.data.stockCode;
this.warehouseName = res.data.stock;
this.cwcode = res.data.subStockCode;
this.erpOrgCode = res.data.orgCode;
//清空当前框数据 自动聚焦箱号
this.focusInput = 'box';
this.dqboxNO = res.data.boxBillNo;
this.xhNo = res.data.boxBillNo;
// 回车当前箱号
this.dqXH = res.data.boxBillNo;
// 缓存箱号
this.boxstrList.push(this.xhNo);
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
});
}
} else {
this.setSMinputbox();
}
});
},
// 扫描框数据重置,光标聚焦
setSMinputxlh() {
this.focusInput = '';
setTimeout(() => {
this.xlhVal = '';
this.dqboxXlh = '';
this.focusInput = 'xlh';
this.xjNum = null;
}, 200);
},
// 根据序列号获取箱信息
getXlhInfo() {
if (!this.xlhVal) {
this.setSMinputxlh();
uni.showToast({
title: '该扫描或输入序列号',
icon: 'none',
duration: 1000
});
return;
}
if (this.xlhstrList.includes(this.xlhVal) || this.twoData.includes(this.xlhVal)) {
this.setSMinputxlh();
uni.showToast({
title: '该序列号已扫描',
icon: 'none',
duration: 1000
});
return;
}
this.focusInput = '';
//根据序列号或规格型号搜索物料信息
this.$api
.get('/SysConfig/GetMaterial', {
serialNumber: this.xlhVal,
IsOps: true,
serialStatus: 3
})
.then((res) => {
if (res.status == 200) {
if (!res.data.serialNumber) {
this.setSMinputxlh();
uni.showToast({
title: '扫描的不是序列号',
icon: 'none',
duration: 1000
});
return;
}
if (!res.data.isBoxInventory) {
this.setSMinputxlh();
uni.showToast({
title: '序列号未上架入库',
icon: 'none',
duration: 1000
});
return;
}
if (res.data.isOldOps && res.data.boxId !== 0 && res.data.boxId !== this.dqBoxInfo.id) {
this.setSMinputxlh();
uni.showToast({
title: '该序列号不存在所扫箱内',
icon: 'none',
duration: 1000
});
return;
}
// 提取列表的物料id
let materialCodelist = [];
materialCodelist = this.dqBoxInfo.details.flatMap((obj) => obj.serialNumbers);
let czoldxlhtag = this.dqBoxInfo.details.findIndex((it) => it.materialNumber == res.data.materialNumber);
if (czoldxlhtag == -1 && res.data.isOldOps) {
this.setSMinputxlh();
uni.showToast({
title: '该序列号对应物料无箱库存',
icon: 'none',
duration: 1000
});
return;
}
// 判断当前扫描的序列号是否存在当前箱,不存在就提示
if (materialCodelist.includes(res.data.serialNumber) || (czoldxlhtag !== -1 && res.data.isOldOps)) {
this.xjNum = 1;
// 找到这条物料对应的明细的规格物料上架数量加一,切不可在编辑
let indexobj = null;
indexobj = this.$util.findMaterialCodePosition(this.dataList, res.data.materialNumber);
if (indexobj || indexobj == 0) {
// 如果是第一次扫,就清空上架数量,切锁住输入框不能在输入
if (this.dataList[indexobj.objectIndex].details[indexobj.detailIndex].itxlhlist.length == 0) {
this.dataList[indexobj.objectIndex].details[indexobj.detailIndex].qty = 0;
}
++this.dataList[indexobj.objectIndex].details[indexobj.detailIndex].qty;
this.dataList[indexobj.objectIndex].details[indexobj.detailIndex].itxlhlist.push(res.data.serialNumber);
}
// 计算已上架总数量
this.yxjTotalNum = this.$util.sumNestedObjectValues(this.dataList, 'details', 'qty');
// 设置光标和输入框的值
this.focusInput = 'xlh';
this.dqboxXlh = res.data.serialNumber;
this.xlhVal = res.data.serialNumber;
// 缓存序列号
this.xlhstrList.push(res.data.serialNumber);
//缓存2件装序列号
if(res.data.isTwo==2) {
this.twoData.push(res.data.twoSerialNumber)
}
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
});
} else {
this.setSMinputxlh();
uni.showToast({
title: '该序列号不存在所扫箱内',
icon: 'none',
duration: 1000
});
}
} else {
this.setSMinputxlh();
}
});
},
goback() {
uni.navigateTo({
url: '/pages/otherUnderwear/index'
});
}
}
};
</script>
<style lang="scss">
@import '@/static/public.scss';
.mianheade2 {
.pagetitle {
margin-left: 26%;
}
}
</style>

View File

@@ -0,0 +1,90 @@
<!--入库 -->
<template>
<view class="rkpage">
<!-- 标题栏 -->
<view class="mianheade" @click="goback()">
<image src="../../static/img/n_back.png" class="blacBackico"></image>
<text class="pagetitle">其他库内操作</text>
</view>
<view class="rkMuen">
<view class="item it50" @click="otherPage(1)">
<image src="../../static/img/qtrk_m1.png" class="rkico"></image>
<text class="t1" >快速改箱/装箱</text>
</view>
</view>
<view class="rkMuen">
<view class="item it50" @click="otherPage(2)">
<image src="../../static/img/qtrk_m3.png" class="rkico"></image>
<text class="t1" > 整箱移货下架</text>
</view>
<view class="item it50" @click="otherPage(3)">
<image src="../../static/img/qtrk_m2.png" class="rkico"></image>
<text class="t1">整箱移货上架</text>
</view>
</view>
<view class="rkMuen">
<view class="item it50" @click="otherPage(4)">
<image src="../../static/img/qtrk_m4.png" class="rkico"></image>
<text class="t1">出库回退上架</text>
</view>
<view class="item it50" @click="otherPage(5)">
<image src="../../static/img/qtrk_m5.png" class="rkico"></image>
<text class="t1">入库回退下架</text>
</view>
</view>
<view class="rkMuen">
<view class="item it50" @click="otherPage(6)">
<image src="../../static/img/outbound.png" class="rkico"></image>
<text class="t1">库存查询</text>
</view>
<view class="item it50" @click="otherPage(7)">
<image src="../../static/img/inventory.png" class="rkico"></image>
<text class="t1">出库箱信息</text>
</view>
</view>
</view>
</template>
<script>
//跳转路径集合
const TO_URLS = {
1:"/pages/otherUnderwear/fastSetbox",// 快速改箱/装箱
2:"/pages/otherUnderwear/moveBoxDown",// 整箱移货下架
3:"/pages/otherUnderwear/moveBoxup",// 整箱移货上架
4:"/pages/otherUnderwear/outStockUp",// 出库回退上架
5:"/pages/otherUnderwear/inStockDown",// 出库回退下架
6:"/pages/otherUnderwear/outbound",// 库存查询
7:"/pages/otherUnderwear/inventory"// 出库箱信息
}
export default {
data(){
return {
}
},
onBackPress(e) {
this.$util.appgoBack(e,'index')
return true
},
methods: {
goback() {
uni.navigateTo({
url: "/pages/index"
})
},
otherPage(type) {
uni.navigateTo({
url: TO_URLS[type]
})
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
.pagetitle{
margin-left: 28% !important;
}
</style>

View File

@@ -0,0 +1,401 @@
<!-- 出库箱查询 -->
<template>
<view class="shpage gx_zxpage">
<z-paging ref="paging" v-model="dataList" @query="queryList">
<template #top>
<!-- 标题 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">出库箱信息</text>
</view>
<!-- 仓库&出库箱信息 -->
<view class="sh_gdInfo">
<view class="item" :class="{ itembg2: outboundOrderNumber }" :style="{ 'pointer-events': outboundOrderNumber ? 'none' : '' }">
<view class="it">
<text class="t1">
<text class="redtag">*</text>
仓库:
</text>
<w-select
class="wwselectit"
v-model.trim="warehouseName"
defaultValue="请选择"
:list="warehouseList"
valueName="name"
keyName="name"
@change="handleWareHouseChange"
@focus="inputfocus($event, 'ck')"
ref="wselectck"
></w-select>
</view>
</view>
<!-- 出库单号 -->
<view class="item" :class="{ itembg2: !warehouseName }" :style="{ 'pointer-events': !warehouseName ? 'none' : '' }">
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
出库单号:
</text>
<w-select
style="margin-left: 20rpx; flex: 1"
v-model.trim="outboundOrderNumber"
defaultValue="模糊搜索"
:list="outboundOrderList"
valueName="billNo"
keyName="billNo"
@change="handleOutboundOrderChange"
:showClose="true"
:focus="focusInput == 'outboundOrderNumber'"
@focus="focusInput = 'outboundOrderNumber'"
:filterable="filterable"
:pagingSet="isPagingSet"
:wselectTotal="total"
@onBottomPage="onBottomPage"
:pageNo="pageNo"
:loadingFlag="loadingFlag"
@clearnFn="clearnFn"
selectTag="ckfsWselect"
></w-select>
</view>
</view>
</view>
<!-- 分割 -->
<view :style="{height:navHeight+formHeight+30+'rpx'}"></view>
<view class="th-box" >
<view class="th-item" style="" >
<view class="th br" style="width: 80rpx;">序号</view>
<view class="th br" style="width: 250rpx;">箱号</view>
<view class="th " style="width: 330rpx;">规格型号</view>
<!-- <view class="th" style="width: 140rpx;">出库数量</view> -->
</view>
</view>
</template>
<!-- border-bttom-radius: 12rpx; -->
<view :class="dataList.length ? 'td-box1' :'td-box'">
<view class="td-item" style="" v-for="(item,index) in dataList" :key="index" >
<view class="td br wd" style="width: 80rpx;">{{item.indexNumber}}</view>
<view class="td br wd" style="width: 250rpx;">{{item.boxBillNo}}</view>
<view class="td wd" style="width: 330rpx;">{{item.specifications}}({{item.qty}})</view>
<!-- <view class="td wd" style="width: 140rpx;">{{item.qty}}</view> -->
</view>
</view>
</z-paging>
</view>
</template>
<script>
export default {
data() {
return {
navHeight:0,
formHeight:0,
dataList:[],
focusInput: '', //自动聚焦
outboundOrderList:[],//出库单号列表
outboundOrderNumber:'',//出库单号
isPagingSet: true, // 是否开启出库单下拉分页
warehouseName: '', // 选择后的仓库名称
warehouseCode: '', // 选择后的仓库编码
warehouseList:[],//仓库列表数据
loadingFlag: 0, //分頁提示
pageNo: 1,//分页
filterable: true,
total:0,//出库单号列表数量
timer:null,
timer1:null,
};
},
onReady() {
this.getElHeight(".sh_gdInfo",1)
this.getElHeight(".mianheade",2)
},
onLoad() {
this.getStock();
},
onBackPress(e) {
//物理设备返回按钮,otherUnderwearIndex是返回当前/otherUnderwear/index下
this.$util.appgoBack(e, 'otherUnderwearIndex');
return true;
},
watch: {
outboundOrderNumber(n) {
if(!n) {
this.tableReload()
return
}
this.pageNo = 1;
this.outboundOrderList=[]
this.getOutboundOrderData(n)
},
},
methods: {
//获取元素高度
getElHeight(el,type){
this.$nextTick(()=>{
uni.createSelectorQuery().select(el).boundingClientRect((data) => {
if(type===1) {
/* #ifdef H5 */
this.navHeight = data.height
/*#endif*/
/*#ifdef APP-PLUS*/
this.navHeight = data.height+14
/*#endif*/
}else if(type===2) {
/* #ifdef H5 */
this.formHeight = data.height
/*#endif*/
/*#ifdef APP-PLUS*/
this.formHeight = data.height+14
/*#endif*/
}
}).exec();
})
},
//根据出库单号获取对应的下拉数据
getOutboundOrderData(val) {
// this.outboundOrderList=[]
clearTimeout(this.timer);
this.isPagingSet = false;
if (this.outboundOrderList.length >= this.total && this.pageNo >= 2) {
this.loadingFlag = 2;
return;
}
this.timer = setTimeout(() => {
this.$api
.post('/OutStockTask/GetOutStockTaskNosByNoBox', {
billNo: val,
pageSize: 10,
pageNo: this.pageNo,
stockCode: this.warehouseCode
})
.then((res) => {
if (res.status == 200) {
this.total = res.totalCount;
let newarr = res.data.map((item) => {
return {
billNo: item
};
});
// this.outboundOrderList.concat(newarr);
this.outboundOrderList = [...this.outboundOrderList,...newarr]
this.isPagingSet = true;
this.loadingFlag = 1;
} else {
this.isPagingSet = true;
this.total = res.totalCount;
console.log('走到了这里吗')
this.outboundOrderList=[]
}
}).catch(err=>{
this.outboundOrderList=[]
})
}, 1000);
},
//仓库
handleWareHouseChange(e) {
this.warehouseName = e.name;
this.warehouseCode = e.code+`_$${e.erpOrgCode}`;
this.outboundOrderList=[]
// this.$refs.paging.complete([]);
this.tableReload()
this.getOutboundOrderData(this.outboundOrderNumber);
this.focusInput=""
//选择仓库后获取该仓库的出库单号
setTimeout(()=>{
this.focusInput="outboundOrderNumber"
},300)
},
//出库单号改变
handleOutboundOrderChange(e){
console.log(this.outboundOrderNumber,'=outboundOrderNumber=')
this.queryList(1,10)
},
//表格刷新
tableReload() {
this.$refs.paging.reload().catch(() => {});
},
//清空出库单号值
clearnFn(val) {
this.outboundOrderNumber=''
this.outboundOrderList=[]
// this.$refs.paging.complete([]);
this.tableReload()
this.focusInput=""
//选择仓库后获取该仓库的出库单号
setTimeout(()=>{
this.focusInput="outboundOrderNumber"
},300)
this.getOutboundOrderData(this.outboundOrderNumber);
},
// 出库订单号查询分页
onBottomPage(val) {
this.pageNo = val;
this.loadingFlag = 1;
this.getOutboundOrderData(this.outboundOrderNumber);
},
//获取仓库数据
getStock() {
this.$api.get('/SysConfig/GetUcStock').then((res) => {
if (res.status == 200) {
this.warehouseList = res.data;
}
});
},
//请求时非200情况下z-paging组件设置和本地数据重置
setRefsPagingComplete() {
this.$refs.paging.complete(false);
this.outboundOrderNumber=""
this.focusInput="outboundOrderNumber"
},
//获取单号下的数据
queryList(pageNo, pageSize) {
if(!this.outboundOrderNumber) {
return
}
clearTimeout(this.timer1);
const params = {
pageNo:pageNo || 1,
pageSize: 10,
billNo:this.outboundOrderNumber,
};
this.timer1 = setTimeout(() => {
this.$api
.post(`/OutStockTask/GetInfoByNo`,params)
.then((res) => {
if (res.status == 200) {
this.$refs.paging.complete(res.data.details);
} else {
this.$refs.paging.complete(false);
this.setRefsPagingComplete()
}
}).catch(res=>{
this.setRefsPagingComplete()
})
},1000)
},
//回退
goback() {
uni.navigateTo({
url: '/pages/otherUnderwear/index'
});
},
}
};
</script>
<style lang="scss">
@import "@/static/public.scss";
.mianheade2 {
.pagetitle {
margin-left: 30%;
}
}
.item1 {
position: relative;
height: 150rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0rpx 30rpx;
}
.item1-detail {
padding: 5rpx 15rpx;
border-radius: 10rpx;
font-size: 28rpx;
color: white;
background-color: #007AFF;
}
.item1-line {
position: absolute;
bottom: 0rpx;
left: 0rpx;
height: 1px;
width: 100%;
background-color: #eeeeee;
}
.table--border {
// border:1rpx solid red
}
.th {
color: #505050;
// border-right: 1rpx solid #E3E5E8;
background-color:#F0F2F5;
display: flex;
align-items: center;
justify-content: center;
padding: 10rpx;
font-weight: 900;
height: 44rpx;
}
.th-box {
margin: 0 24rpx;
padding:20rpx 20rpx 0 20rpx;
background-color: #fff;
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
}
.th-item {
box-sizing: border-box;
display:flex;
font-size:13px;
border: 1rpx solid #E3E5E8;
border-top: 1rpx solid #E3E5E8;
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
}
.td-box {
margin: 0 24rpx;
padding:0 20rpx 20rpx 20rpx;
background-color: #fff;
// border-bottom-left-radius: 12rpx;
// border-bottom-right-radius: 12rpx;
}
.td-box1 {
margin: 0 24rpx;
padding:0 20rpx 20rpx 20rpx;
background-color: #fff;
border-bottom-left-radius: 12rpx;
border-bottom-right-radius: 12rpx;
}
.td-item {
box-sizing: border-box;
display:flex;
font-size:13px;
border: 1rpx solid #E3E5E8;
border-top:none;
border-bottom-left-radius: 12rpx;
border-bottom-right-radius: 12rpx;
}
.td {
display: flex;
align-items: center;
justify-content:center;
text-align: center;
min-height: 140rpx;
background-color: #fff;
padding: 10rpx;
// border-right: 1rpx solid #E3E5E8;
// border-left: 1rpx solid #E3E5E8;
}
.br {
border-right: 1rpx solid #E3E5E8;
}
.wd {
word-wrap: break-word;
white-space:normal ;
word-break: break-all;
}
</style>

View File

@@ -0,0 +1,331 @@
<!-- 整箱移货下架 -->
<template>
<view class="shpage zxyhsjpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">整箱移货下架</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item itembg2">
<view class="it">
<text class="t1">仓库: </text>
<text class="t2">{{warehouseName}}</text>
</view>
</view>
<view class="item">
<view class="it itsp">
<text class="t1"><text class="redtag">*</text>箱号: </text>
<input v-model="boxNo" class="inpt1" type="text" @focus="inputfocus($event,'box')"
@blur="inputblur($event,'')" @confirm="inputConfirm($event,'box')"
:focus="focusInput == 'box'" />
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item itembg2">
<view class="it">
<text class="t1">仓位: </text>
<text class="t2">{{cwName}}</text>
</view>
</view>
<view class="item item2">
<view class="it2 it50">
<text class="t1">{{boxstrList.length}}</text>
<text class="t2">已扫描箱数</text>
</view>
<view class="it2 it50">
<text class="t1 rednum">{{totalNum}}</text>
<text class="t2">总数量</text>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb cgsjrklb jscklb" :style="{'margin-top':heights.top+'px','height':heights.body+'px'}">
<view class="item" v-for="(item,index) in dataList" :key="index">
<view class="it">
<!-- 箱号 -->
<text class="txt titstr">{{item.boxBillNo}}</text>
<view v-for="(cit,index) in item.details" class="ibgt" :key="index+'a'">
<text class="txt">{{cit.specifications}}</text>
<view class="txt txtflexnum">
<text class="txt">{{cit.materialNumber}}</text>
<text class="txt"> {{cit.qty}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空下架数量</view>
<view class="bt bt2" @click="wcNxetFn">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content='qktkContent' @confirm="qktkconfirm"
:showCancelButton='true' @cancel="qktkshow = false" @></u-modal>
</view>
</template>
<script>
export default {
data() {
return {
heights: {
top: 0,
body: 0,
},
focusInput: 'box', // 自动聚焦
warehouseName: '', // 仓库名称 根据箱号带出来的会实时更新
boxNo: '', // 箱号的值
cwIds: [], // 仓位id集合
boxstrList: [], // 缓存的箱号信息(多个)
cwName: '', // 仓位名
totalNum: 0, // 总数量
dataList: [], // 列表明细数据
focusTag: '', // 判断聚焦
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空下架数量?',
qktkContent: "清空后页面数据将不保存",
tjdata: [], // 页面提交数据
dqboxNO: '', //用来是否保存当前输入箱号的值
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
scanTracker: {
lastScanTime: 0,
lastScanCode: null
}, // 源头处理扫码段时间内重复扫
}
},
watch: {
boxNo(n) {
if (!n) {
this.dqboxNO = ''
}
},
chooseValue(n, o) {}
},
onReady() {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts')
},
onLoad() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode)
this.$broadcastScan.start();
this.stopScanCode()
this.startScanCode()
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode()
},
onShow() {
this.$broadcastScan.start();
this.startScanCode()
},
onBackPress(e) {
this.$util.appgoBack(e,'otherUnderwearIndex')
return true
},
methods: {
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if ((res.code === this.scanTracker.lastScanCode) && (timeSinceLastScan < 4000)) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code)
}
})
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan')
},
// 完成完成/下一单
wcNxetFn() {
if (this.boxstrList.length == 0) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1000
})
return
}
// 节流
if (this.requestStatus) {
return false;
}
this.requestStatus = true
this.$api.post('/MoveBoxRecord/Down_Save', this.tjdata).then(res => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1000
})
setTimeout(() => {
uni.navigateTo({
url: '/pages/otherUnderwear/moveBoxDown'
})
}, 200);
// this.$router.go(0)
}
})
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
// 清空二次确认
qktkconfirm() {
this.warehouseName = ''
this.cwName = ''
this.boxNo = ''
this.boxstrList = []
this.dataList = []
this.tjdata = []
this.totalNum = 0
this.cwId = ''
this.qktkshow = false
},
// 区分不同的扫描数据、输入数据做处理显示 box
setSMstr(str) {
let lth = str.length - this.dqboxNO.length
console.log('区分不同的扫描数据、输入数据做处理显示 box', str, this.dqboxNO, lth, str.substring(this.dqboxNO.length))
if (lth > 1) {
// 扫描的值
this.boxNo = str.substring(this.dqboxNO.length)
} else {
this.dqboxNO = str
this.boxNo = str
}
},
// 输入确认
inputConfirm(val, type) {
if (val) {
if (this.focusTag == 'box') {
this.setSMstr(val.target.value)
this.getboxinfo()
}
}
},
// 輸入失去焦點
inputblur(val, type) {
this.focusTag = type
// console.log('輸入失去焦點', val, type)
},
// 输入聚焦
inputfocus(val, type) {
this.focusTag = type
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == "normalAnroid") {
this.$util.doScanQrCode().then(res => {
this.focusInput = type
this.focusTag = type
this.getScancode(res.result)
})
}
},
// 获取扫描的值
getScancode(code) {
if (this.focusTag == 'box') {
// 有些PDA会自带换行符trim函数处理下
this.boxNo = ''
this.boxNo = code.trim()
this.getboxinfo()
}
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = ''
setTimeout(() => {
this.boxNo = ''
this.focusInput = 'box'
this.dqboxNO = ''
}, 200)
},
// 根据箱号获取信息
getboxinfo() {
if (!this.boxNo) {
this.setSMinputbox()
uni.showToast({
title: '请扫描需要上架的箱号',
icon: 'none',
duration: 1000
})
return
}
if (this.boxstrList.includes(this.boxNo)) {
this.setSMinputbox()
uni.showToast({
title: '该箱号已扫描',
icon: 'none',
duration: 1000
})
return
}
this.focusInput = ''
this.$api.get('/Inventory/GetBoxInventoryDetails/' + this.boxNo).then(res => {
if (res.status == 200) {
let thetotalQty = res.data.totalQty ? res.data.totalQty : 0
let newDetails = [];
for (let i = 0; i < res.data.details.length; i++) {
if (res.data.details[i].qty !== 0) {
newDetails.push(res.data.details[i]);
}
}
res.data.details = newDetails
// 页面提交数据
this.tjdata.push({
boxId: res.data.boxId,
subStockCode: res.data.subStockCode,
qty: thetotalQty,
details: res.data.details
})
this.cwName = res.data.subStock
this.warehouseName = res.data.stock
this.dataList.push(res.data)
// 缓存当前箱
this.boxstrList.push(res.data.boxBillNo)
//扫描当前箱
this.boxNo = res.data.boxBillNo
this.dqboxNO = res.data.boxBillNo
// 总数量
this.totalNum = this.totalNum + thetotalQty
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
})
}
//清空当前框数据 自动聚焦箱号
this.setSMinputbox()
})
},
goback() {
uni.navigateTo({
url: "/pages/otherUnderwear/index"
})
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
.mianheade2 {
.pagetitle {
margin-left: 30%;
}
}
</style>

View File

@@ -0,0 +1,390 @@
<!-- 整箱移货上架 -->
<template>
<view class="shpage zxyhsjpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">整箱移货上架</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item itembg2">
<view class="it">
<text class="t1"><text class="redtag">*</text>仓库: </text>
<text class="t2">{{warehouseName}}</text>
</view>
</view>
<view class="item" :class="{'itembg2':boxstrList&&boxstrList.length>0}"
:style="{'pointer-events':boxstrList&&boxstrList.length>0?'none':''}">
<view class="it itsp">
<text class="t1"><text class="redtag">*</text>目标仓位号: </text>
<w-select class="wwselectit" v-model='cwNum' defaultValue="模糊搜索" :list='cwselectList'
valueName='name' keyName="name" @change='cwchange' :filterable='filterable' ref="wselect1"
@focus="inputfocus($event,'cw')" :focus="focusInput=='cw'" :showClose='true'>
</w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('cw')"></image>
</view>
</view>
<view class="item" :class="{'itembg2':!cwcode}" :style="{'pointer-events':!cwcode?'none':''}">
<view class="it itsp">
<text class="t1"><text class="redtag">*</text>箱号: </text>
<input v-model="boxNo" class="inpt1" type="text" @focus="inputfocus($event,'box')"
@blur="inputblur($event,'')" @confirm="inputConfirm($event,'box')"
:focus="focusInput == 'box'" />
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item item2">
<view class="it2 it50">
<text class="t1">{{boxstrList.length}}</text>
<text class="t2">已扫描箱数</text>
</view>
<view class="it2 it50">
<text class="t1 rednum">{{totalNum}}</text>
<text class="t2">总数量</text>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb cgsjrklb jscklb" :style="{'margin-top':heights.top+'px','height':heights.body+'px'}">
<view class="item" v-for="(item,index) in dataList" :key="index">
<view class="it">
<!-- 箱号 -->
<text class="txt titstr">{{item.boxBillNo}}</text>
<view v-for="(cit,index) in item.details" class="ibgt" :key="cit.specifications">
<text class="txt">{{cit.specifications}}</text>
<view class="txt txtflexnum">
<text class="txt">{{cit.materialNumber}}</text>
<text class="txt"> {{cit.qty}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空上架数量</view>
<view class="bt bt2" @click="wcNxetFn">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content='qktkContent' @confirm="qktkconfirm"
:showCancelButton='true' @cancel="qktkshow = false"></u-modal>
</view>
</template>
<script>
export default {
data() {
return {
heights: {
top: 0,
body: 0,
},
focusInput: 'cw', // 自动聚焦
filterable: true, //下拉模糊搜索是否开启
warehouseName: '', // 仓库名称 根据箱号带出来的会实时更新
warehouseCode: '', // 仓库编码
cwNum: '', // 仓位值
cwselectList: [], //仓位下拉集合
cwcode: '', // 仓位code
boxNo: '', //箱号值
boxstrList: [], // 缓存的箱号信息(多个)
totalNum: 0, // 总数量
dataList: [], // 明细数据
focusTag: '', // 判断聚焦
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空上架数量?',
qktkContent: "清空后页面数据将不保存",
tjdata: [], // 页面提交数据
dqboxNO: '', //用来是否保存当前输入箱号的值
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
scanTracker: {
lastScanTime: 0,
lastScanCode: null
}, // 源头处理扫码段时间内重复扫
}
},
watch: {
boxNo(n) {
if (!n) {
this.dqboxNO = ''
}
},
// 仓位下拉数据
cwNum(n, o) {
if(!n){
this.cwselectList =[]
this.cwcode = null
this.warehouseCode = null
this.warehouseName = null
this.orgCode = null
} else {
this.getcwList(n)
}
}
},
onReady() {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts')
},
onLoad() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode)
this.$broadcastScan.start();
this.stopScanCode()
this.startScanCode()
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode()
},
onShow() {
this.$broadcastScan.start();
this.startScanCode()
},
onBackPress(e) {
this.$util.appgoBack(e,'otherUnderwearIndex')
return true
},
methods: {
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if ((res.code === this.scanTracker.lastScanCode) && (timeSinceLastScan < 4000)) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code)
}
})
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan')
},
// 完成完成/下一单
wcNxetFn() {
if (!this.cwcode || this.boxstrList.length == 0) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1500
})
return
}
// 节流
if (this.requestStatus) {
return false;
}
this.requestStatus = true
this.$api.post('/MoveBoxRecord/Up_Save', this.tjdata).then(res => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1500
})
setTimeout(() => {
uni.navigateTo({
url: '/pages/otherUnderwear/moveBoxup'
})
}, 200);
// this.$router.go(0)
}
})
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
// 清空二次确认
qktkconfirm() {
this.boxNo = ''
this.boxstrList = []
this.dataList = []
this.tjdata = []
this.totalNum = 0
this.qktkshow = false
this.focusInput =''
setTimeout(() =>{
if(!this.cwcode){
this.focusInput ='cw'
} else {
this.focusInput = 'box'
}
}, 200)
},
// 区分不同的扫描数据、输入数据做处理显示 box
setSMstr(str) {
let lth = str.length - this.dqboxNO.length
if (lth > 1) {
// 扫描的值
this.boxNo = str.substring(this.dqboxNO.length)
} else {
this.dqboxNO = str
this.boxNo = str
}
},
// 输入确认
inputConfirm(val, type) {
if (val) {
if (this.focusTag == 'box') {
this.setSMstr(val.target.value)
this.getboxinfo()
}
}
},
// 輸入失去焦點
inputblur(val, type) {},
// 输入聚焦
inputfocus(val, type) {
this.focusTag = type
if (type == 'cw') {
this.focusInput = 'cw'
}
},
// 获取仓位下拉数据
getcwList(val) {
if (!val) return
this.$api.get('/SysConfig/GetSubUcStockByName', {
name: val
}).then(res => {
if (res.status == 200) {
this.cwselectList = res.data
if (this.cwselectList && this.cwselectList.length == 1) {
this.cwNum = this.cwselectList[0].name
this.cwchange(this.cwselectList[0])
this.$refs.wselect1.optionsShow = false
this.$refs.wselect1.isShow = false
}
}
})
},
// 仓位下拉选择
cwchange(e) {
this.cwcode = e.code
this.stockId = e.stockId
this.warehouseCode = e.stockCode
this.warehouseName = e.stockName
this.focusInput = 'box'
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == "normalAnroid") {
this.$util.doScanQrCode().then(res => {
this.focusInput = type
this.focusTag = type
this.getScancode(res.result)
})
}
},
// 获取扫描的值
getScancode(code) {
if (this.focusTag == 'box') {
// 有些PDA会自带换行符trim函数处理下
this.boxNo = ''
this.boxNo = code.trim()
this.getboxinfo()
}
// 序列号
if (this.focusTag == 'cw') {
this.cwNum = ''
this.cwNum = code.trim()
this.$refs.wselect1.inputData = code.trim()
this.getcwList()
//根据序列号去更新对应的明细规格型号的上架数量的值 扫描一个数量加一,重复扫描要提示
}
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = ''
setTimeout(() => {
this.boxNo = ''
this.focusInput = 'box'
this.dqboxNO = ''
}, 200)
},
// 根据箱号获取信息
getboxinfo() {
if (!this.boxNo) {
this.setSMinputbox()
uni.showToast({
title: '请扫描需要上架的箱号',
icon: 'none',
duration: 1000
})
return
}
if (this.boxstrList.includes(this.boxNo)) {
this.setSMinputbox()
uni.showToast({
title: '该箱号已扫描',
icon: 'none',
duration: 1000
})
return
}
this.focusInput = ''
this.$api.get('/SysConfig/GetBox_MoveBoxRecord', {
boxBillNo: this.boxNo,
}).then(res => {
if (res.status == 200) {
if (res.data.subStockCode) {
this.setSMinputbox()
uni.showToast({
title: '箱号已上架入库',
icon: 'none',
duration: 1500
})
return
}
// 页面提交数据
let thetotalQty = 0
thetotalQty = this.$util.sumObjectArrayValues(res.data.details, 'qty')
this.tjdata.push({
boxId: res.data.id,
subStockCode: this.cwcode,
qty: thetotalQty,
details: res.data.details
})
this.dataList.push(res.data)
// 总数量
this.totalNum = this.totalNum + thetotalQty
// 缓存箱号
this.boxstrList.push(res.data.boxBillNo)
// 扫描当前
this.dqboxNO = res.data.boxBillNo
this.boxNo = res.data.boxBillNo
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
})
}
//清空当前框数据 自动聚焦箱号
this.setSMinputbox()
})
},
goback() {
uni.navigateTo({
url: "/pages/otherUnderwear/index"
})
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
.mianheade2 {
.pagetitle {
margin-left: 30%;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,561 @@
<!-- 库存查询 -->
<template>
<view class="shpage gx_zxpage">
<z-paging ref="paging" v-model="dataList" @query="queryList">
<template #top>
<!-- 标题 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">库存查询</text>
</view>
<!-- 仓库&出库箱信息 -->
<view class="sh_gdInfo">
<view class="item" :class="{ itembg2: inputVal }" :style="{ 'pointer-events': inputVal ? 'none' : '' }">
<view class="it">
<text class="t1">
<text class="redtag">*</text>
仓库:
</text>
<w-select
class="wwselectit"
v-model.trim="warehouseName"
defaultValue="请选择"
:list="warehouseList"
valueName="name"
keyName="name"
@change="handleWareHouseChange"
@focus="inputfocus($event, 'ck')"
ref="wselectck"
></w-select>
</view>
</view>
<!-- 無聊 -->
<view class="item" :class="{ itembg2: !warehouseName }" :style="{ 'pointer-events': !warehouseName ? 'none' : '' }">
<view class="" style="display: flex;padding: 10rpx 0; margin:0 40rpx;border-bottom: 1rpx solid #E3E5E8; box-sizing: border-box;">
<view style="border-right: 1rpx solid #E3E5E8;padding-right: 16rpx;">
<uni-data-select
v-model="selectValue"
:localdata="options"
@change="hanldeSelectChange"
:clear="false"
></uni-data-select>
</view>
<view style="display: flex; align-items: center;justify-content: center;">
<u-input :focus="focusTag==='box'" @clear="handleClear" border="bottom" :style="{width: inputWidth}" style="font-size: 14px; height:32rpx;"clearable v-model="inputVal" @confirm="handleInputConfirm()"
></u-input>
</view>
<view style="display: flex;align-items: center;"@click="scanImg('box')">
<image src="../../static/img/smico.png" class="searchico" style="margin-left:0;"></image>
</view>
</view>
</view>
</view>
<view :style="{height:navHeight+formHeight+30+'rpx'}"></view>
<view style="padding: 20rpx 16rpx 0;background-color: #fff;margin:0 24rpx;border-top-left-radius: 12rpx;border-top-right-radius: 12rpx;">
<!-- 详情 -->
<view style="font-size: 14px;padding-left:12rpx;color: #717275;">
<view v-if="selectValue===1">
<view style="padding-bottom: 10rpx;">
<text>查询物料为</text>
<text style="margin: 0 10rpx;">:</text>
<text style="color:#222222">{{specifications}}</text>
</view>
<view style="padding-bottom: 10rpx; display: flex;">
<view style="width: 140rpx;text-align-last: justify;">物料编码</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222" >{{materialNumber}}</view>
</view>
<view style="padding-bottom: 10rpx; display: flex;">
<view style="width: 140rpx;text-align-last: justify;">物料名称</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{materialName}}</view>
</view>
<view style="padding-bottom: 10rpx; display: flex;">
<view style="width: 140rpx;text-align-last: justify;">库存总数</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{totalQty}}</view>
</view>
</view>
<!-- 箱号详情 -->
<view v-if="selectValue===2">
<view style="padding-bottom: 10rpx; display: flex;">
<view>查询箱号为</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#4178D5" @click="goInventory()">{{boxBillNo}}</view>
</view>
<view style="padding-bottom: 10rpx;display: flex;">
<view style="width: 140rpx;text-align-last: justify;">所在仓位</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{subStock}}</view>
</view>
<view style="padding-bottom: 10rpx;display: flex;">
<view style="width: 140rpx;text-align-last: justify;">库存总数</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{totalQty}}</view>
</view>
</view>
<!-- 仓位详情 -->
<view v-if="selectValue===3">
<view style="padding-bottom: 10rpx;display: flex;">
<view>查询仓位为</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{subStock}}</view>
</view>
<view style="padding-bottom: 10rpx;display: flex;">
<view style="width: 140rpx;text-align-last: justify;">库存总数</view>
<view style="margin: 0 10rpx;">:</view>
<view style="color:#222222">{{totalQty}}</view>
</view>
</view>
<view style="font-weight: 900;padding-top: 10rpx;padding-bottom: 12rpx;color:#222222">
库存详情 :
</view>
</view>
<!-- 库存详情表格 -->
<!-- 物料 -->
<view class="th-item" v-if="selectValue===1" >
<view class="th br" style="width: 210rpx;">箱号</view>
<view class="th br" style="width: 360rpx;">仓位</view>
<view class="th" style="width: 80rpx;">数量</view>
</view>
<!-- 箱号 -->
<view class="th-item" v-if="selectValue===2">
<view class="th br" style="width: 570rpx;">规格型号</view>
<view class="th" style="width: 80rpx;">数量</view>
</view>
<!-- 仓位 -->
<view class="th-item" v-if="selectValue===3">
<view class="th br" style="width: 210rpx;">箱号</view>
<view class="th br" style="width: 360rpx;">规格型号</view>
<view class="th" style="width: 80rpx;">数量</view>
</view>
</view>
</template>
<!-- border-bottom-left-radius: 12rpx;border-bottom-right-radius: 12rpx; -->
<view :class="dataList.length ? 'c-box':'c-box1'">
<!-- 物料 -->
<view v-if="selectValue===1">
<view class="td-item" v-for="(item,index) in dataList" :key="index" >
<view class="td br wd" style="width: 210rpx;color:#4178D5" @click="goInventory(item)">{{item.boxBillNo}}</view>
<view class="td br wd" style="width: 360rpx;">{{item.subStock}}</view>
<view class="td wd" style="width: 80rpx;">{{item.qty}}</view>
</view>
</view>
<!-- 箱号 -->
<view v-if="selectValue===2">
<view class="td-item" v-for="(item,index) in dataList" :key="index" >
<view class="td br wd" style="width: 570rpx;">{{item.specifications}}</view>
<view class="td wd" style="width: 80rpx;">{{item.qty}}</view>
</view>
</view>
<!-- 仓位 -->
<view v-if="selectValue===3">
<view class="td-item" v-for="(item,index) in dataList" :key="index" >
<view class="td br wd" style="width: 210rpx;color:#4178D5" @click="goInventory(item)">{{item.boxBillNo}}</view>
<view class="td br wd" style="width: 360rpx;">{{item.specifications}}</view>
<view class="td wd" style="width: 80rpx;">{{item.qty}}</view>
</view>
</view>
</view>
</z-paging>
</view>
</template>
<script>
export default {
data() {
return {
navHeight:0,
formHeight:0,
options:[
{value:1,text:'物料'},
{value:2,text:'箱号'},
{value:3,text:'仓位'}
],
selectValue:1,//下拉框值
materialName:"",//物料名称
materialNumber:"",//物料编码
specifications:"",//规格型号
totalQty:"",//总数量
subStock:"",//仓位名称
boxBillNo:"CTN00051426",//箱号
dataList: [],//列表数据
focusTag: '', // 判断聚焦
warehouseName: '', // 选择后的仓库名称
warehouseCode: '', // 选择后的仓库编码
warehouseList:[],//仓库列表数据
inputVal:'',//input输入值
timer:null,
inputWidth:"470rpx",
timer1:null,
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
scanTracker: {
lastScanTime: 0,
lastScanCode: null
} // 源头处理扫码段时间内重复扫
};
},
onReady() {
this.getElHeight(".sh_gdInfo",1)
this.getElHeight(".mianheade",2)
/* #ifdef H5 */
this.inputWidth = '470rpx'
/*#endif*/
/*#ifdef APP-PLUS*/
this.inputWidth = '422rpx'
/*#endif*/
},
onLoad() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode);
this.$broadcastScan.start();
this.stopScanCode();
this.startScanCode();
this.getStock()
// this.$refs.paging.complete([]);
// this.queryList(1,10);
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode();
},
onShow() {
this.$broadcastScan.start();
this.startScanCode();
},
onBackPress(e) {
this.$util.appgoBack(e, 'otherUnderwearIndex');
return true;
},
watch: {
inputVal(n) {
if(!n) {
this.dataList=[]
//表格刷新
this.tableReload()
return
}
},
},
methods: {
//获取元素高度
getElHeight(el,type){
this.$nextTick(()=>{
uni.createSelectorQuery().select(el).boundingClientRect((data) => {
if (data) {
if(type===1) {
/* #ifdef H5 */
this.navHeight = data.height
/*#endif*/
/*#ifdef APP-PLUS*/
this.navHeight = data.height+20
/*#endif*/
}else if(type===2) {
/* #ifdef H5 */
this.formHeight = data.height
/*#endif*/
/*#ifdef APP-PLUS*/
this.formHeight = data.height+20
/*#endif*/
}
}
}).exec();
})
},
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if (res.code === this.scanTracker.lastScanCode && timeSinceLastScan < 4000) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code);
}
});
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan');
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == 'normalAnroid') {
this.$util.doScanQrCode().then((res) => {
this.focusTag = type;
this.getScancode(res.result);
});
}
},
// 获取扫描的值
getScancode(code, index, wlcode) {
// 有些PDA会自带换行符trim函数处理下
this.inputVal = '';
this.dataList=[];
this.inputVal= code.trim();
//表格刷新
this.tableReload()
this.queryList(1,10);
},
//仓库
handleWareHouseChange(e) {
//仓库名称
this.warehouseName = e.name;
//仓库code
this.warehouseCode = e.code+`_$${e.erpOrgCode}`;
this.tableReload()
this.setInputTagBox()
},
//获取仓库数据
getStock() {
this.$api.get('/SysConfig/GetUcStock').then((res) => {
if (res.status == 200) {
this.warehouseList = res.data;
}
});
},
//软键盘确认
handleInputConfirm() {
this.dataList=[];
//表格刷新
this.tableReload()
this.queryList(1,10);
},
//清空获取的值
clearValue(){
this.materialName="";//物料名称
this.materialNumber="";//物料编码
this.specifications="";//规格型号
this.totalQty="";//总数量
this.subStock="";//仓位名称
this.boxBillNo="";//箱号
this.inputVal = "";//input输入框
this.dataList =[];//表格数据
},
//表格刷新
tableReload() {
this.$refs.paging.reload().catch(() => {});
},
//下拉框改变
hanldeSelectChange(e) {
this.clearValue();
//表格刷新
this.tableReload()
this.setInputTagBox()
},
//设置input聚焦
setInputTagBox() {
this.focusTag="";
setTimeout(()=>{
this.focusTag="box";
},200)
},
//库存详情赋值
setDetailsValue(data) {
const {materialNumber,materialName,specifications,subStock,boxBillNo,totalQty} = data
console.log(totalQty,'=totalQty=')
this.totalQty = totalQty ;
this.materialNumber = materialNumber;
this.materialName = materialName;
this.specifications = specifications;
this.subStock = subStock ;
this.boxBillNo = boxBillNo;
},
//表格數據
queryList(pageNo, pageSize) {
//空值直接return
if(!this.inputVal) {
return
}
clearTimeout(this.timer1);
//根据不同的this.selectValue值匹配不同的后端接口
//说明:1为物料 2为箱号 3仓位
const url = {
1:"/Inventory/GetPagedListBoxByMaterial",
2:"/Inventory/GetPagedListBoxByBox",
3:"/Inventory/GetPagedListBoxBySubStock",
};
//根据不同的this.selectValue的值匹配不同的参数传给后端
const selectValCloneParams = {
1:'materialNumber',
2:'boxBillNo',
3:'subStock'
};
//接口基本參數
const params = {
pageNo:pageNo,
pageSize: 10,
stockCode:this.warehouseCode,//仓库编码
};
//选择后的this.selectValue值
let paramsItem = selectValCloneParams[this.selectValue]
//将选择后的selectValue和用户输入的input值添加到params中
params[paramsItem] = this.inputVal;
this.timer1 = setTimeout(() => {
this.$api
.post(url[this.selectValue],params)
.then((res) => {
if (res.status == 200) {
//如果res.data.details是一个空数组直接返回不进行赋值操作
// if(!res.data.totalCount) {
// this.$refs.paging.complete(res.data.details);
// return;
// }
this.$refs.paging.complete(res.data.details);
this.setDetailsValue(res.data)
} else {
this.$refs.paging.complete(false);
this.inputVal=""
this.setInputTagBox()
}
}).catch(res=>{
this.$refs.paging.complete(false);
this.inputVal=""
this.setInputTagBox()
})
},1000)
},
handleClear() {
this.clearValue()
this.setInputTagBox()
},
//跳转到盘点
goInventory(item) {
let boxBillNo = item && item.boxBillNo ? item.boxBillNo:this.boxBillNo
//跳转盘点時需要去掉warehouseCodeClone拼接的org老接口的warehouseCodeClone是没有进行org拼接的.
let warehouseCodeClone = JSON.stringify(this.warehouseCode)
let warehouseCode = JSON.parse(warehouseCodeClone).split("_")[0];
uni.navigateTo({
url:`/pages/Inventory/index?warehouseName=${this.warehouseName}&warehouseCode=${warehouseCode}&boxBillNo=${boxBillNo}`
})
},
//回退
goback() {
uni.navigateTo({
url: '/pages/otherUnderwear/index'
});
},
}
};
</script>
<style lang="scss">
@import "@/static/public.scss";
.mianheade2 {
.pagetitle {
margin-left: 30%;
}
}
.item1 {
position: relative;
height: 150rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0rpx 30rpx;
}
.item1-detail {
padding: 5rpx 15rpx;
border-radius: 10rpx;
font-size: 28rpx;
color: white;
background-color: #007AFF;
}
.item1-line {
position: absolute;
bottom: 0rpx;
left: 0rpx;
height: 1px;
width: 100%;
background-color: #eeeeee;
}
::v-deep .uni-select {
border:none !important;
height:24px;
width: 100rpx;
padding-right: 0;
padding-left: 3rpx;
text-align: center;
margin-left: -7rpx;
}
.th {
color: #505050;
// border-right: 1rpx solid #E3E5E8;
background-color:#F0F2F5;
display: flex;
align-items: center;
justify-content: center;
padding: 10rpx;
font-weight: 900;
height: 44rpx;
}
.th-item {
box-sizing: border-box;
display:flex;
font-size:13px;
border: 1rpx solid #E3E5E8;
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
}
.td-item {
box-sizing: border-box;
display:flex;
font-size:13px;
border: 1rpx solid #E3E5E8;
border-top:none;
}
.td {
display: flex;
align-items: center;
justify-content:center;
text-align: center;
min-height: 90rpx;
background-color: #fff;
padding: 10rpx;
}
.br {
border-right: 1rpx solid #E3E5E8;
}
.wd {
word-wrap: break-word;
white-space:normal ;
word-break: break-all;
}
.c-box {
padding:0rpx 16rpx 20rpx 16rpx;
background-color: #fff;
margin:0 24rpx;
border-bottom-left-radius: 12rpx;
border-bottom-right-radius: 12rpx;
}
.c-box1 {
padding:0rpx 16rpx 20rpx 16rpx;
background-color: #fff;
margin:0 24rpx;
}
</style>

1809
pages/outbound/index.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,724 @@
<!-- 采购上架入库 -->
<template>
<view class="shpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<!-- /生产 -->
<text class="pagetitle">采购上架入库</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item itembg2">
<view class="it">
<text class="t1">仓库:</text>
<text class="t2">{{ warehouseName }}</text>
</view>
</view>
<view
class="item"
:class="{ itembg2: xhNo || boxstrList.length > 0 || ysjxNum > 0 }"
:style="{ 'pointer-events': xhNo || boxstrList.length > 0 || ysjxNum > 0 ? 'none' : '' }"
>
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
来源单号:
</text>
<w-select
class="wwselectit"
v-model.trim="lyOrderNo"
defaultValue="请输入订单号搜索"
:list="lyselectList"
valueName="sourceBillNo"
keyName="sourceBillNo"
@change="lychange"
:filterable="filterable"
optionType="order-cg"
@onBottomPage="onBottomPage"
:pagingSet="false"
:focus="focusInput == 'lydd'"
@focus="inputfocus($event, 'lydd')"
:showClose="true"
ref="wselectlydd"
></w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('cgdd')"></image>
</view>
</view>
<view class="item itembg2">
<view class="it">
<!-- t1 -->
<text class="" style="font-size: 14px;">物料:</text>
<!-- t2 -->
<text class="" style="font-size: 14px;">
{{ krcwInfo.specifications }}
<text v-if="krcwInfo.waitSlefQty">({{ krcwInfo.waitSlefQty }})</text>
</text>
</view>
</view>
<view class="item itembg2">
<view class="it itsp" @click="openkrkTk">
<!-- t1 -->
<text class="" style="font-size: 14px;">可入仓位:</text>
<!-- t1 -->
<text class="tpleft" style="font-size: 14px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
{{ krkStrVal }}
</text>
<image src="../../static/img/ckgd.png" class="searchico icinfo"></image>
</view>
</view>
<view
class="item"
:class="{ itembg2: !lyorderId || !warehouseCode || ysjtotalNum > 0 }"
:style="{ 'pointer-events': !lyorderId || !warehouseCode || ysjtotalNum > 0 ? 'none' : '' }"
>
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
仓位号:
</text>
<w-select
class="wwselectit"
v-model.trim="cwNum"
defaultValue="模糊搜索"
:list="cwselectList"
:focus="focusInput == 'cw'"
@focus="inputfocus($event, 'cw')"
valueName="name"
keyName="name"
@change="cwchange"
:filterable="filterable"
:showClose="true"
ref="wselect1"
></w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('cw')"></image>
</view>
</view>
<view class="item" :class="{ itembg2: !subStockCode || !cwNum }" :style="{ 'pointer-events': !subStockCode || !cwNum ? 'none' : '' }">
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
箱号:
</text>
<input
v-model.trim="xhNo"
class="inpt1"
type="text"
@focus="inputfocus($event, 'box')"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'box')"
:focus="focusInput == 'box'"
/>
<image src="../../static/img/ckxx.png" class="searchico icinfo" @click="daisjboxTk"></image>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item item2">
<view class="it2 it50">
<text class="t1">{{ ysjtotalNum }}</text>
<text class="t2">已上架总数量</text>
</view>
<view class="it2 it50">
<text class="t1">{{ sjNum }}</text>
<text class="t2">当前上架数量</text>
</view>
<view class="it2 it50" @click="xhmodelOpen">
<text class="t1 rednum">{{ ysjxNum }}</text>
<text class="t2">已上架箱数</text>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb cgsjrklb" :style="{ 'margin-top': heights.top + 'px', height: heights.body + 'px' }">
<view class="item" v-for="(item, index) in datalist" :key="index">
<view class="it">
<view class="txt titstr gxzxlb">
<text>{{ item.boxBillNo }}</text>
<image src="../../static/img/deletico.png" class="deletico" @click="deletItem(item, index)"></image>
</view>
<view class="cssj_it">
<view class="tlinb">
<text class="txt">{{ item.specifications }}</text>
<view class="txt txtflexnum">
<text>{{ item.materialNumber }}</text>
<text class="txtNum">数量{{ item.boxMaterialQty }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 可入仓位弹框-->
<u-modal :show="krkshow" title="" @confirm="krkshow = false">
<view class="boxtkct1" style="max-height: 50vh; overflow-y: auto">
<view class="cwit">
<text class="t1 tb">所在仓位:</text>
<view class="cws">
<view v-for="(item, index) in krcwInfo.materialSubStocks" class="krcwname">{{ item }}</view>
</view>
</view>
<text class="t1">{{ krcwInfo.specifications }}</text>
<text class="t1">{{ krcwInfo.materialNumber }}</text>
<text class="t1">{{ krcwInfo.materialName }}</text>
<view class="cwit">
<text class="t1">可入仓位:</text>
<view class="cws">
<view v-for="(item, index) in krcwInfo.materialSubStocks" class="krcwname">{{ item }}</view>
</view>
</view>
</view>
</u-modal>
<!-- 待上架箱号-->
<u-modal :show="daixhlistshow" title="待上架箱号" @confirm="daixhlistshow = false">
<view class="boxtkct">
<view v-for="(item, index) in daiboxstrList" class="c_item">{{ item.boxBillNo }}</view>
</view>
</u-modal>
<!-- 已上架箱号-->
<u-modal :show="xhlistshow" title="已上架箱号" @confirm="xhlistshow = false">
<view class="boxtkct">
<view v-for="(item, index) in boxstrList" class="c_item">{{ item }}</view>
</view>
</u-modal>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空上架数量</view>
<view class="bt bt2" @click="completefn()">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content="qktkContent" @confirm="qktkconfirm" :showCancelButton="true" @cancel="qktkshow = false"></u-modal>
</view>
</template>
<script>
export default {
data() {
return {
krcwInfo: {
materialSubStocks: [],
materialNumber: '',
specifications: '',
materialName: '',
waitSlefQty: ''
}, // 可入仓位
krkStrVal: '', //可入库文本显示
lyselectList: [], // 来源订单列表
heights: {
top: 0,
body: 0
},
krkshow: false, // 可入库弹框
xhlistshow: false, // 箱号查看弹框
daixhlistshow: false, // 待上架箱号查看弹框
focusInput: 'lydd', // 自动聚焦
focusTag: '', // 判斷聚焦
warehouseName: '', //仓库名称
cwNum: '', // 仓位号
cwselectList: [], // 仓位下拉数据
warehouseCode: '', //仓库id
subStockCode: '', // 仓位code
xhNo: '', //箱号
boxstrList: [], // 缓存的箱号信息(多个)
daiboxstrList: [], // 待上架箱号信息(多个)
lyOrderNo: '', // 来源订单号
lyorderId: '', // 来源订单号Id
sjNum: 0, //数量(扫码箱子的数量)
filterable: true,
ysjtotalNum: 0, //已上架总数量
ysjxNum: 0, // 已上架箱数
datalist: [], //列表明细数据,箱号里面的物料信息
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空已收货数量?',
qktkContent: '清空后页面数据将不保存',
fid: '', // 来源单号
orgCode: '', // 组织编码
dqboxNO: '', //用来是否保存当前输入箱号的值
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
scanTracker: {
lastScanTime: 0,
lastScanCode: null
}, // 源头处理扫码段时间内重复扫
detailsId: '', //明细ID
customerCode: '' // 客户编码
};
},
watch: {
boxNo(n) {
if (!n) {
this.dqboxNO = '';
}
},
cwNum(n, o) {
console.log('1232321232323')
if (!n) {
this.cwselectList = [];
this.subStockCode = null;
this.orgCode = null;
} else {
this.subStockCode = null;
this.orgCode = null;
this.getcwList(n);
}
},
// 采购订单号实时输入监听
lyOrderNo(n, o) {
if (n) {
this.getlyOrderSelectData(n);
} else {
this.krkStrVal = '';
this.warehouseCode = '';
this.warehouseName = '';
this.cwNum = '';
this.$refs.wselect1.inputData = '';
this.cwselectList = [];
this.daiboxstrList = [];
this.krcwInfo = {
materialSubStocks: [],
materialNumber: '',
specifications: '',
materialName: '',
waitSlefQty: ''
};
}
}
},
onReady() {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts');
},
onLoad() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode);
this.$broadcastScan.start();
this.stopScanCode();
this.startScanCode();
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode();
},
onShow() {
this.$broadcastScan.start();
this.startScanCode();
},
onBackPress(e) {
this.$util.appgoBack(e, 'warehousIndex');
return true;
},
methods: {
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if (res.code === this.scanTracker.lastScanCode && timeSinceLastScan < 4000) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code);
}
});
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan');
},
// 查看可入库详情弹框
openkrkTk() {
if (this.krcwInfo.materialSubStocks && this.krcwInfo.materialSubStocks.length > 0) {
this.krkshow = true;
}
},
// 待上架弹框
daisjboxTk() {
if (!this.lyorderId) return;
this.$api
.post('/InStockTask/GetReceiveBox', {
taskId: this.lyorderId,
materialNumber: this.krcwInfo.materialNumber
})
.then((res) => {
if (res.status == 200) {
this.daiboxstrList = [];
this.daiboxstrList = res.data;
if (this.daiboxstrList.length > 0) {
this.daixhlistshow = true;
} else {
uni.showToast({
title: '没有待上架箱数据',
icon: 'none',
duration: 1000
});
}
}
});
},
// 获取采购订单下拉数据
getlyOrderSelectData(val) {
if (!val) return;
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.$api.get('/InStockTask/GetSourceOrder/' + val).then((res) => {
if (res.status == 200) {
this.lyselectList = [];
this.lyselectList = res.data && res.data.length>0? res.data.filter(element => element.waitSlefQty > 0):[]
console.log(this.focusInput);
if (this.lyselectList && this.lyselectList.length == 1) {
this.lyOrderNo = this.lyselectList[0].sourceBillNo;
this.$refs.wselectlydd.filterList = res.data;
this.$refs.wselectlydd.inputData = this.lyselectList[0].sourceBillNo;
this.setItemdata(this.lyselectList[0]);
this.lychange(this.lyselectList[0]);
this.$refs.wselectlydd.optionsShow = false;
this.$refs.wselectlydd.isShow = false;
} else {
this.$refs.wselectlydd.optionsShow = true;
this.$refs.wselectlydd.isShow = true;
}
if (this.focusInput !== 'lydd') {
this.$refs.wselectlydd.optionsShow = false;
this.$refs.wselectlydd.isShow = false;
}
}
});
}, 1000);
},
// 来源订单选择监听
lychange(e) {
if (!this.lyOrderNo) {
return;
}
this.setItemdata(e);
},
// 选中的来源订单号相关物料
setItemdata(e) {
this.lyorderId = e.id;
this.detailsId = e.detailsId;
this.customerCode = e.customerCode;
// 仓库名称
this.warehouseName = e.stockName;
this.warehouseCode = e.stockCode;
this.krcwInfo = {
materialSubStocks: e.materialSubStocks,
specifications: e.specifications,
materialNumber: e.materialNumber,
materialName: e.materialName,
waitSlefQty: e.waitSlefQty
};
if (e.materialSubStocks && e.materialSubStocks.length > 0) {
this.krkStrVal = '';
e.materialSubStocks.forEach((it) => {
this.krkStrVal = this.krkStrVal + it + ',';
});
}
this.focusInput = 'cw';
},
// 来源订单下拉框分页加载
onBottomPage(val) {},
// 打开查看箱号
xhmodelOpen() {
if (this.boxstrList.length > 0) {
this.xhlistshow = true;
}
},
// 完成/下一单
completefn() {
if (!this.cwNum || !this.ysjtotalNum || !this.ysjxNum || this.boxstrList.length == 0) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1000
});
return;
}
let thedetails = [];
thedetails = this.datalist.map((it) => {
return {
detailsId: this.detailsId,
customerCode: this.customerCode,
taskId: it.taskId,
boxId: it.boxId,
sourceBillNo: it.sourceBillNo,
supplierId: it.supplierId,
orgId: it.orgId,
materialNumber: it.materialNumber,
qty: it.boxMaterialQty,
serialNumbers: it.serialNumbers,
erpDetailId: it.erpDetailId
};
});
// 节流
if (this.requestStatus) {
return false;
}
this.requestStatus = true;
this.$api
.post('/InStock/Shelf', {
orgCode: this.orgCode,
stockCode: this.warehouseCode,
subStockCode: this.subStockCode,
details: thedetails
})
.then((res) => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1000
});
setTimeout(() => {
uni.navigateTo({
url: '/pages/warehous/cgPutOnsale'
});
}, 200);
// this.$router.go(0)
}
});
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
// 清空二次确认
qktkconfirm() {
this.xhNo = '';
this.sjNum = 0;
this.ysjtotalNum = 0;
this.ysjxNum = 0;
this.qktkshow = false;
this.boxs = [];
this.boxstrList = [];
this.datalist = [];
},
// 刪除明细信息
deletItem(item, index) {
// 如果删掉了当前箱子的明细数据就为0
let idxtag = this.boxstrList.indexOf(item.boxBillNo);
if (this.boxstrList[0] == item.boxBillNo) {
this.sjNum = 0;
}
if (idxtag !== -1) {
this.boxstrList.splice(idxtag, 1);
}
this.datalist.splice(index, 1);
if (this.datalist.length == 0) {
this.sjNum = 0;
}
// 从新计算箱数和上架总数量,还有是否已经完全删除的箱子
this.setNum(this.datalist);
},
// 计算缓存已上架总数量 已上架箱数 已经扫描箱号集合
setNum(list) {
// 已上架总数量 累加
let total = 0;
this.ysjtotalNum = this.$util.sumObjectArrayValues(this.datalist, 'boxMaterialQty');
// 已上架箱数 累加 (和明细挂钩)
let thexs = [];
thexs = list.map((item, index) => {
return item.boxBillNo;
});
this.ysjxNum = Array.from(new Set(thexs)).length;
// 如果查询的箱号正常返回数据,就缓存改箱号信息
this.boxstrList = thexs;
uni.setStorageSync('boxstrList', this.boxstrList);
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == 'normalAnroid') {
this.$util.doScanQrCode().then((res) => {
this.focusInput = type;
this.focusTag = type;
this.getScancode(res.result);
});
}
},
// 获取扫描的值
getScancode(code) {
if (this.focusTag == 'box') {
// 有些PDA会自带换行符trim函数处理下
this.xhNo = '';
this.xhNo = code.trim();
this.getboxinfo();
}
// 仓位
if (this.focusTag == 'cw') {
this.cwNum = '';
this.cwNum = code.trim();
this.$refs.wselect1.inputData = code.trim();
this.getcwList();
}
if (this.focusTag == 'lydd') {
// 有些PDA会自带换行符trim函数处理下
this.lyOrderNo = '';
this.lyOrderNo = code.trim();
console.log('扫描数据', code.trim());
this.getlyOrderSelectData(this.lyOrderNo);
}
},
// 获取仓位数据
getcwList(val) {
console.log('123232')
if (!val) return;
this.$api
.get('/SysConfig/GetSubUcStockByName', {
name: val,
stockCode: this.warehouseCode
})
.then((res) => {
if (res.status == 200) {
this.cwselectList = res.data;
if (this.cwselectList && this.cwselectList.length == 1) {
this.cwNum = this.cwselectList[0].name;
this.cwchange(this.cwselectList[0]);
this.$refs.wselect1.optionsShow = false;
this.$refs.wselect1.isShow = false;
}
}
});
},
// 仓位下拉选择
cwchange(e, type) {
this.subStockCode = e.code;
this.orgCode = e.erpOrgCode;
},
// 輸入失去焦點
inputblur(val, type) {
this.focusTag = type;
},
// 输入聚焦
inputfocus(val, type) {
this.focusTag = type;
if (type == 'cw') {
this.focusInput = 'cw';
}
},
// 输入确认
inputConfirm(val, type) {
if (val) {
this.setSMstr(val.target.value);
if (this.focusTag == 'box') {
// this.xhNo = val.target.value
setTimeout(() => {
this.getboxinfo();
}, 20);
}
}
},
// 区分不同的扫描数据、输入数据做处理显示
setSMstr(str) {
let lth = str.length - this.dqboxNO.length;
if (lth > 1) {
// 扫描的值
this.xhNo = str.substring(this.dqboxNO.length);
} else {
this.dqboxNO = str;
this.xhNo = str;
}
},
// 通过箱号获取对应的单据信息和列表明细信息
getboxOrderInfo(boxBillNo) {
const _this = this;
this.focusInput = '';
this.$api
.post('/InStock/GetTaskByBox', {
boxBillNo: boxBillNo,
stockCode: this.warehouseCode,
taskId: this.lyorderId,
materialNumber: this.krcwInfo.materialNumber
})
.then((res) => {
if (res.status == 200) {
this.fid = res.data.taskId;
this.lyOrderNo = res.data.sourceBillNo;
// 明细数据 (每次新扫箱子物料明细信息往前添加)
if (res.data.details && res.data.details.length > 0) {
// 当前箱子的总数
this.sjNum = this.$util.sumObjectArrayValues(res.data.details, 'boxMaterialQty');
res.data.details.forEach((it) => {
it.boxBillNo = boxBillNo;
it.boxId = res.data.boxId;
it.taskId = res.data.taskId;
it.sourceBillNo = res.data.sourceBillNo;
it.stockCode = _this.warehouseCode;
it.subStockCode = _this.subStockCode;
it.erpDetailId = it.erpDetailId;
it.materialNumber = it.materialNumber;
});
this.datalist = res.data.details.concat(this.datalist);
console.log('列表数据', this.datalist);
}
// 来源单号
this.lyOrderNo = res.data.sourceBillNo;
// 缓存箱号
this.boxstrList.push(boxBillNo);
this.setNum(this.datalist);
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1500
});
//保留当前输入的数据
this.dqboxNO = boxBillNo;
this.xhNo = boxBillNo;
this.focusInput = 'box';
} else {
this.setSMinputbox();
}
});
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = '';
setTimeout(() => {
this.xhNo = '';
this.dqboxNO = '';
this.focusInput = 'box';
console.log('箱光标', this.focusInput);
}, 200);
},
// 根据箱号查相关信息
getboxinfo() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (!this.xhNo) {
this.setSMinputbox();
uni.showToast({
title: '请扫描需要上架的箱号',
icon: 'none',
duration: 1000
});
return;
}
if (this.boxstrList.includes(this.xhNo)) {
this.setSMinputbox();
uni.showToast({
title: '该箱号已扫描',
icon: 'none',
duration: 1000
});
return;
}
this.getboxOrderInfo(this.xhNo);
}, 1000);
},
goback() {
uni.navigateTo({
url: '/pages/warehous/index'
});
}
}
};
</script>
<style lang="scss">
@import '@/static/public.scss';
.mianheade2 {
.pagetitle {
margin-left: 28%;
}
}
</style>

69
pages/warehous/index.vue Normal file
View File

@@ -0,0 +1,69 @@
<!--入库 -->
<template>
<view class="rkpage">
<!-- 标题栏 -->
<view class="mianheade" @click="goback()">
<image src="../../static/img/n_back.png" class="blacBackico"></image>
<text class="pagetitle">入库</text>
</view>
<!--入库菜单-->
<view class="rkMuen">
<view class="item" @click="otherPage(1)">
<image src="../../static/img/rk_shico.png" class="rkico"></image>
<text class="t1" >收货</text>
</view>
<view class="item" @click="otherPage(2)">
<image src="../../static/img/rk_fcgsjico.png" class="rkico"></image>
<text class="t1">采购上架</text>
</view>
<view class="item" @click="otherPage(3)">
<image src="../../static/img/rk_cgsjico.png" class="rkico"></image>
<text class="t1">非采购上架</text>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello'
}
},
onBackPress(e) {
this.$util.appgoBack(e,'index')
return true;
},
methods: {
goback() {
uni.navigateTo({
url: "/pages/index"
})
},
otherPage(type) {
if(type ==1 ){
// 收货
uni.navigateTo({
url: "/pages/warehous/takeDelivery"
})
}
if(type ==2 ){
// 采购上架
uni.navigateTo({
url: "/pages/warehous/cgPutOnsale"
})
}
if(type ==3 ){
// 非采购上架
uni.navigateTo({
url: "/pages/warehous/noCgPutOnsale"
})
}
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
</style>

View File

@@ -0,0 +1,974 @@
<!-- 非采购上架入库 -->
<template>
<view class="shpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">非采购上架入库</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item" :class="{ itembg2: fid }" :style="{ 'pointer-events': fid ? 'none' : '' }">
<view class="it">
<text class="t1">
<text class="redtag">*</text>
仓库:
</text>
<w-select
class="wwselectit"
v-model.trim="warehouseName"
defaultValue="请选择"
:list="warehouseList"
valueName="name"
keyName="name"
@change="ckchange"
@focus="inputfocus($event, 'ck')"
ref="wselectck"
></w-select>
</view>
</view>
<view class="item" :class="{ itembg2: !warehouseCode || boxstrList.length > 0 }" :style="{ 'pointer-events': !warehouseCode || boxstrList.length > 0 ? 'none' : '' }">
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
来源单号:
</text>
<w-select
class="wwselectit"
v-model.trim="lyOrderVal"
defaultValue="请输入订单号搜索"
:list="lyOrderSelectList"
valueName="sourceBillNo"
keyName="sourceBillNo"
@change="lyorderChange"
:filterable="filterable"
optionType="order-fcg"
@onBottomPage="onBottomPage"
@focus="inputfocus($event, 'lyorder')"
:pagingSet="false"
:showClose="true"
ref="wselectlyorder"
></w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('lyorder')"></image>
</view>
</view>
<view
class="item"
:class="{ itembg2: !fid || !warehouseCode || boxstrList.length > 0 }"
:style="{ 'pointer-events': !fid || !warehouseCode || boxstrList.length > 0 ? 'none' : '' }"
>
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
仓位号:
</text>
<w-select
class="wwselectit"
v-model.trim="cwNum"
defaultValue="模糊搜索"
:list="cwselectList"
:focus="focusInput == 'cw'"
@focus="inputfocus($event, 'cw')"
valueName="name"
keyName="name"
@change="cwchange"
:filterable="filterable"
:showClose="true"
ref="wselect1"
@clearnFn="clearnFn"
></w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('cw')"></image>
</view>
</view>
<view
class="item"
:class="{ itembg2: !fid || !warehouseCode || boxstrList.length > 0 }"
:style="{ 'pointer-events': !fid || !warehouseCode || boxstrList.length > 0 ? 'none' : '' }"
>
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
上架方式:
</text>
<w-select
class="wwselectit"
v-model.trim="sjfsType"
defaultValue="请选择"
:list="sjfslist"
valueName="name"
keyName="name"
@change="sjfsChange"
ref="wselectsjfs"
></w-select>
</view>
</view>
<view
class="item"
:class="{ itembg2: !subStockCode || !warehouseCode || !fid || xlhstrList.length > 0 || !sjfsType }"
:style="{ 'pointer-events': !subStockCode || !warehouseCode || !fid || xlhstrList.length > 0 || !sjfsType ? 'none' : '' }"
>
<view class="it itsp">
<text class="t1">
<text class="redtag">*</text>
箱号:
</text>
<input
v-model.trim="xhNo"
class="inpt1"
type="text"
@focus="inputfocus($event, 'box')"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'box')"
:focus="focusInput == 'box'"
/>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item" v-if="sjfsType == '按箱上架' && subStockCode">
<view class="it">
<text class="t1">
<text class="redtag">*</text>
上架数量:
</text>
<text class="t1 tpleft">{{ sjNum }}</text>
</view>
</view>
<view class="item" v-if="sjfsType == '按产品上架'" :class="{ itembg2: !xhNo }" :style="{ 'pointer-events': !xhNo ? 'none' : '' }">
<view class="it itsp">
<text class="t1">序列号:</text>
<input
v-model.trim="xlhVal"
class="inpt1"
type="text"
@focus="inputfocus($event, 'xlh')"
@blur="inputblur($event, '')"
@confirm="inputConfirm($event, 'xlh')"
:focus="focusInput == 'xlh'"
/>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('xlh')"></image>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb cgsjrklb f_cgsjrklb" :style="{ 'margin-top': heights.top + 'px', height: heights.body + 'px' }">
<view class="item" v-for="(item, index) in dataList" :key="index">
<view class="it" style="border: none">
<text class="txt titstr" style="padding-bottom: 4px; border-bottom: 1px dashed #d2d2d2">{{ item.specifications }}</text>
<view class="cssj_it" style="background: #fff">
<view class="tlinb">
<view class="txt txtflexnum">
<view class="pl">
<text style="max-width: 50%">{{ item.materialNumber }}</text>
<view style="background: #eef1f5;display:flex;flex-deraction:row">
{{ item.materialSubStocks && item.materialSubStocks.length > 0 ? '(' : '' }}
<view @click="cwtkfn(item.materialSubStocks)" class="cwhitzs" >
{{ item.materialSubStocks && item.materialSubStocks.length > 0 ? item.materialSubStocks.join(',') : '' }}
</view>
{{ item.materialSubStocks && item.materialSubStocks.length > 0 ? ')' : '' }}
</view>
</view>
</view>
<view class="txt txtflexnum" v-if="sjfsType == '按箱上架' || sjfsType == ''">
<text class="txtNum">{{ item.availableQty }}</text>
<text class="txtNum" v-if="sjfsType == '按箱上架'">{{ item.qty }}</text>
</view>
</view>
<view class="txtNum" v-if="sjfsType == '按产品上架'">
<view>
<text>{{ item.availableQty }}</text>
</view>
<view class="tinput">
<text>上架数量</text>
<u-input
v-model="item.qty"
border="surround"
clearable
class="inpt"
:class="{ inptbordred: item.qty > item.availableQty }"
type="number"
:disabled="boxstrList.length == 0 || (item.xlhList && item.xlhList.length > 0)"
@input="itSJnumConfirm($event, index)"
></u-input>
</view>
</view>
</view>
</view>
</view>
<zero-loading v-if="listloading" type="circle" style="top: 60%"></zero-loading>
</view>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空上架数量</view>
<view class="bt bt2" @click="wcNxetFn">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content="qktkContent" @confirm="qktkconfirm" :showCancelButton="true" @cancel="qktkshow = false"></u-modal>
<!-- 仓位弹框-->
<u-modal :show="cwtkshow" title="可入仓位" @confirm="cwtkshow = false">
<view class="boxtkct">
<view v-for="(item, index) in materialSubStocks" class="c_item">{{ item }}</view>
</view>
</u-modal>
</view>
</template>
<script>
export default {
data() {
return {
cwtkshow: false, // 仓位弹框
materialSubStocks: [], //仓位弹框显示内容
heights: {
top: 0,
body: 0
},
krkStrVal: '', //物料可入库仓位号文本显示
listloading: false,
focusInput: 'ck', //自动聚焦
warehouseName: '', //仓库名称
warehouseCode: '', //仓库编码
warehouseList: [], // 仓库下拉数据
cwNum: '', // 仓位号
cwselectList: [], // 仓位下拉数据
subStockCode: '', // 仓位code
sjNum: '', // 上架数量
sjfsType: '', // 上架方式
lyOrderVal: '', // 来源单号
lyOrderSelectList: [], //来源单号下拉选择单据
xhNo: '', //箱号
boxId: '', // 箱号id
boxstrList: [], // 缓存的箱号信息(多个)
dataList: [], // 页面列表明细数据
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空已收货数量?',
qktkContent: '清空后页面数据将不保存',
focusTag: '', // 判斷聚焦
xlhVal: '', // 序列号的输入值
xlhstrList: [], // 序列号的箱号信息(多个)
filterable: true,
sjfslist: [],
sjfskey: '', // 上架方式key值
boxs: [],
fid: null, // 来源订单号id
orgCode: '', // 组织cdoe
timer: null,
dqboxNO: '', //用来是否保存当前输入箱号的值
dqboxXlh: '', //用来是否保存当前输入xlh的值
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
lymaterialNumber:'',// 选中来源单的编码
twoData:[],//用于判断是否已扫码
scanTracker: {
lastScanTime: 0,
lastScanCode: null
} // 源头处理扫码段时间内重复扫
};
},
watch: {
boxNo(n) {
if (!n) {
this.dqboxNO = '';
}
},
xlhVal(n) {
if (!n) {
this.dqboxXlh = '';
}
},
// 仓位下拉数据
cwNum(n, o) {
if (!n) {
this.cwselectList = [];
this.subStockCode = null;
this.$refs.wselect1.inputData = '';
}
if(n) {
this.subStockCode = null
this.getcwList(n);
}
},
cwselectList(n,o) {
console.log(n,'监听到了吗')
if(n.length && this.cwNum) {
this.cwselectList.forEach((item)=>{
if(item.name === this.cwNum) {
// this.$refs.wselect1.optionsShow = false;
// this.$refs.wselect1.isShow = false;
this.subStockCode = item.code
if(this.subStockCode) {
this.$refs.wselect1.optionsShow = false;
this.$refs.wselect1.isShow = false;
}
// setTimeout(()=>{
// this.$refs.wselect1.optionsShow = false;
// this.$refs.wselect1.isShow = false;
// },500)
}
})
}
},
// 来源订单号实时输入监听
lyOrderVal(n, o) {
if (!n) {
this.qktkconfirm();
this.dataList = [];
this.lyOrderSelectList = [];
this.fid = '';
this.cwNum = '';
this.subStockCode = '';
this.sjfsType = '';
this.$refs.wselectsjfs.inputData = '';
this.$refs.wselect1.inputData = '';
} else {
this.getlyOrderInfolist(n);
}
}
},
mounted() {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts');
console.log('最终列表高度非采购', this.heights);
},
onLoad() {
this.sjfslist = this.$util.setObjectArry(uni.getStorageSync('allTypelist').shelfMethod);
this.sjfskey = this.sjfslist[0].id;
// 按箱子上架 箱号对应来源单号的箱号,且可以扫描多个 箱号存在值之后,仓位就不能修改
// 按产品上架 箱号只取最后的箱,仓位可以一直修改
///获取广播扫码监听
this.$broadcastScan.init(this.getScancode);
this.$broadcastScan.start();
this.stopScanCode();
this.startScanCode();
this.getcklist();
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode();
},
onShow() {
this.$broadcastScan.start();
this.startScanCode();
},
onBackPress(e) {
this.$util.appgoBack(e, 'warehousIndex');
return true;
},
methods: {
// 开启广播
startScanCode() {
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if (res.code === this.scanTracker.lastScanCode && timeSinceLastScan < 4000) {
return;
} else {
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code);
}
});
},
// 关闭广播
stopScanCode() {
uni.$off('xwscan');
},
// 明细上架框显示上架数量不能大于当前物料数量,如果大于就默认为最大数量
itSJnumConfirm(val, index) {
if (parseInt(val) > parseInt(this.dataList[index].availableQty)) {
setTimeout(() => {
this.dataList[index].qty = this.dataList[index].availableQty;
}, 200);
}
},
// 打开仓位弹框
cwtkfn(list) {
if (!list || (list && list.length < 2)) return;
this.cwtkshow = true;
this.materialSubStocks = list;
},
//仓库选择下拉监听
ckchange(e) {
this.warehouseName = e.name;
this.warehouseCode = e.code;
this.orgCode = e.erpOrgCode;
this.lyOrderVal = '';
this.$refs.wselectlyorder.inputData = '';
},
// 获取仓库下拉数据
getcklist() {
this.warehouseList = [];
this.$api.get('/SysConfig/GetUcStock').then((res) => {
if (res.status == 200) {
this.warehouseList = res.data;
}
});
},
// 完成下一单
wcNxetFn() {
console.log('完成下一单', this.subStockCode, this.lyOrderVal, this.boxstrList);
if (!this.subStockCode || !this.lyOrderVal || this.boxstrList.length == 0) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1000
});
return;
}
let dataForm = {};
let details = [];
console.log(this.dataList);
details = this.dataList.map((it) => {
return {
qty: it.qty,
supplierId: it.supplierId,
materialNumber: it.materialNumber,
serialNumbers: it.xlhList, //序列号集
erpDetailId: it.erpDetailId
};
});
console.log('提交数据1', this.dataList, dataForm);
if (this.sjfsType == '按产品上架') {
this.boxs[0].details = details;
}
dataForm = {
taskId: this.fid,
shelfMethod: this.sjfskey,
orgCode: this.orgCode,
stockCode: this.warehouseCode,
subStockCode: this.subStockCode,
boxs: this.boxs
};
console.log('dataForm', dataForm);
// 节流
if (this.requestStatus) {
return false;
}
this.requestStatus = true;
this.$api.post('/InStock/ShelfOther', dataForm).then((res) => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1000
});
setTimeout(() => {
uni.navigateTo({
url: '/pages/warehous/noCgPutOnsale'
});
}, 200);
// this.$router.go(0)
}
});
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
// 清空二次确认
qktkconfirm() {
this.boxstrList = [];
this.xlhstrList = [];
this.twoData=[];
this.boxs = [];
this.xlhVal = '';
this.xhNo = '';
this.dqboxNO = '';
this.dqboxXlh = '';
this.sjNum = null;
this.dataList.forEach((it) => {
it.qty = 0;
it.xlhList = [];
});
this.qktkshow = false;
this.focusInput = '';
},
// 根据来源单号获取下拉数据
getlyOrderInfolist(val) {
if (!val) return;
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.$api
.post('/InStockTask/GetSourceOrderNoPurchase', {
sourceBillNo: val,
stockCode: this.warehouseCode
})
.then((res) => {
if (res.status == 200) {
this.lyOrderSelectList = res.data;
}
});
}, 1000);
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = '';
setTimeout(() => {
this.dqboxNO = '';
this.xhNo = '';
this.sjNum = null;
this.focusInput = 'box';
}, 200);
},
clearnFn(){
// console.log('123232323')
this.cwNum=''
this.subStockCode =''
this.cwselectList=[]
this.focusInput = ''
setTimeout(()=>{
this.focusInput ='cw'
},300)
},
// 根据箱号查相关信息
getboxinfo() {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
if (!this.xhNo) {
this.setSMinputbox();
uni.showToast({
title: '请扫描需要上架的箱号',
icon: 'none',
duration: 1000
});
return;
}
if (this.boxstrList.includes(this.xhNo) && this.sjfsType == '按箱上架') {
this.setSMinputbox();
uni.showToast({
title: '该箱号已扫描',
icon: 'none',
duration: 1000
});
return;
}
this.focusInput = '';
//采购订单物料明细和箱物料明细-对比接口,
if (this.sjfsType == '按箱上架') {
this.$api
.post('/InStockTask/Contrast', {
boxBillNos: [this.xhNo],
stockCode: this.warehouseCode,
taskId: this.fid,
isPurchase:false,
})
.then((res) => {
if (res.status == 200) {
/*
数据分配 如果相同物料相同单号,相同规格,相同组织
1.先判断箱子里面的物料数量是否大于订单里面物料数量的总和大于直接提示不能上架
2.先判断a物料总数对应明细相同物料去分配总数
3.// 如果是扫描的第一箱子,就一一判断明细物料数量去判断,一旦某条物料总数超过就提示不能上架
*/
// 明细相同物料,数量总和
let mxwldb = this.$util.subtractQty(this.$util.sumByField(this.dataList, 'availableQty'), this.$util.sumByField(this.dataList, 'qty'));
// 如果是第一次扫箱就拿物料的availableQty做统计如果不是就那qty做统计
let mxggWLnumTotal = this.boxstrList.length > 0 ? mxwldb : this.$util.sumByField(this.dataList, 'availableQty');
// 箱子相同物料,数量总和
let xwlnumTotal = this.$util.sumByField(res.data.boxs[0].details, 'qty');
// 如果存在箱物料数量大于订单物料数量就不能上架
let pdcg = !this.$util.checkQtyExceedsLimit(mxggWLnumTotal, xwlnumTotal, 'materialNumber', 'qty');
// console.log('判断数量超过', mxwldb,mxggWLnumTotal, xwlnumTotal,pdcg)
if (pdcg) {
// 进行分配
const result = this.$util.allocateQty(xwlnumTotal, this.dataList);
this.dataList = result.updatedDetails;
// 每个箱子分配要知道给那条物料分别分配了多少数量
this.boxs.push({
id: 0,
boxId: res.data.boxs[0].boxId,
boxBillNo: res.data.boxs[0].boxBillNo,
details: result.allocationLog
});
this.sjNum = res.data.boxs[0].totalCount;
//保留当前输入的数据
this.dqboxNO = res.data.boxs[0].boxBillNo;
this.xhNo = res.data.boxs[0].boxBillNo;
// 缓存箱号
this.boxstrList.push(res.data.boxs[0].boxBillNo);
this.focusInput = 'box';
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
});
} else {
this.setSMinputbox();
uni.showToast({
title: '箱内产品数量超过可上架数量',
icon: 'none',
duration: 1000
});
return;
}
} else {
this.setSMinputbox();
}
});
}
if (this.sjfsType == '按产品上架') {
this.$api
.get('/SysConfig/GetBoxSynthesis', {
boxBillNo: this.xhNo
})
.then((res) => {
if (res.status == 200) {
// 如果当前箱子的仓库和来源单的仓库不一致就不能用这个箱子
if (res.data.stockCode && res.data.stockCode !== this.warehouseCode) {
this.setSMinputbox();
uni.showToast({
title: '该箱号仓库与来源单仓库不一致,请重新操作',
icon: 'none',
duration: 1400
});
return;
}
// 如果查询的箱号正常返回数据,就缓存改箱号信息
this.boxstrList = [];
this.boxstrList.push(this.xhNo);
var theid = 0;
// 如果是按产品上架要判断是否存在过的部分扫过的箱信息如果存在id不能为0 。按照箱就不存这这个情况为0
if (this.lyOrderSelectList && this.lyOrderSelectList.length > 0 && this.lyOrderSelectList.boxs) {
this.lyOrderSelectList.boxs.forEach((it) => {
if (res.data.id == it.boxId) {
theid = it.id;
}
});
}
this.boxs = [];
this.boxs.push({
id: theid,
boxId: res.data.id,
boxBillNo: res.data.boxBillNo
});
this.sjNum = res.data.totalQty ? res.data.totalQty : 0;
//保留当前输入的数据
this.dqboxNO = '';
this.dqboxNO = res.data.boxBillNo;
this.xhNo = res.data.boxBillNo;
this.xlhVal = '';
// 如果这个箱子仓库有值和单的仓库一致但是仓位不一致以箱子的仓位为准
if (res.data.stockCode == this.warehouseCode && res.data.subStockCode) {
this.$refs.wselect1.inputData = res.data.subStock;
this.cwNum = res.data.subStock;
this.subStockCode = res.data.subStockCode;
console.log('仓位为准', res.data);
}
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
});
this.focusInput = 'xlh';
} else {
this.setSMinputbox();
}
});
}
}, 1000);
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == 'normalAnroid') {
this.$util.doScanQrCode().then((res) => {
this.focusInput = type;
this.focusTag = type;
this.getScancode(res.result);
});
}
},
// 获取扫描的值
getScancode(code) {
console.log('获取扫描的值', this.focusTag, code);
if (this.focusTag == 'box') {
this.xhNo = '';
this.xhNo = code.trim();
this.getboxinfo();
console.log('获取扫描的值', code);
}
// 序列号
if (this.focusTag == 'xlh') {
this.xlhVal = '';
this.xlhVal = code.trim();
this.getXlhInfo();
//根据序列号去更新对应的明细规格型号的上架数量的值 扫描一个数量加一,重复扫描要提示
}
// 仓位
if (this.focusTag == 'cw') {
this.cwNum = '';
this.cwNum = code.trim();
this.$refs.wselect1.inputData = code.trim();
this.getcwList();
}
// 来源单
if (this.focusTag == 'lyorder') {
this.lyOrderVal = '';
this.lyOrderVal = code.trim();
this.$refs.wselect1.wselectlyorder = code.trim();
this.getlyOrderInfolist(this.lyOrderVal);
}
},
// 輸入失去焦點
inputblur(val, type) {},
// 输入聚焦
inputfocus(val, type) {
this.focusTag = type;
if (type == 'cw') {
this.focusInput = 'cw';
}
},
// 区分不同的扫描数据、输入数据做处理显示 box
setSMstr(str) {
let lth = str.length - this.dqboxNO.length;
if (lth > 1) {
// 扫描的值
this.xhNo = str.substring(this.dqboxNO.length);
} else {
this.dqboxNO = str;
this.xhNo = str;
}
},
// 区分不同的扫描数据、输入数据做处理显示 xlh
setSMxlhstr(str) {
let lth = str.length - this.dqboxXlh.length;
if (lth > 1) {
// 扫描的值
this.xlhVal = str.substring(this.dqboxXlh.length);
} else {
this.dqboxXlh = str;
this.xlhVal = str;
}
},
// 输入确认
inputConfirm(val, type) {
if (val) {
if (this.focusTag == 'box') {
this.setSMstr(val.target.value);
this.getboxinfo();
}
if (this.focusTag == 'xlh') {
this.setSMxlhstr(val.target.value);
this.getXlhInfo();
}
}
},
// 扫描框数据重置,光标聚焦
setSMinputxlh() {
this.focusInput = '';
setTimeout(() => {
this.xlhVal = '';
this.focusInput = 'xlh';
}, 200);
},
// 根据序列号获取对应的规格型号
getXlhInfo() {
if (!this.xlhVal) {
this.setSMinputxlh();
uni.showToast({
title: '请扫描来源单内的序列号',
icon: 'none',
duration: 1000
});
return;
}
if (this.xlhstrList.includes(this.xlhVal) || this.twoData.includes(this.xlhVal) && this.sjfsType == '按产品上架') {
this.setSMinputxlh();
uni.showToast({
title: '该序列号已扫描过',
icon: 'none',
duration: 1000
});
return;
}
this.focusInput = '';
console.log('序列號', this.xlhVal);
this.$api
.get('/SysConfig/GetMaterial', {
serialNumber: this.xlhVal,
IsOps: true,
serialStatus: 1
})
.then((res) => {
if (res.status == 200) {
let thindx = this.dataList.findIndex((it) => it.materialNumber == res.data.materialNumber);
if (thindx == -1) {
this.setSMinputxlh();
uni.showToast({
title: '请扫描来源单内的序列号',
icon: 'none',
duration: 1000
});
} else if (res.data.isBoxInventory && !res.data.isOldOps) {
this.setSMinputxlh();
uni.showToast({
title: '序列号已上架入库',
icon: 'none',
duration: 1000
});
} else if (!res.data.serialNumber) {
this.setSMinputxlh();
uni.showToast({
title: '请扫描序列号',
icon: 'none',
duration: 1000
});
} else {
/*
*1.判断该序列号对应的物料是否有存在过扫描的物料,
* 如果存在都已经是扫描的状态,就判断该物料所有的上架数量是否有大于该物料数量的总和,大于就提示不能在扫描了
* 如果存在部分扫描就拿扫描的的数量总和去判断是否大于物料明细的总和,大于也不能在扫描了
*2.分配序列号重上到下,如果第一条没有扫描过就重置上架输入框为空然后置灰累计加一,
* 如果累计的数量大于了物料数量就继续往下分配,下一条物料也是如此
*3.一直扫描序列号 就扫描到所有物料都分配完为止()
* */
let totalAvailableQty = 0;
let totalXlhListLength = 0;
// 遍历数组计算总可用数量和xlhList总长度
for (const item of this.dataList) {
if (item.materialNumber === res.data.materialNumber) {
totalAvailableQty += item.availableQty;
totalXlhListLength += item.xlhList.length;
}
}
if (totalXlhListLength + 1 > totalAvailableQty) {
this.setSMinputxlh();
uni.showToast({
title: '上架数量超过来源单可上架数量',
icon: 'none',
duration: 1000
});
return;
}
this.dataList = this.$util.scanAndAllocate(this.dataList, res.data.materialNumber, res.data.serialNumber);
// 缓存序列号
this.xlhstrList.push(res.data.serialNumber);
//缓存2件装序列号
if(res.data.isTwo==2) {
this.twoData.push(res.data.twoSerialNumber)
}
//保留当前输入的数据
this.dqboxXlh = res.data.serialNumber;
this.xlhVal = res.data.serialNumber;
//清空当前框数据 自动聚焦箱号
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1000
});
}
} else {
this.dqboxXlh = '';
this.xlhVal = '';
}
this.focusInput = 'xlh';
});
},
// 根据序列号的时候明细数据结构
xlhsetDetaildata(list) {
if (list && list.length > 0) {
list.forEach((it) => {
it.qty = 0;
it.xlhList = [];
});
}
console.log('根据序列号的时候明细数据结构', list);
return list;
},
// 来源单号下拉选择监听
lyorderChange(e) {
this.fid = e.id;
this.focusInput = '';
this.fid = e.id;
this.lymaterialNumber = e.materialNumber
e.details = this.itemDateset(e.details);
this.dataList = this.xlhsetDetaildata(e.details);
console.log(1111, this.dataList);
this.focusInput = 'cw';
},
// 明细数据初始化处理
itemDateset(list) {
let objArray = [];
objArray = list;
let newObjArray = objArray.map((obj) => {
obj.zQty = JSON.parse(JSON.stringify(obj.qty)); // 修改 name 属性,这里是在姓名后加上 ' Smith'
obj.qty = 0; // 添加 age 属性,这里设定年龄为 30
return obj;
});
return objArray;
},
// 仓位下拉选择
cwchange(e) {
this.cwNum = e.name;
this.subStockCode = e.code;
},
// 上架返回下拉选择监听
sjfsChange(e) {
// 清空箱号和缓存
this.boxstrList = [];
this.xhNo = '';
this.sjfskey = e.id;
this.sjfsType = e.name;
this.boxs = [];
setTimeout(() => {
this.heights.top = this.heights.top + 36;
this.heights.body = this.heights.body - 36;
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts');
}, 200);
// if(this.cwNum && this.cwselectList.length && !this.subStockCode){
// this.cwselectList.forEach((item)=>{
// if(item.name === this.cwNum) {
// this.subStockCode = item.code
// console.log(this.subStockCode,'=走到这里来了=')
// }
// })
// }
this.$forceUpdate();
},
// 获取仓位下拉数据
getcwList(val) {
if (!val && !this.warehouseCode) return;
this.$api
.post('/SysConfig/GetSubUcStockByName', {
name: val,
stockCode: this.warehouseCode,
orgCode:this.orgCode
})
.then((res) => {
if (res.status == 200) {
this.cwselectList = res.data;
//&& this.cwselectList.length == 1
// if (this.cwselectList && this.cwselectList.length == 1) {
// this.cwNum = this.cwselectList[0].name;
// this.cwchange(this.cwselectList[0]);
// this.$refs.wselect1.optionsShow = false;
// this.$refs.wselect1.isShow = false;
// }
}
});
},
onBottomPage() {},
goback() {
uni.navigateTo({
url: '/pages/warehous/index'
});
}
}
};
</script>
<style lang="scss">
@import '@/static/public.scss';
.mianheade2 {
.pagetitle {
margin-left: 26%;
}
}
</style>

View File

@@ -0,0 +1,527 @@
<!-- 收货 -->
<template>
<view class="shpage">
<!-- 标题栏 -->
<view class="mianheade mianheade2" @click="goback()">
<image src="../../static/img/n_baiback.png" class="blacBackico"></image>
<text class="pagetitle">收货</text>
</view>
<!-- 固定内容-->
<view class="sh_gdInfo">
<view class="item itembg2">
<view class="it">
<text class="t1">仓库: </text>
<text class="t2">{{warehouseName}}</text>
</view>
</view>
<view class="item" :class="{'itembg2':xhNo || boxstrList.length>0 }"
:style="{'pointer-events':xhNo ||boxstrList.length>0?'none':''}">
<view class="it itsp" >
<text class="t1"><text class="redtag">*</text>采购订单号: </text>
<!-- <view class="t1" style="display: flex;">
<text class="redtag">*</text>
<uni-data-select
style="font-size:12px"
v-model="selectValue"
:localdata="options"
@change="hanldeSelectChange"
:clear="false"
></uni-data-select>
</view> -->
<w-select class="wwselectit" v-model.trim='cgOrderVal' defaultValue="请输入订单号搜索" :list='cgselectList'
valueName='sourceBillNo' keyName="sourceBillNo" @change='cgchange' :filterable='filterable'
optionType="order" @onBottomPage="onBottomPage" :pagingSet='false' :focus="focusInput=='cgdd'"
@focus="inputfocus($event,'cgdd')" :showClose='true' ref="wselectcgdd">
</w-select>
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('cgdd')"></image>
</view>
</view>
<view class="item" :class="{'itembg2':!cgOrderVal}" :style="{'pointer-events':!cgOrderVal?'none':''}">
<view class="it itsp">
<text class="t1"><text class="redtag">*</text>箱号: </text>
<input v-model.trim="xhNo" class="inpt1" type="text" @focus="inputfocus($event,'box')"
@blur="inputblur($event,'')" @confirm="inputConfirm($event,'box')"
:focus="focusInput == 'box'" />
<image src="../../static/img/smico.png" class="searchico" @click="scanImg('box')"></image>
</view>
</view>
<view class="item itembg2">
<view class="it">
<text class="t1">数量: </text>
<text class="t1 tpleft">{{boxNum}} </text>
</view>
</view>
<view class="item item2">
<view class="it2">
<text class="t1">{{cgOrderWLnum}}</text>
<text class="t2">订单数量</text>
</view>
<view class="it2">
<text class="t1">{{krkNum}}</text>
<text class="t2">可入库数</text>
</view>
<view class="it2">
<text class="t1 rednum">{{yshNum}}</text>
<text class="t2">已收货数</text>
</view>
<view class="it2" @click="xhmodelOpen">
<text class="t1 rednum">{{boxstrList.length}}</text>
<text class="t2">已收箱数</text>
</view>
</view>
</view>
<!-- 列表内容-->
<view class="shlb" :style="{'margin-top':heights.top+'px','height':heights.body+'px'}">
<z-paging ref="paging" v-model="dataList" @query="queryList" class="xlfeview"
loading-more-default-text="上拉加载更多" :refresher-enabled="false">
<view class="item" v-for="(i,index) in dataList" :key="index">
<view class="it">
<text class="txt">{{i.specifications}}</text>
<text class="txt">{{i.materialNumber}}</text>
<text class="txt">明细备注:{{i.remark}}</text>
</view>
</view>
<zero-loading v-if="listloading" type="circle" style="top: 60%;"></zero-loading>
</z-paging>
</view>
<!-- 已上架箱号-->
<u-modal :show="xhlistshow" title="已收箱号" @confirm="xhlistshow =false">
<view style="display: flex;flex-direction: column;overflow-y: auto;max-height: 60vh;overflow-y: auto;">
<view v-for="(item,index) in boxstrList" style="margin-bottom: 5px;">{{item}}</view>
</view>
</u-modal>
<!-- 底部按钮固定-->
<view class="footbts">
<view class="bt bt1" @click="qktkshow = true">清空收货数量</view>
<view class="bt bt2" @click="completefn()">完成/下一单</view>
</view>
<!--清空二次确认弹框-->
<u-modal :show="qktkshow" :title="qktkTitle" :content='qktkContent' @confirm="qktkconfirm"
:showCancelButton='true' @cancel="qktkshow = false"></u-modal>
</view>
</template>
<script>
export default {
data() {
return {
heights: {
top: 0,
body: 0,
},
options:[
{value:1,text:'采购订单号'},
{value:2,text:'生产单号'},
],
selectValue:1,//单号选择
listloading: false,
xhlistshow: false, // 箱号查看弹框
focusInput: 'cgdd', // 自动聚焦
mxid: '', //采购订单下拉选中明细id
focusTag: "", // 判斷聚焦
warehouseName: '', //仓库名称
warehouseCode: '', // 仓库编码
xhNo: "", //箱号
boxstrList: [], // 缓存的箱号信息(多个)
filterable: true, // 采购订单是否开启模糊下拉搜索
boxNum: 0, //数量(扫码箱子的数量)
boxs: [], // 已经扫描的箱子和对应id集合
cgOrderWLnum: 0, // 订单数量(采购订单物料数量)
cgOrderVal: "", //输入的采购订单号
cgselectList: [], //采购下拉数据
krkNum: 0, //可入库数量
yshNum: 0, // 已收货数量
dataList: [], // 列表数据
qktkshow: false, //清空二次确认弹框
qktkTitle: '确定清空已收货数量?',
qktkContent: "清空后页面数据将不保存",
timer: null,
availableQty: 0, // 第一次订单的可入库数量
erpDetailId: null, // erp明细id
dqboxNO: '', //用来是否保存当前输入箱号的值
APPdevice: uni.getStorageSync('devicePixelRatio'), // 缓存设备的像素比用来区分普通安卓normalAnroid还是pda
requestStatus: false, // 请求状态识别变量
materialNumber: null, //选中采购单的时候物料编码
scanTracker: {
lastScanTime: 0,
lastScanCode: null
}, // 源头处理扫码段时间内重复扫
}
},
watch: {
boxNo(n) {
if (!n) {
this.dqboxNO = ''
}
},
// 采购订单号实时输入监听
cgOrderVal(n, o) {
if (!n) {
this.qktkconfirm()
this.dataList = []
this.cgOrderWLnum = 0
this.krkNum = 0
this.yshNum = 0
this.yshNum = 0
this.dqboxNO = ''
this.cgselectList = []
this.warehouseName = ''
this.warehouseCode = ''
} else {
this.getcgOrderSelectData(n)
}
}
},
onReady() {
setTimeout(() => {
this.heights = this.$util.setlistHeight('.sh_gdInfo', '.footbts')
console.log("设备信息", this.heights)
}, 500)
},
mounted() {
//获取广播扫码监听
this.$broadcastScan.init(this.getScancode)
this.$broadcastScan.start();
this.stopScanCode()
this.startScanCode()
},
onHide() {
this.$broadcastScan.stop();
this.stopScanCode()
},
onShow() {
this.$broadcastScan.start();
this.startScanCode()
},
onBackPress(e) {
this.$util.appgoBack(e,'warehousIndex')
return true
},
methods: {
// 开启广播
startScanCode(){
uni.$on('xwscan', (res) => {
const now = Date.now();
const timeSinceLastScan = now - this.scanTracker.lastScanTime;
// 如果扫描的箱码和上次相同并且时间间隔小于500ms则不作处理
if ((res.code === this.scanTracker.lastScanCode) && (timeSinceLastScan < 4000)) {
return;
} else{
// 更新扫描跟踪信息
this.scanTracker.lastScanTime = now;
this.scanTracker.lastScanCode = res.code;
this.getScancode(res.code)
}
})
},
// 关闭广播
stopScanCode(){
uni.$off('xwscan')
},
// 打开查看箱号
xhmodelOpen() {
if (this.boxstrList.length > 0) {
this.xhlistshow = true
}
},
// 清空二次确认
qktkconfirm() {
this.xhNo = ""
this.boxNum = 0
this.krkNum = this.$util.sumObjectArrayValues(this.dataList, 'availableQty')
this.qktkshow = false
this.yshNum = 0
this.boxs = []
this.boxstrList = []
},
// //select-change
// hanldeSelectChange() {
// this.cgOrderVal = ""
// this.$refs.wselectcgdd.inputData=""
// this.focusInput= ""
// setTimeout(()=>{
// this.focusInput='cgdd'
// },200)
// },
// 获取采购订单下拉数据
getcgOrderSelectData(val) {
if (!val) return
clearTimeout(this.timer)
this.timer = setTimeout(() => {
this.$api.get('/InStockTask/GetSourceOrder/' + val).then(res => {
if (res.status == 200) {
this.cgselectList = []
this.cgselectList = res.data
console.log(this.focusInput)
if (this.cgselectList && this.cgselectList.length == 1) {
this.cgOrderVal = this.cgselectList[0].sourceBillNo
this.$refs.wselectcgdd.filterList = res.data
this.$refs.wselectcgdd.inputData = this.cgselectList[0].sourceBillNo
this.setItemdata(this.cgselectList[0])
this.cgchange(this.cgselectList[0])
this.$refs.wselectcgdd.optionsShow = false
this.$refs.wselectcgdd.isShow = false
} else {
this.$refs.wselectcgdd.optionsShow = true
this.$refs.wselectcgdd.isShow = true
}
if(this.focusInput !== 'cgdd'){
this.$refs.wselectcgdd.optionsShow = false
this.$refs.wselectcgdd.isShow = false
}
}
})
}, 1000)
},
// 采购订单下拉框分页加载
onBottomPage(val) {},
// 选中的采购订单号相关物料 如果数据校验失败就取明细带来的信息,不是就去明细信息的
setItemdata(e) {
this.availableQty = e.availableQty
this.cgOrderWLnum = this.$util.sumObjectArrayValues(this.dataList, 'qty')
this.mxid = e.detailsId
this.fid = e.id
this.materialNumber = e.materialNumber
// 仓库名称
this.warehouseName = e.stockName
this.warehouseCode = e.stockCode
this.erpDetailId = e.erpDetailId
this.krkNum = e.availableQty
this.focusInput = 'box'
},
// 采购订单下拉选中
cgchange(e) {
if (!this.cgOrderVal) {
return
}
this.dataList = [e]
// 以前已收货数量
this.setItemdata(e)
},
// 扫描框数据重置,光标聚焦
setSMinputbox() {
this.focusInput = ''
setTimeout(() => {
this.xhNo = ''
this.focusInput = 'box'
this.boxNum = ''
}, 200)
},
// 根据箱号查相关信息
getboxinfo() {
if (this.timer) {
clearTimeout(this.timer)
}
this.timer = setTimeout(() => {
if (!this.xhNo) {
this.setSMinputbox()
uni.showToast({
title: '请扫描需要上架的箱号',
icon: 'none',
duration: 1500
})
return
}
if (this.boxstrList.includes(this.xhNo)) {
this.setSMinputbox()
uni.showToast({
title: '该箱号已扫描,请重新输入',
icon: 'none',
duration: 1500
})
return
}
this.focusInput = ''
//采购订单物料明细和箱物料明细-对比接口,
this.$api.post('/InStockTask/Contrast', {
boxBillNos: [this.xhNo.trim()],
stockCode: this.warehouseCode,
materialNumber:this.materialNumber,
taskId: this.fid,
isPurchase:true,
}).then(res => {
if (res.status == 200) {
if(res.data.boxs[0].details.length>1){
this.dqboxNO = ''
this.xhNo = ''
uni.showToast({
title: '箱内产品和采购单不一致!',
icon: 'none',
duration: 1000
})
return
}
// 需要带出相关已收货数和已收箱数(这个数量应该是箱子对应单据选择物料的数量)
// let boxbymaterialQtyobj = res.data.boxs[0].details.find(item => item.materialNumber === this.materialNumber)
// console.log('物料数量',boxbymaterialQtyobj.qty)
let totalCount = res.data.boxs[0].totalCount
// 可入库数量=订单数量-(当前箱子的数量+累计)-以前收货数量-已交
// let dqkrkNUM = this.cgOrderWLnum - (this.yshNum + totalCount) - this.$util
// .sumObjectArrayValues(this.dataList, 'receiveQty') - this.$util.sumObjectArrayValues(
// this.dataList, 'deliveredQty')
// 12.5 界面可入库数量=接口第一次返回的可入库数量-已收货数量
let dqkrkNum = this.$util.sumObjectArrayValues(this.dataList, 'availableQty')
console.log('可入', parseInt(this.yshNum + totalCount), this.krkNum, )
if (res.data.boxs.length > 0) {
if (parseInt(this.yshNum + totalCount) > dqkrkNum) {
this.setSMinputbox()
uni.showToast({
title: '箱内产品数量超过可入库数量',
icon: 'none',
duration: 1000
})
return
}
// 当前箱号里面物料的数量
this.boxNum = totalCount
// 已收货数量 累加
this.krkNum = dqkrkNum - (this.yshNum + totalCount)
this.yshNum = this.yshNum + totalCount
this.boxs.push({
id: 0,
erpDetailId: this.erpDetailId,
boxId: res.data.boxs[0].boxId,
boxBillNo: res.data.boxs[0].boxBillNo
})
// 如果查询的箱号正常返回数据,就缓存改箱号信息
this.boxstrList.push(res.data.boxs[0].boxBillNo)
//保留当前输入的数据
this.dqboxNO = res.data.boxs[0].boxBillNo
this.xhNo = res.data.boxs[0].boxBillNo
uni.showToast({
title: '获取成功',
icon: 'none',
duration: 1500
})
}
} else {
this.dqboxNO = ''
this.xhNo = ''
}
this.focusInput = 'box'
})
}, 1000)
},
// 输入确认
inputConfirm(val, type) {
if (val) {
this.setSMstr(val.target.value)
if (this.focusTag == 'box') {
// this.xhNo = val.target.value
this.getboxinfo()
}
}
},
// 区分不同的扫描数据、输入数据做处理显示
setSMstr(str) {
let lth = str.length - this.dqboxNO.length
if (lth > 1) {
// 扫描的值
this.xhNo = str.substring(this.dqboxNO.length)
} else {
this.dqboxNO = str
this.xhNo = str
}
},
// 普通安卓设备碘酒扫描图标扫描
scanImg(type) {
if (this.APPdevice == "normalAnroid") {
this.$util.doScanQrCode().then(res => {
this.focusInput = type
this.focusTag = type
this.getScancode(res.result)
})
}
},
// 获取扫描的值
getScancode(code) {
// 有些PDA会自带换行符trim函数处理下、
if (this.focusTag == 'box') {
this.xhNo = ''
this.xhNo = code.trim()
this.getboxinfo()
}
if (this.focusTag == 'cgdd') {
this.cgOrderVal = ''
this.cgOrderVal = code.trim()
this.$refs.wselectcgdd.inputData = code.trim()
this.getcgOrderSelectData(this.cgOrderVal)
}
},
// 輸入失去焦點
inputblur(val, type) {},
// 输入聚焦
inputfocus(val, type) {
this.focusTag = type
},
// 完成/下一单
completefn() {
if (!this.cgOrderVal || this.boxstrList.length == 0) {
uni.showToast({
title: '请先输入必填值',
icon: 'none',
duration: 1500
})
return
}
// 节流
if (this.requestStatus) {
return false;
}
this.requestStatus = true;
this.$api.post('/InStockTask/Receive', {
id: this.fid,
boxs: this.boxs,
details: [{
id: this.mxid, //明细id
materialNumber: this.materialNumber,
receiveQty: this.yshNum,
erpDetailId: this.erpDetailId
}]
}).then(res => {
if (res.status == 200) {
uni.showToast({
title: '成功',
icon: 'none',
duration: 1500
})
setTimeout(() => {
uni.navigateTo({
url: '/pages/warehous/takeDelivery'
})
}, 200);
// this.$router.go(0)
}
})
setTimeout(() => {
this.requestStatus = false;
}, 1500);
},
goback() {
uni.navigateTo({
url: "/pages/warehous/index"
})
},
// 列表上拉加载更多
queryList(pageNo, pageSize) {
// console.log('上拉加载', pageNo, pageSize, this.dataList.length)
// this.$refs.paging.complete(this.dataList)
}
}
}
</script>
<style lang="scss">
@import "@/static/public.scss";
::v-deep .uni-select {
border:none !important;
height:24px;
width: 175rpx;
padding-right: 0;
padding-left: 3rpx;
text-align: center;
margin-left: -7rpx;
}
</style>

BIN
static/img/Frame.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

BIN
static/img/ckgd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 950 B

BIN
static/img/ckxx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

BIN
static/img/copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
static/img/deletico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

BIN
static/img/headbg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
static/img/ic_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

BIN
static/img/ic_qcinput.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

BIN
static/img/ic_remark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
static/img/inventory.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/img/log.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/img/logbg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

BIN
static/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
static/img/n_back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

BIN
static/img/n_baiback.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

BIN
static/img/out.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/img/outbound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
static/img/qtrk_m1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/img/qtrk_m2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
static/img/qtrk_m3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
static/img/qtrk_m4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/img/qtrk_m5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
static/img/rk_cgsjico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
static/img/rk_fcgsjico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
static/img/rk_shico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
static/img/searchico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
static/img/smico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

BIN
static/img/sybg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

BIN
static/img/syico1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
static/img/syico2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
static/img/syico3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
static/img/syico4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

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,
};

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

752
static/public.scss Normal file
View File

@@ -0,0 +1,752 @@
/*登录*/
.login {
background: #fff;
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
}
.logoPage {
background: url(@/static/img/logbg.png) no-repeat;
background-size: 100% 100%;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
overflow: hidden;
padding-top: 70px;
.logo_from {
display: flex;
flex-direction: column;
width: 100%;
margin-top: 30px;
.item {
margin: 0 32px;
margin-bottom: 25px;
}
.loglabe {
font-size: 14px;
color: #505050;
}
.loginput {
font-size: 18px;
color: #222222;
padding: 5px;
width: 100%;
border-bottom: 1px solid #dfe3e8;
}
.dlbt {
background: #2d53eb;
margin: 0 32px;
margin-top: 10px;
color: #fff;
padding: 10px 0;
border-radius: 10px;
font-size: 16px;
text-align: center;
}
}
}
.imglogo {
width: 80px;
height: 80px;
display: block;
}
/*end登录*/
/*首頁*/
.sy {
background: #eef1f5;
width: 100%;
height: 100vh;
position: relative;
.sybg {
position: absolute;
top: 0;
width: 100%;
height: 175px;
}
.sy_info {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 32px;
padding-bottom: 22px;
padding-top: 55px;
z-index: 1;
.sy_txt {
display: flex;
flex-direction: column;
z-index: 1;
.t1 {
font-size: 16px;
padding-bottom: 3px;
color: #fff;
}
.t2 {
font-size: 16px;
font-weight: bold;
color: #fff;
}
}
.syoutico {
width: 32px;
height: 32px;
}
}
.sy_meuns {
display: flex;
flex-direction: column;
margin: 0 24px;
z-index: 1;
position: relative;
.sy_item {
padding: 24px;
border-radius: 10px;
background: #fff;
margin-bottom: 16px;
display: flex;
flex-direction: row;
align-items: center;
position: relative;
.symeunico {
width: 48px;
height: 48px;
margin-right: 24px;
position: absolute;
top: 20px;
}
.t1 {
color: #222222;
font-size: 16px;
margin-left: 66px;
}
}
}
}
/*end首頁*/
/*入库菜单*/
.rkpage {
width: 100%;
height: 100vh;
position: relative;
background: #eef1f5;
.rkMuen {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
background: #fff;
border-radius: 10px;
padding: 10px;
margin: 15px;
margin-top: 10px;
.item {
width: 33.3%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.rkico {
width: 30px;
height: 30px;
margin-bottom: 5px;
}
.t1 {
font-size: 14px;
color: #505050;
}
}
}
}
/*end入库菜单*/
/*入库-收货*/
::v-deep .select-wrap {
border: none !important;
width: 100% !important;
height: 19px !important;
}
/*按鈕置灰*/
.disbt {
opacity: 0.5;
}
.shpage {
width: 100%;
height: 100vh;
background: #eef1f5;
position: relative;
overflow: hidden;
// background: pink;
.searchico {
width: 20px;
height: 20px;
margin-left: 10rpx;
}
.sh_gdInfo {
width: 100%;
position: fixed;
top: 67px;
display: flex;
flex-direction: column;
z-index: 11;
.item {
width: 100%;
background: #fff;
position: relative;
.it {
display: flex;
flex-direction: row;
align-items: center;
margin: 0 20px;
padding: 8px 0;
border-bottom: 1px solid #e0e5eb;
input {
flex: 1;
margin: 0 2%;
}
}
.itsp {
justify-content: space-between;
}
.t1,
.t2 {
font-size: 14px;
}
.t2 {
padding-left: 5px;
}
.redtag {
color: #d6366e;
}
}
.item2 {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: 8px 0;
.it2 {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 25%;
.t1 {
font-size: 14px;
color: #222222;
font-weight: bold;
padding-bottom: 2px;
}
.t2 {
font-size: 14px;
color: #717275;
}
.rednum {
color: #f42551;
}
}
}
.itembg2 {
background: #f3f6fa;
.it {
.t1,
.t2 {
color: #bbbdc1 !important;
}
.searchico {
opacity: 0.6;
}
}
}
}
.shlb {
height: 35%;
// background: #D6366E;
position: relative;
margin-top: 66%;
padding: 10px 6px;
overflow-y: auto;
position: relative;
margin: 0 6px;
overflow: hidden;
overflow-y: auto;
.item {
background: #fff;
border-radius: 6px;
margin-bottom: 5px;
padding: 5px;
z-index: 2;
.it {
padding: 0 2px;
display: flex;
flex-direction: column;
border-radius: 10px;
// background: linear-gradient(360deg, #FFFFFF 0%, #EDF3FF 100%);
.txt {
font-size: 12px;
color: #222222;
}
}
}
}
.footbts {
display: flex;
bottom: 0;
width: 100%;
position: fixed;
background: #fff;
padding: 5px 0px;
flex-direction: row;
align-items: center;
justify-content: space-between;
.bt {
width: 50%;
margin: 0 10px;
padding: 10px 0;
border-radius: 10px;
color: #fff;
font-size: 14px;
text-align: center;
}
.bt1 {
background: #f96422;
}
.bt2 {
background: linear-gradient(215deg, #122ae1 10%, #3e67fd 100%);
}
.bt3 {
background: #f5bd08;
}
}
}
/*end入库-收货*/
/*标题栏目*/
.mianheade {
padding: 12px 20px;
display: flex;
flex-direction: row;
align-items: center;
padding-top: 30px;
.blacBackico {
width: 18px;
height: 18px;
}
.pagetitle {
text-align: center;
color: #222222;
font-size: 16px;
font-weight: bold;
margin-left: 38%;
}
}
/*标题栏目2*/
.mianheade2 {
background: url(@/static/img/headbg.png) no-repeat !important;
background-size: 100% 100% !important;
.blacBackico {
width: 25px !important;
height: 25px !important;
}
.pagetitle {
color: #fff !important;
}
}
/*采购上架入库*/
.cgsjrklb {
margin-top: 74%;
height: 30%;
.item {
.it {
.titstr {
font-weight: bold;
color: #222;
}
}
}
.cssj_it {
background: #f3f6fa;
padding: 3px 5px;
border-radius: 6px;
.tlinb {
display: flex;
flex-direction: column;
}
.txtNum {
font-size: 12px;
color: #717275;
display: flex;
align-items: center;
justify-content: space-between;
.tinput {
display: flex;
align-items: center;
flex-direction: row;
.inpt {
width: 100px;
height: 15px;
font-size: 12px;
background: #fff;
margin-left: 5px;
border: 1px solid #d0d7de;
}
}
}
}
}
/*非采购上架入库*/
.f_cgsjrklb {
margin-top: 67.5%;
height: 34%;
}
/*拣货出库*/
.jscklb {
margin-top: 74%;
height: 29%;
.titstr {
border-bottom: 1px dashed #d2d3d5 !important;
padding-bottom: 3px;
margin-bottom: 3px;
}
}
/*快速改箱/装箱*/
.gx_zxpage {
position: relative;
.cxsjdiv {
width: 100%;
background: #eef1f5;
margin-top: 48%;
z-index: 10;
position: relative;
.gxcheckbox {
margin-left: 16px;
}
.checkboxlabel {
margin-bottom: 4px !important;
span {
font-size: 14px;
}
}
}
.f_cgsjrklb {
position: relative;
height: 42%;
z-index: 1;
.titstr {
padding-bottom: 2px;
border-bottom: 1px dashed #d2d3d5 !important;
}
.cssj_it {
background: #fff;
padding-left: 0;
padding-right: 0;
}
}
}
// 整箱移货上架
.zxyhsjpage {
.jscklb {
margin-top: 51%;
height: 43%;
}
}
// 出库回退
.ckhtsjpage {
.f_cgsjrklb {
margin-top: 85%;
height: 23%;
}
}
// 出库回退xj
.ckhtsxjpage {
.f_cgsjrklb {
margin-top: 65%;
height: 35%;
}
}
// 盘点
.pdpage {
.jscklb {
margin-top: 56%;
height: 40%;
}
}
// 个别样式
.inpt1 {
font-size: 14px;
color: #222;
}
.inpt2 {
color: #bbbdc1;
}
.inptbordred {
border: 1px solid red !important;
}
.it50 {
width: 50% !important;
}
.fgx {
border-left: 1px solid #e0e5eb;
height: 11px;
margin: 0 16px;
display: inline-flex;
} //分割线
.txtflexnum {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.ckhtit {
margin-bottom: 5px;
}
.gxzxlb {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.redtxt {
.txt {
color: #f42551 !important;
}
}
.greentxt {
.txt {
color: #1bc9b0 !important;
}
}
.tpleft {
padding-left: 8px;
}
.deletico {
width: 16px;
height: 16px;
}
.xlfeview {
position: absolute !important;
top: 0 !important;
z-index: 10;
}
.wwselectit {
margin-left: 20rpx !important;
flex: 1 !important;
}
.inpt {
font-size: 12px;
}
.ckjhTxt {
background: #f3f6fa;
padding: 2px;
border: 1px solid #d0d7de;
border-radius: 6px;
margin-left: 5px;
min-width: 20px;
}
.cktinput_jh {
border: 1px solid #d0d7de;
border-radius: 6px;
padding: 2px;
}
.oldxlhboxct {
width: 100%;
height: 60rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.tkinput {
width: 93%;
font-size: 12px;
margin-top: 5px;
padding: 2px 5px !important;
}
.tkvi {
font-size: 14px;
display: flex;
width: 100%;
flex-direction: column;
align-items: flex-start;
}
.disInput {
background: #edf0f5 !important;
}
.shpage {
.u-input {
// padding: 0;
height: 20px;
}
}
.ibgt {
margin-top: 5px !important;
background: #f3f6fa !important;
border-radius: 4px !important;
padding: 5px 10px 5px 10px !important;
.txt {
color: #505050 !important;
}
}
.pdpage {
position: relative;
::v-deep .u-popup__content {
margin-top: -30% !important;
}
}
.orgicomain {
font-size: 10px;
color: orange;
position: absolute;
top: 0;
left: 35%;
display: flex;
flex-direction: row;
align-items: center;
A .orgico {
width: 12px;
height: 12px;
border-radius: 12px;
border: 1px solid orange;
text-align: center;
line-height: 12px;
margin-right: 5px;
}
}
.icinfo {
width: 22px !important;
}
.boxtkct {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
overflow-y: auto;
max-height: 60vh;
.c_item {
width: 100%;
text-align: center;
margin-bottom: 10rpx;
}
}
.boxtkct1 {
display: flex;
flex-direction: column;
justify-content: start;
width: 100%;
.t1 {
font-size: 36rpx !important;
color: #333;
}
.cws {
display: flex;
flex-wrap: wrap;
}
.cwit {
display: flex;
flex-direction: column;
font-weight: bold;
.krcwname {
font-size: 36rpx !important;
color: #333;
margin-right: 25rpx;
}
}
}
.txtflexnum {
.pl {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
margin-top: 4px;
margin-bottom: 4px;
}
}
.mxcwdiv {
display: flex;
flex-direction: row;
align-items: center;
max-width: 48%;
background: #eef1f5;
margin-left: 2%;
padding: 0 4px;
.cwhitzs {
width: 96%;
margin: 0 10rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.ntxtcolor{
color: #505050 !important;
}
.nbtxt{
font-weight: blod;
}
.nwemxflex{
display: flex;
flex-direction: row;
align-items: center;
margin: 6rpx 0;
.fgline{
margin: 0 30rpx;
background: #BBBDC1;
width: 1px;
height: 24rpx;
}
.txt{
color: #505050 !important;
}
}
.nslbzflex{
margin-bottom: 8rpx;
.n-sl-bz{
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.tinput{
width: 48% !important;
}
}
.remaktinpt{
background-color: #fff;
font-size: 12px;
border: 1px solid #ccc;
padding:5px 10px;
border-radius: 6px;
}

10
uni.promisify.adaptor.js Normal file
View File

@@ -0,0 +1,10 @@
uni.addInterceptor({
returnValue (res) {
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
return res;
}
return new Promise((resolve, reject) => {
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1]));
});
},
});

82
uni.scss Normal file
View File

@@ -0,0 +1,82 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;
*{margin:0;padding:0;}
@import '@/uni_modules/uview-ui/theme.scss';
/*wms公共样式*/
@import '@/static/public.scss';
/*入库主页面*/

View File

@@ -0,0 +1,22 @@
## 1.0.102022-10-19
- 修改文档,更改为不兼容小程序(存在下拉框滑动会自动关闭的问题,后期改进后再兼容,若各位有好的解决方法的话欢迎评论)
## 1.0.92022-07-28
- 完善是否创建新条目功能,并将默认值改为允许
## 1.0.82022-07-26
- 新增禁用选项和是否创建新条目功能新增disabledColor和isAllowCreate属性
## 1.0.72022-05-05
- 解决传入JSON数组后在模糊匹配项中进行选择@select事件返回值为undefined且报错的问题
## 1.0.62022-03-24
- 新增@select事件
## 1.0.52022-03-22
- 修改文档
## 1.0.42022-03-18
- 新增isJSON和keyName属性candidates支持JSON数组格式
## 1.0.32022-03-01
- 调整为uni_modules目录规范
## 1.0.22022-03-01
- 基于官方uni-combox组件解决选择后再次选择不展示全部选项的问题同时新增选中项默认的文字和背景颜色也可自定义进行样式覆盖
## 1.0.12022-03-01
-
## 1.0.02022-03-01
- 无

View File

@@ -0,0 +1,379 @@
<template>
<view class="superwei-combox" :class="border ? '' : 'superwei-combox__no-border'">
<view v-if="label" class="superwei-combox__label" :style="labelStyle">
<text>{{label}}</text>
</view>
<view class="superwei-combox__input-box">
<input class="superwei-combox__input" type="text" :placeholder="placeholder"
placeholder-class="superwei-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus"
@blur="onBlur" />
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
</uni-icons>
</view>
<view class="superwei-combox__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="superwei-combox__selector-scroll">
<view class="superwei-combox__selector-empty" v-if="filterCandidatesLength === 0">
<text>{{emptyTips}}</text>
</view>
<view class="superwei-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index">
<template v-if="(isJSON?(item.disabled?true:false):false)">
<text
:style="'color:'+disabledColor+';cursor: not-allowed;'">{{isJSON?item[keyName]?item[keyName]:'字段'+keyName+'不存在':item}}</text>
</template>
<template v-else>
<text @click="onSelectorClick(index)"
:style="(isJSON?item[keyName]?item[keyName]==inputVal:false:item==inputVal)?'font-weight: bold;background-color: '+selectedBackground+';color: '+selectedColor:''">{{isJSON?item[keyName]?item[keyName]:'字段'+keyName+'不存在':item}}</text>
</template>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
/**
* Combox 组合输入框
* @description 组合输入框一般用于既可以输入也可以选择的场景
* @property {String} label 左侧文字
* @property {String} labelWidth 左侧内容宽度
* @property {String} placeholder 输入框占位符
* @property {Array} candidates 候选项列表
* @property {String} emptyTips 筛选结果为空时显示的文字
* @property {String} value 组合框的值
* @property {String} selectedBackground 选中项背景颜色
* @property {String} selectedColor 选中项文字颜色
* @property {Boolean} isJSON 是否是json数组
* @property {String} keyName json数组显示的字段值
* @property {String} disabledColor 禁用项文字颜色
* @property {Boolean} isAllowCreate 是否允许用户创建新条目
*/
export default {
name: 'superweiCombox',
emits: ['input', 'update:modelValue', 'select'],
props: {
isAllowCreate: {
type: Boolean,
default: true
},
disabledColor: {
type: String,
default: '#ababac'
},
isJSON: {
type: Boolean,
default: false
},
keyName: {
type: String,
default: ''
},
selectedBackground: {
type: String,
default: '#f5f7fa'
},
selectedColor: {
type: String,
default: '#409eff'
},
border: {
type: Boolean,
default: true
},
label: {
type: String,
default: ''
},
labelWidth: {
type: String,
default: 'auto'
},
placeholder: {
type: String,
default: ''
},
candidates: {
type: Array,
default () {
return []
}
},
emptyTips: {
type: String,
default: '无匹配项'
},
// #ifndef VUE3
value: {
type: [String, Number],
default: ''
},
// #endif
// #ifdef VUE3
modelValue: {
type: [String, Number],
default: ''
},
// #endif
},
data() {
return {
isInput: false,
showSelector: false,
isSelector: false,
inputVal: ''
}
},
computed: {
labelStyle() {
if (this.labelWidth === 'auto') {
return ""
}
return `width: ${this.labelWidth}`
},
filterCandidates() {
if (this.isInput) {
if (this.isJSON) {
return this.candidates.filter((item) => {
return item[this.keyName].toString().indexOf(this.inputVal) > -1
})
} else {
return this.candidates.filter((item) => {
return item.toString().indexOf(this.inputVal) > -1
})
}
} else {
return this.candidates
}
},
filterCandidatesLength() {
return this.filterCandidates.length
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
this.inputVal = newVal
this.isInput = true
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.inputVal = newVal
this.isInput = true
},
immediate: true
},
// #endif
},
methods: {
toggleSelector() {
this.showSelector = !this.showSelector
this.isInput = false
},
onFocus() {
this.showSelector = true
this.isInput = false
},
onChange() {
setTimeout(() => {
this.showSelector = false
this.isInput = false
}, 200)
},
onBlur() {
if (!this.isInput) {
this.onChange()
} else {
if (this.inputVal && !this.isAllowCreate) {
let index = this.candidates.findIndex((item) => {
if (this.isJSON) {
return item[this.keyName].toString() == this.inputVal && !item.disabled
} else {
return item.toString() == this.inputVal
}
})
if (index == -1) {
if (this.filterCandidatesLength > 0) {
setTimeout(() => {
this.showSelector = false
this.isInput = false
if (!this.isSelector) {
this.inputVal = ''
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
}
}, 200)
this.isSelector = false
} else {
this.showSelector = false
this.isInput = false
this.inputVal = ''
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
}
} else {
this.onChange()
}
} else {
this.onChange()
}
}
},
onSelectorClick(index) {
let item = this.filterCandidates[index]
if (this.isJSON) {
this.inputVal = item[this.keyName]
} else {
this.inputVal = item
}
this.showSelector = false
this.isSelector = true
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
this.$emit('select', item)
},
onInput() {
setTimeout(() => {
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
})
}
}
}
</script>
<style lang="scss" scoped>
.superwei-combox {
font-size: 14px;
border: 1px solid #DCDFE6;
border-radius: 4px;
padding: 6px 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// height: 40px;
flex-direction: row;
align-items: center;
// border-bottom: solid 1px #DDDDDD;
}
.superwei-combox__label {
font-size: 16px;
line-height: 22px;
padding-right: 10px;
color: #999999;
}
.superwei-combox__input-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
cursor: pointer;
}
.superwei-combox__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.superwei-combox__input-plac {
font-size: 14px;
color: #ccc; //placeholder-style="color:#FFFFFF"
}
.superwei-combox__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2;
padding: 4px 0;
}
.superwei-combox__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
.superwei-combox__selector-empty,
.superwei-combox__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 36px;
font-size: 14px;
text-align: center;
// border-bottom: solid 1px #DDDDDD;
padding: 0px 0px;
}
.superwei-combox__selector-empty text,
.superwei-combox__selector-item text {
width: 100%;
}
.superwei-combox__selector-item:hover {
background-color: #f9f9f9;
}
.superwei-combox__selector-empty:last-child,
.superwei-combox__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
// picker 弹出层通用的指示小三角
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.superwei-combox__no-border {
border: none;
}
</style>

View File

@@ -0,0 +1,89 @@
{
"id": "superwei-combox",
"displayName": "superwei-combox 组合框",
"version": "1.0.10",
"description": "下拉搜索选择组合框基于官方uni-combox组件解决选择后再次选择不展示全部选项的问题支持模糊搜索和JSON数组格式可设置选中项文字和背景颜色若使用请一定下载uni_modules版本",
"keywords": [
"combox",
"组合框",
"select",
"下拉选择",
"搜索选择"
],
"repository": "",
"engines": {
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "u",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "u",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,104 @@
## 基本用法
在 ``template`` 中使用组件
```html
<template>
<view class="content">
<span class="title">非JSON数组模式</span>
<superwei-combox :candidates="candidates" placeholder="请选择或输入" v-model="inputValue" @input="input"
@select="select"></superwei-combox>
<span class="title">JSON数组模式</span>
<superwei-combox :candidates="candidates_json" :isJSON="true" keyName="name" placeholder="请选择或输入"
v-model="inputValue_json" @input="input_json" @select="select_json"></superwei-combox>
</view>
</template>
<script>
export default {
data() {
return {
inputValue: '',
candidates: ['选项一', '选项二', '选项三', '选项四', '选项五', '选项六', '...'],
inputValue_json: '',
candidates_json: [{
id: '1',
name: '选项一'
}, {
id: '2',
name: '选项二',
disabled: true // 单独设置disabled后即可禁用该选项
}, {
id: '3',
name: '选项三'
}, {
id: '4',
name: '选项四'
}, {
id: '5',
name: '选项五',
disabled: true // 单独设置disabled后即可禁用该选项
}, {
id: '6',
name: '...'
}]
}
},
methods: {
input(e) {
console.log(e) // 选项一
},
select(e) {
console.log(e) // 选项一
},
input_json(e) {
console.log(e) // 选项一
},
select_json(e) {
console.log(e) // {id: '1',name: '选项一'}
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.title {
margin-top: 20px;
}
</style>
```
## API
### Combox Props
|属性名 |类型 |默认值 |说明 |
|:-: |:-: |:-: |:-: |
|label |String |- |标签文字 |
|value |String |- |combox的值 |
|labelWidth |String |auto |标签宽度,有单位字符串,如:'100px' |
|placeholder|String |- |输入框占位符 |
|candidates |Array/String |[] |候选字段 |
|emptyTips |String |无匹配项 |无匹配项时的提示语 |
|selectedBackground |String |#f5f7fa |选中项背景颜色 |
|selectedColor |String |#409eff |选中项文字颜色 |
|isJSON |Boolean |false |候选字段是否是json数组 |
|keyName |String |- |json数组显示的字段值 |
|disabledColor |String |#ababac |禁用项文字颜色 |
|isAllowCreate |Boolean |true |是否允许用户创建新条目 |
### Combox Events
|事件称名 |说明 |返回值 |
|:-: |:-: |:-: |
|@input |combox输入事件 |返回combox输入值|
|@select|combox选择事件 |返回combox选项值|

View File

@@ -0,0 +1,39 @@
## 1.0.82024-03-28
- 修复 在vue2下:style动态绑定导致编译失败的bug
## 1.0.72024-01-20
- 修复 长文本回显超过容器的bug超过容器部分显示省略号
## 1.0.62023-04-12
- 修复 微信小程序点击时会改变背景颜色的 bug
## 1.0.52023-02-03
- 修复 禁用时会显示清空按钮
## 1.0.42023-02-02
- 优化 查询条件短期内多次变更只查询最后一次变更后的结果
- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue
## 1.0.32023-01-16
- 修复 不关联服务空间报错的问题
## 1.0.22023-01-14
- 新增 属性 `format` 可用于格式化显示选项内容
## 1.0.12022-12-06
- 修复 当where变化时数据不会自动更新的问题
## 0.1.92022-09-05
- 修复 微信小程序下拉框出现后选择会点击到蒙板后面的输入框
## 0.1.82022-08-29
- 修复 点击的位置不准确
## 0.1.72022-08-12
- 新增 支持 disabled 属性
## 0.1.62022-07-06
- 修复 pc端宽度异常的bug
## 0.1.5
- 修复 pc端宽度异常的bug
## 0.1.42022-07-05
- 优化 显示样式
## 0.1.32022-06-02
- 修复 localdata 赋值不生效的 bug
- 新增 支持 uni.scss 修改颜色
- 新增 支持选项禁用(数据选项设置 disabled: true 即禁用)
## 0.1.22022-05-08
- 修复 当 value 为 0 时选择不生效的 bug
## 0.1.12022-05-07
- 新增 记住上次的选项(仅 collection 存在时有效)
## 0.1.02022-04-22
- 初始化

View File

@@ -0,0 +1,562 @@
<template>
<view class="uni-stat__select">
<span v-if="label" class="uni-label-text hide-on-phone">{{label + ''}}</span>
<view class="uni-stat-box" :class="{'uni-stat__actived': current}">
<view class="uni-select" :class="{'uni-select--disabled':disabled}">
<view class="uni-select__input-box" @click="toggleSelector">
<view v-if="current" class="uni-select__input-text">{{textShow}}</view>
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
<view v-if="current && clear && !disabled" @click.stop="clearVal">
<uni-icons type="clear" color="#c0c4cc" size="24" />
</view>
<view v-else>
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
</view>
</view>
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
<view class="uni-select__selector" :style="getOffsetByPlacement" v-if="showSelector">
<view :class="placement=='bottom'?'uni-popper__arrow_bottom':'uni-popper__arrow_top'"></view>
<scroll-view scroll-y="true" class="uni-select__selector-scroll">
<view class="uni-select__selector-empty" v-if="mixinDatacomResData.length === 0">
<text>{{emptyTips}}</text>
</view>
<view v-else class="uni-select__selector-item" v-for="(item,index) in mixinDatacomResData" :key="index"
@click="change(item)">
<text :class="{'uni-select__selector__disabled': item.disable}">{{formatItemName(item)}}</text>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* DataChecklist 数据选择器
* @description 通过数据渲染的下拉框组件
* @tutorial https://uniapp.dcloud.io/component/uniui/uni-data-select
* @property {String} value 默认值
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
* @property {Boolean} clear 是否可以清空已选项
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
* @property {String} label 左侧标题
* @property {String} placeholder 输入框的提示文字
* @property {Boolean} disabled 是否禁用
* @property {String} placement 弹出位置
* @value top 顶部弹出
* @value bottom 底部弹出default)
* @event {Function} change 选中发生变化触发
*/
export default {
name: "uni-data-select",
mixins: [uniCloud.mixinDatacom || {}],
props: {
localdata: {
type: Array,
default () {
return []
}
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
label: {
type: String,
default: ''
},
placeholder: {
type: String,
default: '请选择'
},
emptyTips: {
type: String,
default: '无选项'
},
clear: {
type: Boolean,
default: true
},
defItem: {
type: Number,
default: 0
},
disabled: {
type: Boolean,
default: false
},
// 格式化输出 用法 field="_id as value, version as text, uni_platform as label" format="{label} - {text}"
format: {
type: String,
default: ''
},
placement: {
type: String,
default: 'bottom'
}
},
data() {
return {
showSelector: false,
current: '',
mixinDatacomResData: [],
apps: [],
channels: [],
cacheKey: "uni-data-select-lastSelectedValue",
};
},
created() {
this.debounceGet = this.debounce(() => {
this.query();
}, 300);
if (this.collection && !this.localdata.length) {
this.debounceGet();
}
},
computed: {
typePlaceholder() {
const text = {
'opendb-stat-app-versions': '版本',
'opendb-app-channels': '渠道',
'opendb-app-list': '应用'
}
const common = this.placeholder
const placeholder = text[this.collection]
return placeholder ?
common + placeholder :
common
},
valueCom() {
// #ifdef VUE3
return this.modelValue;
// #endif
// #ifndef VUE3
return this.value;
// #endif
},
textShow() {
// 长文本显示
let text = this.current;
if (text.length > 10) {
return text.slice(0, 25) + '...';
}
return text;
},
getOffsetByPlacement() {
switch (this.placement) {
case 'top':
return "bottom:calc(100% + 12px);";
case 'bottom':
return "top:calc(100% + 12px);";
}
}
},
watch: {
localdata: {
immediate: true,
handler(val, old) {
if (Array.isArray(val) && old !== val) {
this.mixinDatacomResData = val
}
}
},
valueCom(val, old) {
this.initDefVal()
},
mixinDatacomResData: {
immediate: true,
handler(val) {
if (val.length) {
this.initDefVal()
}
}
},
},
methods: {
debounce(fn, time = 100) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, time)
}
},
// 执行数据库查询
query() {
this.mixinDatacomEasyGet();
},
// 监听查询条件变更事件
onMixinDatacomPropsChange() {
if (this.collection) {
this.debounceGet();
}
},
initDefVal() {
let defValue = ''
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
defValue = this.valueCom
} else {
let strogeValue
if (this.collection) {
strogeValue = this.getCache()
}
if (strogeValue || strogeValue === 0) {
defValue = strogeValue
} else {
let defItem = ''
if (this.defItem > 0 && this.defItem <= this.mixinDatacomResData.length) {
defItem = this.mixinDatacomResData[this.defItem - 1].value
}
defValue = defItem
}
if (defValue || defValue === 0) {
this.emit(defValue)
}
}
const def = this.mixinDatacomResData.find(item => item.value === defValue)
this.current = def ? this.formatItemName(def) : ''
},
/**
* @param {[String, Number]} value
* 判断用户给的 value 是否同时为禁用状态
*/
isDisabled(value) {
let isDisabled = false;
this.mixinDatacomResData.forEach(item => {
if (item.value === value) {
isDisabled = item.disable
}
})
return isDisabled;
},
clearVal() {
this.emit('')
if (this.collection) {
this.removeCache()
}
},
change(item) {
if (!item.disable) {
this.showSelector = false
this.current = this.formatItemName(item)
this.emit(item.value)
}
},
emit(val) {
this.$emit('input', val)
this.$emit('update:modelValue', val)
this.$emit('change', val)
if (this.collection) {
this.setCache(val);
}
},
toggleSelector() {
if (this.disabled) {
return
}
this.showSelector = !this.showSelector
},
formatItemName(item) {
let {
text,
value,
channel_code
} = item
channel_code = channel_code ? `(${channel_code})` : ''
if (this.format) {
// 格式化输出
let str = "";
str = this.format;
for (let key in item) {
str = str.replace(new RegExp(`{${key}}`, "g"), item[key]);
}
return str;
} else {
return this.collection.indexOf('app-list') > 0 ?
`${text}(${value})` :
(
text ?
text :
`未命名${channel_code}`
)
}
},
// 获取当前加载的数据
getLoadData() {
return this.mixinDatacomResData;
},
// 获取当前缓存key
getCurrentCacheKey() {
return this.collection;
},
// 获取缓存
getCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
return cacheData[name];
},
// 设置缓存
setCache(value, name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
cacheData[name] = value;
uni.setStorageSync(this.cacheKey, cacheData);
},
// 删除缓存
removeCache(name = this.getCurrentCacheKey()) {
let cacheData = uni.getStorageSync(this.cacheKey) || {};
delete cacheData[name];
uni.setStorageSync(this.cacheKey, cacheData);
},
}
}
</script>
<style lang="scss">
$uni-base-color: #6a6a6a !default;
$uni-main-color: #333 !default;
$uni-secondary-color: #909399 !default;
$uni-border-3: #e5e5e5;
/* #ifndef APP-NVUE */
@media screen and (max-width: 500px) {
.hide-on-phone {
display: none;
}
}
/* #endif */
.uni-stat__select {
display: flex;
align-items: center;
// padding: 15px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
width: 100%;
flex: 1;
box-sizing: border-box;
}
.uni-stat-box {
width: 100%;
flex: 1;
}
.uni-stat__actived {
width: 100%;
flex: 1;
// outline: 1px solid #2979ff;
}
.uni-label-text {
font-size: 14px;
font-weight: bold;
color: $uni-base-color;
margin: auto 0;
margin-right: 5px;
}
.uni-select {
font-size: 14px;
border: 1px solid $uni-border-3;
box-sizing: border-box;
border-radius: 4px;
padding: 0 5px;
padding-left: 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
user-select: none;
/* #endif */
flex-direction: row;
align-items: center;
border-bottom: solid 1px $uni-border-3;
width: 100%;
flex: 1;
height: 35px;
&--disabled {
background-color: #f5f7fa;
cursor: not-allowed;
}
}
.uni-select__label {
font-size: 16px;
// line-height: 22px;
height: 35px;
padding-right: 10px;
color: $uni-secondary-color;
}
.uni-select__input-box {
height: 35px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-select__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-select__input-plac {
font-size: 14px;
color: $uni-secondary-color;
}
.uni-select__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 3;
padding: 4px 0;
}
.uni-select__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
/* #ifdef H5 */
@media (min-width: 768px) {
.uni-select__selector-scroll {
max-height: 600px;
}
}
/* #endif */
.uni-select__selector-empty,
.uni-select__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 35px;
font-size: 14px;
text-align: center;
/* border-bottom: solid 1px $uni-border-3; */
padding: 0px 10px;
}
.uni-select__selector-item:hover {
background-color: #f9f9f9;
}
.uni-select__selector-empty:last-child,
.uni-select__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
.uni-select__selector__disabled {
opacity: 0.4;
cursor: default;
}
/* picker 弹出层通用的指示小三角 */
.uni-popper__arrow_bottom,
.uni-popper__arrow_bottom::after,
.uni-popper__arrow_top,
.uni-popper__arrow_top::after,
{
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow_bottom {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow_bottom::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-popper__arrow_top {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
bottom: -6px;
left: 10%;
margin-right: 3px;
border-bottom-width: 0;
border-top-color: #EBEEF5;
}
.uni-popper__arrow_top::after {
content: " ";
bottom: 1px;
margin-left: -6px;
border-bottom-width: 0;
border-top-color: #fff;
}
.uni-select__input-text {
// width: 280px;
width: 100%;
color: $uni-main-color;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
overflow: hidden;
}
.uni-select__input-placeholder {
color: $uni-base-color;
font-size: 12px;
}
.uni-select--mask {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 2;
}
</style>

View File

@@ -0,0 +1,86 @@
{
"id": "uni-data-select",
"displayName": "uni-data-select 下拉框选择器",
"version": "1.0.8",
"description": "通过数据驱动的下拉框选择器",
"keywords": [
"uni-ui",
"select",
"uni-data-select",
"下拉框",
"下拉选"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.1.1"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-load-more"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "u",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
## DataSelect 下拉框选择器
> **组件名uni-data-select**
> 代码块: `uDataSelect`
当选项过多时,使用下拉菜单展示并选择内容
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-select)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@@ -0,0 +1,168 @@
## 2.2.382024-10-15
- 修复 微信小程序中的getSystemInfo警告
## 2.2.372024-10-12
- 修复 微信小程序中的getSystemInfo警告
## 2.2.362024-10-12
- 修复 微信小程序中的getSystemInfo警告
## 2.2.352024-09-21
- 修复 没有选中日期时点击确定直接报错的Bug [详情](https://ask.dcloud.net.cn/question/198168)
## 2.2.342024-04-24
- 新增 日期点击事件,在点击日期时会触发该事件。
## 2.2.332024-04-15
- 修复 抖音小程序事件传递失效bug
## 2.2.322024-02-20
- 修复 日历的close事件触发异常的bug [详情](https://github.com/dcloudio/uni-ui/issues/844)
## 2.2.312024-02-20
- 修复 h5平台 右边日历的月份默认+1的bug [详情](https://github.com/dcloudio/uni-ui/issues/841)
## 2.2.302024-01-31
- 修复 隐藏“秒”时在IOS15及以下版本时出现 结束时间在开始时间之前 的bug [详情](https://github.com/dcloudio/uni-ui/issues/788)
## 2.2.292024-01-20
- 新增 show事件弹窗弹出时触发该事件 [详情](https://github.com/dcloudio/uni-app/issues/4694)
## 2.2.282024-01-18
- 去除 noChange事件当进行日期范围选择时若只选了一天则开始结束日期都为同一天 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.272024-01-10
- 优化 增加noChange事件当进行日期范围选择时若有空值则触发该事件 [详情](https://github.com/dcloudio/uni-ui/issues/815)
## 2.2.262024-01-08
- 修复 字节小程序时间选择范围器失效问题 [详情](https://github.com/dcloudio/uni-ui/issues/834)
## 2.2.252023-10-18
- 修复 PC端初次修改时间开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
## 2.2.242023-06-02
- 修复 部分情况修改时间开始、结束时间显示异常的Bug [详情](https://ask.dcloud.net.cn/question/171146)
- 优化 当前月可以选择上月、下月的日期的Bug
## 2.2.232023-05-02
- 修复 部分情况修改时间开始时间未更新的Bug [详情](https://github.com/dcloudio/uni-ui/issues/737)
- 修复 部分平台及设备第一次点击无法显示弹框的Bug
- 修复 ios 日期格式未补零显示及使用异常的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.222023-03-30
- 修复 日历 picker 修改年月后自动选中当月1日的Bug [详情](https://ask.dcloud.net.cn/question/165937)
- 修复 小程序端 低版本 ios NaN的Bug [详情](https://ask.dcloud.net.cn/question/162979)
## 2.2.212023-02-20
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
## 2.2.202023-02-17
- 优化 值为空依然选中当天问题
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
- 优化 字节小程序日期时间范围选择底部日期换行的Bug
## 2.2.192023-02-09
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
## 2.2.182023-02-08
- 修复 移动端范围选择change事件触发异常的Bug [详情](https://github.com/dcloudio/uni-ui/issues/684)
- 优化 PC端输入日期格式错误时返回当前日期时间
- 优化 PC端输入日期时间超出 start、end 限制的Bug
- 优化 移动端日期时间范围用法时间展示不完整问题
## 2.2.172023-02-04
- 修复 小程序端绑定 Date 类型报错的Bug [详情](https://github.com/dcloudio/uni-ui/issues/679)
- 修复 vue3 time-picker 无法显示绑定时分秒的Bug
## 2.2.162023-02-02
- 修复 字节小程序报错的Bug
## 2.2.152023-02-02
- 修复 某些情况切换月份错误的Bug
## 2.2.142023-01-30
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/162033)
## 2.2.132023-01-10
- 修复 多次加载组件造成内存占用的Bug
## 2.2.122022-12-01
- 修复 vue3 下 i18n 国际化初始值不正确的Bug
## 2.2.112022-09-19
- 修复 支付宝小程序样式错乱的Bug [详情](https://github.com/dcloudio/uni-app/issues/3861)
## 2.2.102022-09-19
- 修复 反向选择日期范围日期显示异常的Bug [详情](https://ask.dcloud.net.cn/question/153401?item_id=212892&rf=false)
## 2.2.92022-09-16
- 可以使用 uni-scss 控制主题色
## 2.2.82022-09-08
- 修复 close事件无效的Bug
## 2.2.72022-09-05
- 修复 移动端 maskClick 无效的Bug [详情](https://ask.dcloud.net.cn/question/140824)
## 2.2.62022-06-30
- 优化 组件样式调整了组件图标大小、高度、颜色等与uni-ui风格保持一致
## 2.2.52022-06-24
- 修复 日历顶部年月及底部确认未国际化的Bug
## 2.2.42022-03-31
- 修复 Vue3 下动态赋值,单选类型未响应的Bug
## 2.2.32022-03-28
- 修复 Vue3 下动态赋值未响应的Bug
## 2.2.22021-12-10
- 修复 clear-icon 属性在小程序平台不生效的Bug
## 2.2.12021-12-10
- 修复 日期范围选在小程序平台必须多点击一次才能取消选中状态的Bug
## 2.2.02021-11-19
- 优化 组件UI并提供设计资源 [详情](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移 [https://uniapp.dcloud.io/component/uniui/uni-datetime-picker](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
## 2.1.52021-11-09
- 新增 提供组件设计资源,组件样式调整
## 2.1.42021-09-10
- 修复 hide-second 在移动端的Bug
- 修复 单选赋默认值时赋值日期未高亮的Bug
- 修复 赋默认值时移动端未正确显示时间的Bug
## 2.1.32021-09-09
- 新增 hide-second 属性,支持只使用时分,隐藏秒
## 2.1.22021-09-03
- 优化 取消选中时(范围选)直接开始下一次选择, 避免多点一次
- 优化 移动端支持清除按钮,同时支持通过 ref 调用组件的 clear 方法
- 优化 调整字号大小,美化日历界面
- 修复 因国际化导致的 placeholder 失效的Bug
## 2.1.12021-08-24
- 新增 支持国际化
- 优化 范围选择器在 pc 端过宽的问题
## 2.1.02021-08-09
- 新增 适配 vue3
## 2.0.192021-08-09
- 新增 支持作为 uni-forms 子组件相关功能
- 修复 在 uni-forms 中使用时,选择时间报 NAN 错误的Bug
## 2.0.182021-08-05
- 修复 type 属性动态赋值无效的Bug
- 修复 ‘确认’按钮被 tabbar 遮盖 bug
- 修复 组件未赋值时范围选左、右日历相同的Bug
## 2.0.172021-08-04
- 修复 范围选未正确显示当前值的Bug
- 修复 h5 平台(移动端)报错 'cale' of undefined 的Bug
## 2.0.162021-07-21
- 新增 return-type 属性支持返回 date 日期对象
## 2.0.152021-07-14
- 修复 单选日期类型初始赋值后不在当前日历的Bug
- 新增 clearIcon 属性,显示框的清空按钮可配置显示隐藏(仅 pc 有效)
- 优化 移动端移除显示框的清空按钮,无实际用途
## 2.0.142021-07-14
- 修复 组件赋值为空界面未更新的Bug
- 修复 start 和 end 不能动态赋值的Bug
- 修复 范围选类型用户选择后再次选择右侧日历结束日期显示不正确的Bug
## 2.0.132021-07-08
- 修复 范围选择不能动态赋值的Bug
## 2.0.122021-07-08
- 修复 范围选择的初始时间在一个月内时造成无法选择的bug
## 2.0.112021-07-08
- 优化 弹出层在超出视窗边缘定位不准确的问题
## 2.0.102021-07-08
- 修复 范围起始点样式的背景色与今日样式的字体前景色融合导致日期字体看不清的Bug
- 优化 弹出层在超出视窗边缘被遮盖的问题
## 2.0.92021-07-07
- 新增 maskClick 事件
- 修复 特殊情况日历 rpx 布局错误的Bugrpx -> px
- 修复 范围选择时清空返回值不合理的bug['', ''] -> []
## 2.0.82021-07-07
- 新增 日期时间显示框支持插槽
## 2.0.72021-07-01
- 优化 添加 uni-icons 依赖
## 2.0.62021-05-22
- 修复 图标在小程序上不显示的Bug
- 优化 重命名引用组件,避免潜在组件命名冲突
## 2.0.52021-05-20
- 优化 代码目录扁平化
## 2.0.42021-05-12
- 新增 组件示例地址
## 2.0.32021-05-10
- 修复 ios 下不识别 '-' 日期格式的Bug
- 优化 pc 下弹出层添加边框和阴影
## 2.0.22021-05-08
- 修复 在 admin 中获取弹出层定位错误的bug
## 2.0.12021-05-08
- 修复 type 属性向下兼容,默认值从 date 变更为 datetime
## 2.0.02021-04-30
- 支持日历形式的日期+时间的范围选择
> 注意此版本不向后兼容不再支持单独时间选择type=time及相关的 hide-second 属性(时间选可使用内置组件 picker
## 1.0.62021-03-18
- 新增 hide-second 属性,时间支持仅选择时、分
- 修复 选择跟显示的日期不一样的Bug
- 修复 chang事件触发2次的Bug
- 修复 分、秒 end 范围错误的Bug
- 优化 更好的 nvue 适配

View File

@@ -0,0 +1,177 @@
<template>
<view class="uni-calendar-item__weeks-box" :class="{
'uni-calendar-item--disable':weeks.disable,
'uni-calendar-item--before-checked-x':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked-x':weeks.afterMultiple,
}" @click="choiceDate(weeks)" @mouseenter="handleMousemove(weeks)">
<view class="uni-calendar-item__weeks-box-item" :class="{
'uni-calendar-item--checked':calendar.fullDate === weeks.fullDate && (calendar.userChecked || !checkHover),
'uni-calendar-item--checked-range-text': checkHover,
'uni-calendar-item--before-checked':weeks.beforeMultiple,
'uni-calendar-item--multiple': weeks.multiple,
'uni-calendar-item--after-checked':weeks.afterMultiple,
'uni-calendar-item--disable':weeks.disable,
}">
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
</view>
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
</view>
</template>
<script>
export default {
props: {
weeks: {
type: Object,
default () {
return {}
}
},
calendar: {
type: Object,
default: () => {
return {}
}
},
selected: {
type: Array,
default: () => {
return []
}
},
checkHover: {
type: Boolean,
default: false
}
},
methods: {
choiceDate(weeks) {
this.$emit('change', weeks)
},
handleMousemove(weeks) {
this.$emit('handleMouse', weeks)
}
}
}
</script>
<style lang="scss" >
$uni-primary: #007aff !default;
.uni-calendar-item__weeks-box {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
margin: 1px 0;
position: relative;
}
.uni-calendar-item__weeks-box-text {
font-size: 14px;
// font-family: Lato-Bold, Lato;
font-weight: bold;
color: darken($color: $uni-primary, $amount: 40%);
}
.uni-calendar-item__weeks-box-item {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
width: 40px;
height: 40px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.uni-calendar-item__weeks-box-circle {
position: absolute;
top: 5px;
right: 5px;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #dd524d;
}
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
cursor: default;
}
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
color: #D1D1D1;
}
.uni-calendar-item--today {
position: absolute;
top: 10px;
right: 17%;
background-color: #dd524d;
width:6px;
height: 6px;
border-radius: 50%;
}
.uni-calendar-item--extra {
color: #dd524d;
opacity: 0.8;
}
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
background-color: $uni-primary;
border-radius: 50%;
box-sizing: border-box;
border: 3px solid #fff;
}
.uni-calendar-item--checked .uni-calendar-item--checked-text {
color: #fff;
}
.uni-calendar-item--multiple .uni-calendar-item--checked-range-text {
color: #333;
}
.uni-calendar-item--multiple {
background-color: #F6F7FC;
// color: #fff;
}
.uni-calendar-item--multiple .uni-calendar-item--before-checked,
.uni-calendar-item--multiple .uni-calendar-item--after-checked {
background-color: $uni-primary;
border-radius: 50%;
box-sizing: border-box;
border: 3px solid #F6F7FC;
}
.uni-calendar-item--before-checked .uni-calendar-item--checked-text,
.uni-calendar-item--after-checked .uni-calendar-item--checked-text {
color: #fff;
}
.uni-calendar-item--before-checked-x {
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
box-sizing: border-box;
background-color: #F6F7FC;
}
.uni-calendar-item--after-checked-x {
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
background-color: #F6F7FC;
}
</style>

View File

@@ -0,0 +1,947 @@
<template>
<view class="uni-calendar" @mouseleave="leaveCale">
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
@click="maskClick"></view>
<view v-if="insert || show" class="uni-calendar__content"
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
<view class="uni-calendar__header-btn uni-calendar--left"></view>
</view>
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
<text
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
</picker>
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
<view class="uni-calendar__header-btn uni-calendar--right"></view>
</view>
<view v-if="!insert" class="dialog-close" @click="maskClick">
<view class="dialog-close-plus" data-id="close"></view>
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
</view>
</view>
<view class="uni-calendar__box">
<view v-if="showMonth" class="uni-calendar__box-bg">
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
</view>
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{MONText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{TUEText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{WEDText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{THUText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{FRIText}}</text>
</view>
<view class="uni-calendar__weeks-day">
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
</view>
</view>
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar" :selected="selected"
:checkHover="range" @change="choiceDate" @handleMouse="handleMouse">
</calendar-item>
</view>
</view>
</view>
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
style="padding: 0 80px;">
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
</time-picker>
</view>
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
<view class="uni-date-changed--time-start">
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
</view>
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
</time-picker>
</view>
<view style="line-height: 50px;">
<uni-icons type="arrowthinright" color="#999"></uni-icons>
</view>
<view class="uni-date-changed--time-end">
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
</time-picker>
</view>
</view>
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
</view>
</view>
</view>
</template>
<script>
import {
Calendar,
getDate,
getTime
} from './util.js';
import calendarItem from './calendar-item.vue'
import timePicker from './time-picker.vue'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const {
t
} = initVueI18n(i18nMessages)
/**
* Calendar 日历
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
* @property {String} date 自定义当前时间,默认为今天
* @property {String} startDate 日期选择范围-开始日期
* @property {String} endDate 日期选择范围-结束日期
* @property {Boolean} range 范围选择
* @property {Boolean} insert = [true|false] 插入模式,默认为false
* @value true 弹窗模式
* @value false 插入模式
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
* @property {Boolean} showMonth 是否选择月份为背景
* @property {[String} defaultValue 选择器打开时默认显示的时间
* @event {Function} change 日期改变,`insert :ture` 时生效
* @event {Function} confirm 确认选择`insert :false` 时生效
* @event {Function} monthSwitch 切换月份时触发
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
*/
export default {
components: {
calendarItem,
timePicker
},
options: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
props: {
date: {
type: String,
default: ''
},
defTime: {
type: [String, Object],
default: ''
},
selectableTimes: {
type: [Object],
default () {
return {}
}
},
selected: {
type: Array,
default () {
return []
}
},
startDate: {
type: String,
default: ''
},
endDate: {
type: String,
default: ''
},
startPlaceholder: {
type: String,
default: ''
},
endPlaceholder: {
type: String,
default: ''
},
range: {
type: Boolean,
default: false
},
hasTime: {
type: Boolean,
default: false
},
insert: {
type: Boolean,
default: true
},
showMonth: {
type: Boolean,
default: true
},
clearDate: {
type: Boolean,
default: true
},
checkHover: {
type: Boolean,
default: true
},
hideSecond: {
type: [Boolean],
default: false
},
pleStatus: {
type: Object,
default () {
return {
before: '',
after: '',
data: [],
fulldate: ''
}
}
},
defaultValue: {
type: [String, Object, Array],
default: ''
}
},
data() {
return {
show: false,
weeks: [],
calendar: {},
nowDate: {},
aniMaskShow: false,
firstEnter: true,
time: '',
timeRange: {
startTime: '',
endTime: ''
},
tempSingleDate: '',
tempRange: {
before: '',
after: ''
}
}
},
watch: {
date: {
immediate: true,
handler(newVal) {
if (!this.range) {
this.tempSingleDate = newVal
setTimeout(() => {
this.init(newVal)
}, 100)
}
}
},
defTime: {
immediate: true,
handler(newVal) {
if (!this.range) {
this.time = newVal
} else {
this.timeRange.startTime = newVal.start
this.timeRange.endTime = newVal.end
}
}
},
startDate(val) {
// 字节小程序 watch 早于 created
if (!this.cale) {
return
}
this.cale.setStartDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
endDate(val) {
// 字节小程序 watch 早于 created
if (!this.cale) {
return
}
this.cale.setEndDate(val)
this.cale.setDate(this.nowDate.fullDate)
this.weeks = this.cale.weeks
},
selected(newVal) {
// 字节小程序 watch 早于 created
if (!this.cale) {
return
}
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
this.weeks = this.cale.weeks
},
pleStatus: {
immediate: true,
handler(newVal) {
const {
before,
after,
fulldate,
which
} = newVal
this.tempRange.before = before
this.tempRange.after = after
setTimeout(() => {
if (fulldate) {
this.cale.setHoverMultiple(fulldate)
if (before && after) {
this.cale.lastHover = true
if (this.rangeWithinMonth(after, before)) return
this.setDate(before)
} else {
this.cale.setMultiple(fulldate)
this.setDate(this.nowDate.fullDate)
this.calendar.fullDate = ''
this.cale.lastHover = false
}
} else {
// 字节小程序 watch 早于 created
if (!this.cale) {
return
}
this.cale.setDefaultMultiple(before, after)
if (which === 'left' && before) {
this.setDate(before)
this.weeks = this.cale.weeks
} else if (after) {
this.setDate(after)
this.weeks = this.cale.weeks
}
this.cale.lastHover = true
}
}, 16)
}
}
},
computed: {
timepickerStartTime() {
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
return activeDate === this.startDate ? this.selectableTimes.start : ''
},
timepickerEndTime() {
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
return activeDate === this.endDate ? this.selectableTimes.end : ''
},
/**
* for i18n
*/
selectDateText() {
return t("uni-datetime-picker.selectDate")
},
startDateText() {
return this.startPlaceholder || t("uni-datetime-picker.startDate")
},
endDateText() {
return this.endPlaceholder || t("uni-datetime-picker.endDate")
},
okText() {
return t("uni-datetime-picker.ok")
},
yearText() {
return t("uni-datetime-picker.year")
},
monthText() {
return t("uni-datetime-picker.month")
},
MONText() {
return t("uni-calender.MON")
},
TUEText() {
return t("uni-calender.TUE")
},
WEDText() {
return t("uni-calender.WED")
},
THUText() {
return t("uni-calender.THU")
},
FRIText() {
return t("uni-calender.FRI")
},
SATText() {
return t("uni-calender.SAT")
},
SUNText() {
return t("uni-calender.SUN")
},
confirmText() {
return t("uni-calender.confirm")
},
},
created() {
// 获取日历方法实例
this.cale = new Calendar({
selected: this.selected,
startDate: this.startDate,
endDate: this.endDate,
range: this.range,
})
// 选中某一天
this.init(this.date)
},
methods: {
leaveCale() {
this.firstEnter = true
},
handleMouse(weeks) {
if (weeks.disable) return
if (this.cale.lastHover) return
let {
before,
after
} = this.cale.multipleStatus
if (!before) return
this.calendar = weeks
// 设置范围选
this.cale.setHoverMultiple(this.calendar.fullDate)
this.weeks = this.cale.weeks
// hover时进入一个日历更新另一个
if (this.firstEnter) {
this.$emit('firstEnterCale', this.cale.multipleStatus)
this.firstEnter = false
}
},
rangeWithinMonth(A, B) {
const [yearA, monthA] = A.split('-')
const [yearB, monthB] = B.split('-')
return yearA === yearB && monthA === monthB
},
// 蒙版点击事件
maskClick() {
this.close()
this.$emit('maskClose')
},
clearCalender() {
if (this.range) {
this.timeRange.startTime = ''
this.timeRange.endTime = ''
this.tempRange.before = ''
this.tempRange.after = ''
this.cale.multipleStatus.before = ''
this.cale.multipleStatus.after = ''
this.cale.multipleStatus.data = []
this.cale.lastHover = false
} else {
this.time = ''
this.tempSingleDate = ''
}
this.calendar.fullDate = ''
this.setDate(new Date())
},
bindDateChange(e) {
const value = e.detail.value + '-1'
this.setDate(value)
},
/**
* 初始化日期显示
* @param {Object} date
*/
init(date) {
// 字节小程序 watch 早于 created
if (!this.cale) {
return
}
this.cale.setDate(date || new Date())
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
this.calendar = {
...this.nowDate
}
if (!date) {
// 优化date为空默认不选中今天
this.calendar.fullDate = ''
if (this.defaultValue && !this.range) {
// 暂时只支持移动端非范围选择
const defaultDate = new Date(this.defaultValue)
const fullDate = getDate(defaultDate)
const year = defaultDate.getFullYear()
const month = defaultDate.getMonth() + 1
const date = defaultDate.getDate()
const day = defaultDate.getDay()
this.calendar = {
fullDate,
year,
month,
date,
day
},
this.tempSingleDate = fullDate
this.time = getTime(defaultDate, this.hideSecond)
}
}
},
/**
* 打开日历弹窗
*/
open() {
// 弹窗模式并且清理数据
if (this.clearDate && !this.insert) {
this.cale.cleanMultipleStatus()
this.init(this.date)
}
this.show = true
this.$nextTick(() => {
setTimeout(() => {
this.aniMaskShow = true
}, 50)
})
},
/**
* 关闭日历弹窗
*/
close() {
this.aniMaskShow = false
this.$nextTick(() => {
setTimeout(() => {
this.show = false
this.$emit('close')
}, 300)
})
},
/**
* 确认按钮
*/
confirm() {
this.setEmit('confirm')
this.close()
},
/**
* 变化触发
*/
change(isSingleChange) {
if (!this.insert && !isSingleChange) return
this.setEmit('change')
},
/**
* 选择月份触发
*/
monthSwitch() {
let {
year,
month
} = this.nowDate
this.$emit('monthSwitch', {
year,
month: Number(month)
})
},
/**
* 派发事件
* @param {Object} name
*/
setEmit(name) {
if (!this.range) {
if (!this.calendar.fullDate) {
this.calendar = this.cale.getInfo(new Date())
this.tempSingleDate = this.calendar.fullDate
}
if (this.hasTime && !this.time) {
this.time = getTime(new Date(), this.hideSecond)
}
}
let {
year,
month,
date,
fullDate,
extraInfo
} = this.calendar
this.$emit(name, {
range: this.cale.multipleStatus,
year,
month,
date,
time: this.time,
timeRange: this.timeRange,
fulldate: fullDate,
extraInfo: extraInfo || {}
})
},
/**
* 选择天触发
* @param {Object} weeks
*/
choiceDate(weeks) {
if (weeks.disable) return
this.calendar = weeks
this.calendar.userChecked = true
// 设置多选
this.cale.setMultiple(this.calendar.fullDate, true)
this.weeks = this.cale.weeks
this.tempSingleDate = this.calendar.fullDate
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
if (beforeDate > afterDate && afterDate) {
this.tempRange.before = this.cale.multipleStatus.after
this.tempRange.after = this.cale.multipleStatus.before
} else {
this.tempRange.before = this.cale.multipleStatus.before
this.tempRange.after = this.cale.multipleStatus.after
}
this.change(true)
},
changeMonth(type) {
let newDate
if (type === 'pre') {
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
} else if (type === 'next') {
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
}
this.setDate(newDate)
this.monthSwitch()
},
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
this.cale.setDate(date)
this.weeks = this.cale.weeks
this.nowDate = this.cale.getInfo(date)
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
.uni-calendar {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.uni-calendar__mask {
position: fixed;
bottom: 0;
top: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.4);
transition-property: opacity;
transition-duration: 0.3s;
opacity: 0;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--mask-show {
opacity: 1
}
.uni-calendar--fixed {
position: fixed;
bottom: calc(var(--window-bottom));
left: 0;
right: 0;
transition-property: transform;
transition-duration: 0.3s;
transform: translateY(460px);
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
}
.uni-calendar--ani-show {
transform: translateY(0);
}
.uni-calendar__content {
background-color: #fff;
}
.uni-calendar__content-mobile {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
box-shadow: 0px 0px 5px 3px rgba(0, 0, 0, 0.1);
}
.uni-calendar__header {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
height: 50px;
}
.uni-calendar__header-mobile {
padding: 10px;
padding-bottom: 0;
}
.uni-calendar--fixed-top {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
border-top-color: rgba(0, 0, 0, 0.4);
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--fixed-width {
width: 50px;
}
.uni-calendar__backtoday {
position: absolute;
right: 0;
top: 25rpx;
padding: 0 5px;
padding-left: 10px;
height: 25px;
line-height: 25px;
font-size: 12px;
border-top-left-radius: 25px;
border-bottom-left-radius: 25px;
color: #fff;
background-color: #f1f1f1;
}
.uni-calendar__header-text {
text-align: center;
width: 100px;
font-size: 15px;
color: #666;
}
.uni-calendar__button-text {
text-align: center;
width: 100px;
font-size: 14px;
color: $uni-primary;
/* #ifndef APP-NVUE */
letter-spacing: 3px;
/* #endif */
}
.uni-calendar__header-btn-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
}
.uni-calendar__header-btn {
width: 9px;
height: 9px;
border-left-color: #808080;
border-left-style: solid;
border-left-width: 1px;
border-top-color: #555555;
border-top-style: solid;
border-top-width: 1px;
}
.uni-calendar--left {
transform: rotate(-45deg);
}
.uni-calendar--right {
transform: rotate(135deg);
}
.uni-calendar__weeks {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-calendar__weeks-item {
flex: 1;
}
.uni-calendar__weeks-day {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
height: 40px;
border-bottom-color: #F5F5F5;
border-bottom-style: solid;
border-bottom-width: 1px;
}
.uni-calendar__weeks-day-text {
font-size: 12px;
color: #B2B2B2;
}
.uni-calendar__box {
position: relative;
// padding: 0 10px;
padding-bottom: 7px;
}
.uni-calendar__box-bg {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.uni-calendar__box-bg-text {
font-size: 200px;
font-weight: bold;
color: #999;
opacity: 0.1;
text-align: center;
/* #ifndef APP-NVUE */
line-height: 1;
/* #endif */
}
.uni-date-changed {
padding: 0 10px;
// line-height: 50px;
text-align: center;
color: #333;
border-top-color: #DCDCDC;
;
border-top-style: solid;
border-top-width: 1px;
flex: 1;
}
.uni-date-btn--ok {
padding: 20px 15px;
}
.uni-date-changed--time-start {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
}
.uni-date-changed--time-end {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
}
.uni-date-changed--time-date {
color: #999;
line-height: 50px;
/* #ifdef MP-TOUTIAO */
font-size: 16px;
/* #endif */
margin-right: 5px;
// opacity: 0.6;
}
.time-picker-style {
// width: 62px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
justify-content: center;
align-items: center
}
.mr-10 {
margin-right: 10px;
}
.dialog-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 0 25px;
margin-top: 10px;
}
.dialog-close-plus {
width: 16px;
height: 2px;
background-color: #737987;
border-radius: 2px;
transform: rotate(45deg);
}
.dialog-close-rotate {
position: absolute;
transform: rotate(-45deg);
}
.uni-datetime-picker--btn {
border-radius: 100px;
height: 40px;
line-height: 40px;
background-color: $uni-primary;
color: #fff;
font-size: 16px;
letter-spacing: 2px;
}
/* #ifndef APP-NVUE */
.uni-datetime-picker--btn:active {
opacity: 0.7;
}
/* #endif */
</style>

View File

@@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "select date",
"uni-datetime-picker.selectTime": "select time",
"uni-datetime-picker.selectDateTime": "select date and time",
"uni-datetime-picker.startDate": "start date",
"uni-datetime-picker.endDate": "end date",
"uni-datetime-picker.startTime": "start time",
"uni-datetime-picker.endTime": "end time",
"uni-datetime-picker.ok": "ok",
"uni-datetime-picker.clear": "clear",
"uni-datetime-picker.cancel": "cancel",
"uni-datetime-picker.year": "-",
"uni-datetime-picker.month": "",
"uni-calender.MON": "MON",
"uni-calender.TUE": "TUE",
"uni-calender.WED": "WED",
"uni-calender.THU": "THU",
"uni-calender.FRI": "FRI",
"uni-calender.SAT": "SAT",
"uni-calender.SUN": "SUN",
"uni-calender.confirm": "confirm"
}

View File

@@ -0,0 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "选择日期",
"uni-datetime-picker.selectTime": "选择时间",
"uni-datetime-picker.selectDateTime": "选择日期时间",
"uni-datetime-picker.startDate": "开始日期",
"uni-datetime-picker.endDate": "结束日期",
"uni-datetime-picker.startTime": "开始时间",
"uni-datetime-picker.endTime": "结束时间",
"uni-datetime-picker.ok": "确定",
"uni-datetime-picker.clear": "清除",
"uni-datetime-picker.cancel": "取消",
"uni-datetime-picker.year": "年",
"uni-datetime-picker.month": "月",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六",
"uni-calender.confirm": "确认"
}

View File

@@ -0,0 +1,22 @@
{
"uni-datetime-picker.selectDate": "選擇日期",
"uni-datetime-picker.selectTime": "選擇時間",
"uni-datetime-picker.selectDateTime": "選擇日期時間",
"uni-datetime-picker.startDate": "開始日期",
"uni-datetime-picker.endDate": "結束日期",
"uni-datetime-picker.startTime": "開始时间",
"uni-datetime-picker.endTime": "結束时间",
"uni-datetime-picker.ok": "確定",
"uni-datetime-picker.clear": "清除",
"uni-datetime-picker.cancel": "取消",
"uni-datetime-picker.year": "年",
"uni-datetime-picker.month": "月",
"uni-calender.SUN": "日",
"uni-calender.MON": "一",
"uni-calender.TUE": "二",
"uni-calender.WED": "三",
"uni-calender.THU": "四",
"uni-calender.FRI": "五",
"uni-calender.SAT": "六",
"uni-calender.confirm": "確認"
}

View File

@@ -0,0 +1,940 @@
<template>
<view class="uni-datetime-picker">
<view @click="initTimePicker">
<slot>
<view class="uni-datetime-picker-timebox-pointer"
:class="{'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border}">
<text class="uni-datetime-picker-text">{{time}}</text>
<view v-if="!time" class="uni-datetime-picker-time">
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
</view>
</view>
</slot>
</view>
<view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
<view v-if="visible" class="uni-datetime-picker-popup" :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
:style="fixNvueBug">
<view class="uni-title">
<text class="uni-datetime-picker-text">{{selectTimeText}}</text>
</view>
<view v-if="dateShow" class="uni-datetime-picker__container-box">
<picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd"
@change="bindDateChange">
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in years" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in months" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in days" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
</picker-view>
<!-- 兼容 nvue 不支持伪类 -->
<text class="uni-datetime-picker-sign sign-left">-</text>
<text class="uni-datetime-picker-sign sign-right">-</text>
</view>
<view v-if="timeShow" class="uni-datetime-picker__container-box">
<picker-view class="uni-datetime-picker-view" :class="[hideSecond ? 'time-hide-second' : '']"
:indicator-style="indicatorStyle" :value="hms" @change="bindTimeChange">
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in hours" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="uni-datetime-picker-item" v-for="(item,index) in minutes" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
<picker-view-column v-if="!hideSecond">
<view class="uni-datetime-picker-item" v-for="(item,index) in seconds" :key="index">
<text class="uni-datetime-picker-item">{{lessThanTen(item)}}</text>
</view>
</picker-view-column>
</picker-view>
<!-- 兼容 nvue 不支持伪类 -->
<text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
<text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
</view>
<view class="uni-datetime-picker-btn">
<view @click="clearTime">
<text class="uni-datetime-picker-btn-text">{{clearText}}</text>
</view>
<view class="uni-datetime-picker-btn-group">
<view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
<text class="uni-datetime-picker-btn-text">{{cancelText}}</text>
</view>
<view @click="setTime">
<text class="uni-datetime-picker-btn-text">{{okText}}</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import i18nMessages from './i18n/index.js'
const {
t
} = initVueI18n(i18nMessages)
import {
fixIosDateFormat
} from './util'
/**
* DatetimePicker 时间选择器
* @description 可以同时选择日期和时间的选择器
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
* @property {String} type = [datetime | date | time] 显示模式
* @property {Boolean} multiple = [true|false] 是否多选
* @property {String|Number} value 默认值
* @property {String|Number} start 起始日期或时间
* @property {String|Number} end 起始日期或时间
* @property {String} return-type = [timestamp | string]
* @event {Function} change 选中发生变化触发
*/
export default {
name: 'UniDatetimePicker',
data() {
return {
indicatorStyle: `height: 50px;`,
visible: false,
fixNvueBug: {},
dateShow: true,
timeShow: true,
title: '日期和时间',
// 输入框当前时间
time: '',
// 当前的年月日时分秒
year: 1920,
month: 0,
day: 0,
hour: 0,
minute: 0,
second: 0,
// 起始时间
startYear: 1920,
startMonth: 1,
startDay: 1,
startHour: 0,
startMinute: 0,
startSecond: 0,
// 结束时间
endYear: 2120,
endMonth: 12,
endDay: 31,
endHour: 23,
endMinute: 59,
endSecond: 59,
}
},
options: {
// #ifdef MP-TOUTIAO
virtualHost: false,
// #endif
// #ifndef MP-TOUTIAO
virtualHost: true
// #endif
},
props: {
type: {
type: String,
default: 'datetime'
},
value: {
type: [String, Number],
default: ''
},
modelValue: {
type: [String, Number],
default: ''
},
start: {
type: [Number, String],
default: ''
},
end: {
type: [Number, String],
default: ''
},
returnType: {
type: String,
default: 'string'
},
disabled: {
type: [Boolean, String],
default: false
},
border: {
type: [Boolean, String],
default: true
},
hideSecond: {
type: [Boolean, String],
default: false
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
if (newVal) {
this.parseValue(fixIosDateFormat(newVal))
this.initTime(false)
} else {
this.time = ''
this.parseValue(Date.now())
}
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
if (newVal) {
this.parseValue(fixIosDateFormat(newVal))
this.initTime(false)
} else {
this.time = ''
this.parseValue(Date.now())
}
},
immediate: true
},
// #endif
type: {
handler(newValue) {
if (newValue === 'date') {
this.dateShow = true
this.timeShow = false
this.title = '日期'
} else if (newValue === 'time') {
this.dateShow = false
this.timeShow = true
this.title = '时间'
} else {
this.dateShow = true
this.timeShow = true
this.title = '日期和时间'
}
},
immediate: true
},
start: {
handler(newVal) {
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
},
immediate: true
},
end: {
handler(newVal) {
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
},
immediate: true
},
// 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
months(newVal) {
this.checkValue('month', this.month, newVal)
},
days(newVal) {
this.checkValue('day', this.day, newVal)
},
hours(newVal) {
this.checkValue('hour', this.hour, newVal)
},
minutes(newVal) {
this.checkValue('minute', this.minute, newVal)
},
seconds(newVal) {
this.checkValue('second', this.second, newVal)
}
},
computed: {
// 当前年、月、日、时、分、秒选择范围
years() {
return this.getCurrentRange('year')
},
months() {
return this.getCurrentRange('month')
},
days() {
return this.getCurrentRange('day')
},
hours() {
return this.getCurrentRange('hour')
},
minutes() {
return this.getCurrentRange('minute')
},
seconds() {
return this.getCurrentRange('second')
},
// picker 当前值数组
ymd() {
return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay]
},
hms() {
return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond]
},
// 当前 date 是 start
currentDateIsStart() {
return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay
},
// 当前 date 是 end
currentDateIsEnd() {
return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay
},
// 当前年、月、日、时、分、秒的最小值和最大值
minYear() {
return this.startYear
},
maxYear() {
return this.endYear
},
minMonth() {
if (this.year === this.startYear) {
return this.startMonth
} else {
return 1
}
},
maxMonth() {
if (this.year === this.endYear) {
return this.endMonth
} else {
return 12
}
},
minDay() {
if (this.year === this.startYear && this.month === this.startMonth) {
return this.startDay
} else {
return 1
}
},
maxDay() {
if (this.year === this.endYear && this.month === this.endMonth) {
return this.endDay
} else {
return this.daysInMonth(this.year, this.month)
}
},
minHour() {
if (this.type === 'datetime') {
if (this.currentDateIsStart) {
return this.startHour
} else {
return 0
}
}
if (this.type === 'time') {
return this.startHour
}
},
maxHour() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd) {
return this.endHour
} else {
return 23
}
}
if (this.type === 'time') {
return this.endHour
}
},
minMinute() {
if (this.type === 'datetime') {
if (this.currentDateIsStart && this.hour === this.startHour) {
return this.startMinute
} else {
return 0
}
}
if (this.type === 'time') {
if (this.hour === this.startHour) {
return this.startMinute
} else {
return 0
}
}
},
maxMinute() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd && this.hour === this.endHour) {
return this.endMinute
} else {
return 59
}
}
if (this.type === 'time') {
if (this.hour === this.endHour) {
return this.endMinute
} else {
return 59
}
}
},
minSecond() {
if (this.type === 'datetime') {
if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
return this.startSecond
} else {
return 0
}
}
if (this.type === 'time') {
if (this.hour === this.startHour && this.minute === this.startMinute) {
return this.startSecond
} else {
return 0
}
}
},
maxSecond() {
if (this.type === 'datetime') {
if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
return this.endSecond
} else {
return 59
}
}
if (this.type === 'time') {
if (this.hour === this.endHour && this.minute === this.endMinute) {
return this.endSecond
} else {
return 59
}
}
},
/**
* for i18n
*/
selectTimeText() {
return t("uni-datetime-picker.selectTime")
},
okText() {
return t("uni-datetime-picker.ok")
},
clearText() {
return t("uni-datetime-picker.clear")
},
cancelText() {
return t("uni-datetime-picker.cancel")
}
},
mounted() {
// #ifdef APP-NVUE
const res = uni.getSystemInfoSync();
this.fixNvueBug = {
top: res.windowHeight / 2,
left: res.windowWidth / 2
}
// #endif
},
methods: {
/**
* @param {Object} item
* 小于 10 在前面加个 0
*/
lessThanTen(item) {
return item < 10 ? '0' + item : item
},
/**
* 解析时分秒字符串例如00:00:00
* @param {String} timeString
*/
parseTimeType(timeString) {
if (timeString) {
let timeArr = timeString.split(':')
this.hour = Number(timeArr[0])
this.minute = Number(timeArr[1])
this.second = Number(timeArr[2])
}
},
/**
* 解析选择器初始值类型可以是字符串、时间戳例如2000-10-02、'08:30:00'、 1610695109000
* @param {String | Number} datetime
*/
initPickerValue(datetime) {
let defaultValue = null
if (datetime) {
defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end)
} else {
defaultValue = Date.now()
defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end)
}
this.parseValue(defaultValue)
},
/**
* 初始值规则:
* - 用户设置初始值 value
* - 设置了起始时间 start、终止时间 end并 start < value < end初始值为 value 否则初始值为 start
* - 只设置了起始时间 start并 start < value初始值为 value否则初始值为 start
* - 只设置了终止时间 end并 value < end初始值为 value否则初始值为 end
* - 无起始终止时间,则初始值为 value
* - 无初始值 value则初始值为当前本地时间 Date.now()
* @param {Object} value
* @param {Object} dateBase
*/
compareValueWithStartAndEnd(value, start, end) {
let winner = null
value = this.superTimeStamp(value)
start = this.superTimeStamp(start)
end = this.superTimeStamp(end)
if (start && end) {
if (value < start) {
winner = new Date(start)
} else if (value > end) {
winner = new Date(end)
} else {
winner = new Date(value)
}
} else if (start && !end) {
winner = start <= value ? new Date(value) : new Date(start)
} else if (!start && end) {
winner = value <= end ? new Date(value) : new Date(end)
} else {
winner = new Date(value)
}
return winner
},
/**
* 转换为可比较的时间戳,接受日期、时分秒、时间戳
* @param {Object} value
*/
superTimeStamp(value) {
let dateBase = ''
if (this.type === 'time' && value && typeof value === 'string') {
const now = new Date()
const year = now.getFullYear()
const month = now.getMonth() + 1
const day = now.getDate()
dateBase = year + '/' + month + '/' + day + ' '
}
if (Number(value)) {
value = parseInt(value)
dateBase = 0
}
return this.createTimeStamp(dateBase + value)
},
/**
* 解析默认值 value字符串、时间戳
* @param {Object} defaultTime
*/
parseValue(value) {
if (!value) {
return
}
if (this.type === 'time' && typeof value === "string") {
this.parseTimeType(value)
} else {
let defaultDate = null
defaultDate = new Date(value)
if (this.type !== 'time') {
this.year = defaultDate.getFullYear()
this.month = defaultDate.getMonth() + 1
this.day = defaultDate.getDate()
}
if (this.type !== 'date') {
this.hour = defaultDate.getHours()
this.minute = defaultDate.getMinutes()
this.second = defaultDate.getSeconds()
}
}
if (this.hideSecond) {
this.second = 0
}
},
/**
* 解析可选择时间范围 start、end年月日字符串、时间戳
* @param {Object} defaultTime
*/
parseDatetimeRange(point, pointType) {
// 时间为空,则重置为初始值
if (!point) {
if (pointType === 'start') {
this.startYear = 1920
this.startMonth = 1
this.startDay = 1
this.startHour = 0
this.startMinute = 0
this.startSecond = 0
}
if (pointType === 'end') {
this.endYear = 2120
this.endMonth = 12
this.endDay = 31
this.endHour = 23
this.endMinute = 59
this.endSecond = 59
}
return
}
if (this.type === 'time') {
const pointArr = point.split(':')
this[pointType + 'Hour'] = Number(pointArr[0])
this[pointType + 'Minute'] = Number(pointArr[1])
this[pointType + 'Second'] = Number(pointArr[2])
} else {
if (!point) {
pointType === 'start' ? this.startYear = this.year - 60 : this.endYear = this.year + 60
return
}
if (Number(point)) {
point = parseInt(point)
}
// datetime 的 end 没有时分秒, 则不限制
const hasTime = /[0-9]:[0-9]/
if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(
point)) {
point = point + ' 23:59:59'
}
const pointDate = new Date(point)
this[pointType + 'Year'] = pointDate.getFullYear()
this[pointType + 'Month'] = pointDate.getMonth() + 1
this[pointType + 'Day'] = pointDate.getDate()
if (this.type === 'datetime') {
this[pointType + 'Hour'] = pointDate.getHours()
this[pointType + 'Minute'] = pointDate.getMinutes()
this[pointType + 'Second'] = pointDate.getSeconds()
}
}
},
// 获取 年、月、日、时、分、秒 当前可选范围
getCurrentRange(value) {
const range = []
for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
range.push(i)
}
return range
},
// 字符串首字母大写
capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
},
// 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
checkValue(name, value, values) {
if (values.indexOf(value) === -1) {
this[name] = values[0]
}
},
// 每个月的实际天数
daysInMonth(year, month) { // Use 1 for January, 2 for February, etc.
return new Date(year, month, 0).getDate();
},
/**
* 生成时间戳
* @param {Object} time
*/
createTimeStamp(time) {
if (!time) return
if (typeof time === "number") {
return time
} else {
time = time.replace(/-/g, '/')
if (this.type === 'date') {
time = time + ' ' + '00:00:00'
}
return Date.parse(time)
}
},
/**
* 生成日期或时间的字符串
*/
createDomSting() {
const yymmdd = this.year +
'-' +
this.lessThanTen(this.month) +
'-' +
this.lessThanTen(this.day)
let hhmmss = this.lessThanTen(this.hour) +
':' +
this.lessThanTen(this.minute)
if (!this.hideSecond) {
hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
}
if (this.type === 'date') {
return yymmdd
} else if (this.type === 'time') {
return hhmmss
} else {
return yymmdd + ' ' + hhmmss
}
},
/**
* 初始化返回值,并抛出 change 事件
*/
initTime(emit = true) {
this.time = this.createDomSting()
if (!emit) return
if (this.returnType === 'timestamp' && this.type !== 'time') {
this.$emit('change', this.createTimeStamp(this.time))
this.$emit('input', this.createTimeStamp(this.time))
this.$emit('update:modelValue', this.createTimeStamp(this.time))
} else {
this.$emit('change', this.time)
this.$emit('input', this.time)
this.$emit('update:modelValue', this.time)
}
},
/**
* 用户选择日期或时间更新 data
* @param {Object} e
*/
bindDateChange(e) {
const val = e.detail.value
this.year = this.years[val[0]]
this.month = this.months[val[1]]
this.day = this.days[val[2]]
},
bindTimeChange(e) {
const val = e.detail.value
this.hour = this.hours[val[0]]
this.minute = this.minutes[val[1]]
this.second = this.seconds[val[2]]
},
/**
* 初始化弹出层
*/
initTimePicker() {
if (this.disabled) return
const value = fixIosDateFormat(this.time)
this.initPickerValue(value)
this.visible = !this.visible
},
/**
* 触发或关闭弹框
*/
tiggerTimePicker(e) {
this.visible = !this.visible
},
/**
* 用户点击“清空”按钮,清空当前值
*/
clearTime() {
this.time = ''
this.$emit('change', this.time)
this.$emit('input', this.time)
this.$emit('update:modelValue', this.time)
this.tiggerTimePicker()
},
/**
* 用户点击“确定”按钮
*/
setTime() {
this.initTime()
this.tiggerTimePicker()
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
.uni-datetime-picker {
/* #ifndef APP-NVUE */
/* width: 100%; */
/* #endif */
}
.uni-datetime-picker-view {
height: 130px;
width: 270px;
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-item {
height: 50px;
line-height: 50px;
text-align: center;
font-size: 14px;
}
.uni-datetime-picker-btn {
margin-top: 60px;
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
flex-direction: row;
justify-content: space-between;
}
.uni-datetime-picker-btn-text {
font-size: 14px;
color: $uni-primary;
}
.uni-datetime-picker-btn-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.uni-datetime-picker-cancel {
margin-right: 30px;
}
.uni-datetime-picker-mask {
position: fixed;
bottom: 0px;
top: 0px;
left: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.4);
transition-duration: 0.3s;
z-index: 998;
}
.uni-datetime-picker-popup {
border-radius: 8px;
padding: 30px;
width: 270px;
/* #ifdef APP-NVUE */
height: 500px;
/* #endif */
/* #ifdef APP-NVUE */
width: 330px;
/* #endif */
background-color: #fff;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition-duration: 0.3s;
z-index: 999;
}
.fix-nvue-height {
/* #ifdef APP-NVUE */
height: 330px;
/* #endif */
}
.uni-datetime-picker-time {
color: grey;
}
.uni-datetime-picker-column {
height: 50px;
}
.uni-datetime-picker-timebox {
border: 1px solid #E5E5E5;
border-radius: 5px;
padding: 7px 10px;
/* #ifndef APP-NVUE */
box-sizing: border-box;
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-timebox-pointer {
/* #ifndef APP-NVUE */
cursor: pointer;
/* #endif */
}
.uni-datetime-picker-disabled {
opacity: 0.4;
/* #ifdef H5 */
cursor: not-allowed !important;
/* #endif */
}
.uni-datetime-picker-text {
font-size: 14px;
line-height: 50px
}
.uni-datetime-picker-sign {
position: absolute;
top: 53px;
/* 减掉 10px 的元素高度兼容nvue */
color: #999;
/* #ifdef APP-NVUE */
font-size: 16px;
/* #endif */
}
.sign-left {
left: 86px;
}
.sign-right {
right: 86px;
}
.sign-center {
left: 135px;
}
.uni-datetime-picker__container-box {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-top: 40px;
}
.time-hide-second {
width: 180px;
}
</style>

View File

@@ -0,0 +1,421 @@
class Calendar {
constructor({
selected,
startDate,
endDate,
range,
} = {}) {
// 当前日期
this.date = this.getDateObj(new Date()) // 当前初入日期
// 打点信息
this.selected = selected || [];
// 起始时间
this.startDate = startDate
// 终止时间
this.endDate = endDate
// 是否范围选择
this.range = range
// 多选状态
this.cleanMultipleStatus()
// 每周日期
this.weeks = {}
this.lastHover = false
}
/**
* 设置日期
* @param {Object} date
*/
setDate(date) {
const selectDate = this.getDateObj(date)
this.getWeeks(selectDate.fullDate)
}
/**
* 清理多选状态
*/
cleanMultipleStatus() {
this.multipleStatus = {
before: '',
after: '',
data: []
}
}
setStartDate(startDate) {
this.startDate = startDate
}
setEndDate(endDate) {
this.endDate = endDate
}
getPreMonthObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const oldMonth = date.getMonth()
date.setMonth(oldMonth - 1)
const newMonth = date.getMonth()
if (oldMonth !== 0 && newMonth - oldMonth === 0) {
date.setMonth(newMonth - 1)
}
return this.getDateObj(date)
}
getNextMonthObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const oldMonth = date.getMonth()
date.setMonth(oldMonth + 1)
const newMonth = date.getMonth()
if (newMonth - oldMonth > 1) {
date.setMonth(newMonth - 1)
}
return this.getDateObj(date)
}
/**
* 获取指定格式Date对象
*/
getDateObj(date) {
date = fixIosDateFormat(date)
date = new Date(date)
return {
fullDate: getDate(date),
year: date.getFullYear(),
month: addZero(date.getMonth() + 1),
date: addZero(date.getDate()),
day: date.getDay()
}
}
/**
* 获取上一个月日期集合
*/
getPreMonthDays(amount, dateObj) {
const result = []
for (let i = amount - 1; i >= 0; i--) {
const month = dateObj.month - 1
result.push({
date: new Date(dateObj.year, month, -i).getDate(),
month,
disable: true
})
}
return result
}
/**
* 获取本月日期集合
*/
getCurrentMonthDays(amount, dateObj) {
const result = []
const fullDate = this.date.fullDate
for (let i = 1; i <= amount; i++) {
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
const isToday = fullDate === currentDate
// 获取打点信息
const info = this.selected && this.selected.find((item) => {
if (this.dateEqual(currentDate, item.date)) {
return item
}
})
// 日期禁用
let disableBefore = true
let disableAfter = true
if (this.startDate) {
disableBefore = dateCompare(this.startDate, currentDate)
}
if (this.endDate) {
disableAfter = dateCompare(currentDate, this.endDate)
}
let multiples = this.multipleStatus.data
let multiplesStatus = -1
if (this.range && multiples) {
multiplesStatus = multiples.findIndex((item) => {
return this.dateEqual(item, currentDate)
})
}
const checked = multiplesStatus !== -1
result.push({
fullDate: currentDate,
year: dateObj.year,
date: i,
multiple: this.range ? checked : false,
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
month: dateObj.month,
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
currentDate, this.endDate)),
isToday,
userChecked: false,
extraInfo: info
})
}
return result
}
/**
* 获取下一个月日期集合
*/
_getNextMonthDays(amount, dateObj) {
const result = []
const month = dateObj.month + 1
for (let i = 1; i <= amount; i++) {
result.push({
date: i,
month,
disable: true
})
}
return result
}
/**
* 获取当前日期详情
* @param {Object} date
*/
getInfo(date) {
if (!date) {
date = new Date()
}
const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
return res ? res : this.getDateObj(date)
}
/**
* 比较时间是否相等
*/
dateEqual(before, after) {
before = new Date(fixIosDateFormat(before))
after = new Date(fixIosDateFormat(after))
return before.valueOf() === after.valueOf()
}
/**
* 比较真实起始日期
*/
isLogicBefore(currentDate, before, after) {
let logicBefore = before
if (before && after) {
logicBefore = dateCompare(before, after) ? before : after
}
return this.dateEqual(logicBefore, currentDate)
}
isLogicAfter(currentDate, before, after) {
let logicAfter = after
if (before && after) {
logicAfter = dateCompare(before, after) ? after : before
}
return this.dateEqual(logicAfter, currentDate)
}
/**
* 获取日期范围内所有日期
* @param {Object} begin
* @param {Object} end
*/
geDateAll(begin, end) {
var arr = []
var ab = begin.split('-')
var ae = end.split('-')
var db = new Date()
db.setFullYear(ab[0], ab[1] - 1, ab[2])
var de = new Date()
de.setFullYear(ae[0], ae[1] - 1, ae[2])
var unixDb = db.getTime() - 24 * 60 * 60 * 1000
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
for (var k = unixDb; k <= unixDe;) {
k = k + 24 * 60 * 60 * 1000
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
}
return arr
}
/**
* 获取多选状态
*/
setMultiple(fullDate) {
if (!this.range) return
let {
before,
after
} = this.multipleStatus
if (before && after) {
if (!this.lastHover) {
this.lastHover = true
return
}
this.multipleStatus.before = fullDate
this.multipleStatus.after = ''
this.multipleStatus.data = []
this.multipleStatus.fulldate = ''
this.lastHover = false
} else {
if (!before) {
this.multipleStatus.before = fullDate
this.multipleStatus.after = undefined;
this.lastHover = false
} else {
this.multipleStatus.after = fullDate
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
.before);
}
this.lastHover = true
}
}
this.getWeeks(fullDate)
}
/**
* 鼠标 hover 更新多选状态
*/
setHoverMultiple(fullDate) {
//抖音小程序点击会触发hover事件需要避免一下
// #ifndef MP-TOUTIAO
if (!this.range || this.lastHover) return
const {
before
} = this.multipleStatus
if (!before) {
this.multipleStatus.before = fullDate
} else {
this.multipleStatus.after = fullDate
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
} else {
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
}
}
this.getWeeks(fullDate)
// #endif
}
/**
* 更新默认值多选状态
*/
setDefaultMultiple(before, after) {
this.multipleStatus.before = before
this.multipleStatus.after = after
if (before && after) {
if (dateCompare(before, after)) {
this.multipleStatus.data = this.geDateAll(before, after);
this.getWeeks(after)
} else {
this.multipleStatus.data = this.geDateAll(after, before);
this.getWeeks(before)
}
}
}
/**
* 获取每周数据
* @param {Object} dateData
*/
getWeeks(dateData) {
const {
year,
month,
} = this.getDateObj(dateData)
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
const currentMonthDayAmount = new Date(year, month, 0).getDate()
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
const weeks = new Array(6)
for (let i = 0; i < calendarDays.length; i++) {
const index = Math.floor(i / 7)
if (!weeks[index]) {
weeks[index] = new Array(7)
}
weeks[index][i % 7] = calendarDays[i]
}
this.calendar = calendarDays
this.weeks = weeks
}
}
function getDateTime(date, hideSecond) {
return `${getDate(date)} ${getTime(date, hideSecond)}`
}
function getDate(date) {
date = fixIosDateFormat(date)
date = new Date(date)
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
return `${year}-${addZero(month)}-${addZero(day)}`
}
function getTime(date, hideSecond) {
date = fixIosDateFormat(date)
date = new Date(date)
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
}
function addZero(num) {
if (num < 10) {
num = `0${num}`
}
return num
}
function getDefaultSecond(hideSecond) {
return hideSecond ? '00:00' : '00:00:00'
}
function dateCompare(startDate, endDate) {
startDate = new Date(fixIosDateFormat(startDate))
endDate = new Date(fixIosDateFormat(endDate))
return startDate <= endDate
}
function checkDate(date) {
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
return date.match(dateReg)
}
//ios低版本15及以下无法匹配 没有 ’秒‘ 时的情况,所以需要在末尾 秒 加上 问号
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;
function fixIosDateFormat(value) {
if (typeof value === 'string' && dateTimeReg.test(value)) {
value = value.replace(/-/g, '/')
}
return value
}
export {
Calendar,
getDateTime,
getDate,
getTime,
addZero,
getDefaultSecond,
dateCompare,
checkDate,
fixIosDateFormat
}

View File

@@ -0,0 +1,88 @@
{
"id": "uni-datetime-picker",
"displayName": "uni-datetime-picker 日期选择器",
"version": "2.2.38",
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
"keywords": [
"uni-datetime-picker",
"uni-ui",
"uniui",
"日期时间选择器",
"日期时间"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,21 @@
> `重要通知:组件升级更新 2.0.0 后,支持日期+时间范围选择,组件 ui 将使用日历选择日期ui 变化较大,同时支持 PC 和 移动端。此版本不向后兼容不再支持单独的时间选择type=time及相关的 hide-second 属性(时间选可使用内置组件 picker。若仍需使用旧版本可在插件市场下载*非uni_modules版本*,旧版本将不再维护`
## DatetimePicker 时间选择器
> **组件名uni-datetime-picker**
> 代码块: `uDatetimePicker`
该组件的优势是,支持**时间戳**输入和输出(起始时间、终止时间也支持时间戳),可**同时选择**日期和时间。
若只是需要单独选择日期和时间,不需要时间戳输入和输出,可使用原生的 picker 组件。
**_点击 picker 默认值规则_**
- 若设置初始值 value, 会显示在 picker 显示框中
- 若无初始值 value则初始值 value 为当前本地时间 Date.now() 但不会显示在 picker 显示框中
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-datetime-picker)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@@ -0,0 +1,42 @@
## 2.0.102024-06-07
- 优化 uni-app x 中size 属性的类型
## 2.0.92024-01-12
fix: 修复图标大小默认值错误的问题
## 2.0.82023-12-14
- 修复 项目未使用 ts 情况下打包报错的bug
## 2.0.72023-12-14
- 修复 size 属性为 string 时不加单位导致尺寸异常的bug
## 2.0.62023-12-11
- 优化 兼容老版本icon类型如 top bottom 等
## 2.0.52023-12-11
- 优化 兼容老版本icon类型如 top bottom 等
## 2.0.42023-12-06
- 优化 uni-app x 下示例项目图标排序
## 2.0.32023-12-06
- 修复 nvue下引入组件报错的bug
## 2.0.22023-12-05
-优化 size 属性支持单位
## 2.0.12023-12-05
- 新增 uni-app x 支持定义图标
## 1.3.52022-01-24
- 优化 size 属性可以传入不带单位的字符串数值
## 1.3.42022-01-24
- 优化 size 支持其他单位
## 1.3.32022-01-17
- 修复 nvue 有些图标不显示的bug兼容老版本图标
## 1.3.22021-12-01
- 优化 示例可复制图标名称
## 1.3.12021-11-23
- 优化 兼容旧组件 type 值
## 1.3.02021-11-19
- 新增 更多图标
- 优化 自定义图标使用方式
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons)
## 1.1.72021-11-08
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.52021-05-12
- 新增 组件示例地址
## 1.1.42021-02-05
- 调整为uni_modules目录规范

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
<template>
<text class="uni-icons" :style="styleObj">
<slot>{{unicode}}</slot>
</text>
</template>
<script>
import { fontData, IconsDataItem } from './uniicons_file'
/**
* Icons 图标
* @description 用于展示 icon 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number,String} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: "uni-icons",
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {};
},
computed: {
unicode() : string {
let codes = fontData.find((item : IconsDataItem) : boolean => { return item.font_class == this.type })
if (codes !== null) {
return codes.unicode
}
return ''
},
iconSize() : string {
const size = this.size
if (typeof size == 'string') {
const reg = /^[0-9]*$/g
return reg.test(size as string) ? '' + size + 'px' : '' + size;
// return '' + this.size
}
return this.getFontSize(size as number)
},
styleObj() : UTSJSONObject {
if (this.fontFamily !== '') {
return { color: this.color, fontSize: this.iconSize, fontFamily: this.fontFamily }
}
return { color: this.color, fontSize: this.iconSize }
}
},
created() { },
methods: {
/**
* 字体大小
*/
getFontSize(size : number) : string {
return size + 'px';
},
},
}
</script>
<style scoped>
@font-face {
font-family: UniIconsFontFamily;
src: url('./uniicons.ttf');
}
.uni-icons {
font-family: UniIconsFontFamily;
font-size: 18px;
font-style: normal;
color: #333;
}
</style>

View File

@@ -0,0 +1,110 @@
<template>
<!-- #ifdef APP-NVUE -->
<text :style="styleObj" class="uni-icons" @click="_onClick">{{unicode}}</text>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<text :style="styleObj" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick">
<slot></slot>
</text>
<!-- #endif -->
</template>
<script>
import { fontData } from './uniicons_file_vue.js';
const getVal = (val) => {
const reg = /^[0-9]*$/g
return (typeof val === 'number' || reg.test(val)) ? val + 'px' : val;
}
// #ifdef APP-NVUE
var domModule = weex.requireModule('dom');
import iconUrl from './uniicons.ttf'
domModule.addRule('fontFace', {
'fontFamily': "uniicons",
'src': "url('" + iconUrl + "')"
});
// #endif
/**
* Icons 图标
* @description 用于展示 icons 图标
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
* @property {Number} size 图标大小
* @property {String} type 图标图案,参考示例
* @property {String} color 图标颜色
* @property {String} customPrefix 自定义图标
* @event {Function} click 点击 Icon 触发事件
*/
export default {
name: 'UniIcons',
emits: ['click'],
props: {
type: {
type: String,
default: ''
},
color: {
type: String,
default: '#333333'
},
size: {
type: [Number, String],
default: 16
},
customPrefix: {
type: String,
default: ''
},
fontFamily: {
type: String,
default: ''
}
},
data() {
return {
icons: fontData
}
},
computed: {
unicode() {
let code = this.icons.find(v => v.font_class === this.type)
if (code) {
return code.unicode
}
return ''
},
iconSize() {
return getVal(this.size)
},
styleObj() {
if (this.fontFamily !== '') {
return `color: ${this.color}; font-size: ${this.iconSize}; font-family: ${this.fontFamily};`
}
return `color: ${this.color}; font-size: ${this.iconSize};`
}
},
methods: {
_onClick() {
this.$emit('click')
}
}
}
</script>
<style lang="scss">
/* #ifndef APP-NVUE */
@import './uniicons.css';
@font-face {
font-family: uniicons;
src: url('./uniicons.ttf');
}
/* #endif */
.uni-icons {
font-family: uniicons;
text-decoration: none;
text-align: center;
}
</style>

View File

@@ -0,0 +1,664 @@
.uniui-cart-filled:before {
content: "\e6d0";
}
.uniui-gift-filled:before {
content: "\e6c4";
}
.uniui-color:before {
content: "\e6cf";
}
.uniui-wallet:before {
content: "\e6b1";
}
.uniui-settings-filled:before {
content: "\e6ce";
}
.uniui-auth-filled:before {
content: "\e6cc";
}
.uniui-shop-filled:before {
content: "\e6cd";
}
.uniui-staff-filled:before {
content: "\e6cb";
}
.uniui-vip-filled:before {
content: "\e6c6";
}
.uniui-plus-filled:before {
content: "\e6c7";
}
.uniui-folder-add-filled:before {
content: "\e6c8";
}
.uniui-color-filled:before {
content: "\e6c9";
}
.uniui-tune-filled:before {
content: "\e6ca";
}
.uniui-calendar-filled:before {
content: "\e6c0";
}
.uniui-notification-filled:before {
content: "\e6c1";
}
.uniui-wallet-filled:before {
content: "\e6c2";
}
.uniui-medal-filled:before {
content: "\e6c3";
}
.uniui-fire-filled:before {
content: "\e6c5";
}
.uniui-refreshempty:before {
content: "\e6bf";
}
.uniui-location-filled:before {
content: "\e6af";
}
.uniui-person-filled:before {
content: "\e69d";
}
.uniui-personadd-filled:before {
content: "\e698";
}
.uniui-arrowthinleft:before {
content: "\e6d2";
}
.uniui-arrowthinup:before {
content: "\e6d3";
}
.uniui-arrowthindown:before {
content: "\e6d4";
}
.uniui-back:before {
content: "\e6b9";
}
.uniui-forward:before {
content: "\e6ba";
}
.uniui-arrow-right:before {
content: "\e6bb";
}
.uniui-arrow-left:before {
content: "\e6bc";
}
.uniui-arrow-up:before {
content: "\e6bd";
}
.uniui-arrow-down:before {
content: "\e6be";
}
.uniui-arrowthinright:before {
content: "\e6d1";
}
.uniui-down:before {
content: "\e6b8";
}
.uniui-bottom:before {
content: "\e6b8";
}
.uniui-arrowright:before {
content: "\e6d5";
}
.uniui-right:before {
content: "\e6b5";
}
.uniui-up:before {
content: "\e6b6";
}
.uniui-top:before {
content: "\e6b6";
}
.uniui-left:before {
content: "\e6b7";
}
.uniui-arrowup:before {
content: "\e6d6";
}
.uniui-eye:before {
content: "\e651";
}
.uniui-eye-filled:before {
content: "\e66a";
}
.uniui-eye-slash:before {
content: "\e6b3";
}
.uniui-eye-slash-filled:before {
content: "\e6b4";
}
.uniui-info-filled:before {
content: "\e649";
}
.uniui-reload:before {
content: "\e6b2";
}
.uniui-micoff-filled:before {
content: "\e6b0";
}
.uniui-map-pin-ellipse:before {
content: "\e6ac";
}
.uniui-map-pin:before {
content: "\e6ad";
}
.uniui-location:before {
content: "\e6ae";
}
.uniui-starhalf:before {
content: "\e683";
}
.uniui-star:before {
content: "\e688";
}
.uniui-star-filled:before {
content: "\e68f";
}
.uniui-calendar:before {
content: "\e6a0";
}
.uniui-fire:before {
content: "\e6a1";
}
.uniui-medal:before {
content: "\e6a2";
}
.uniui-font:before {
content: "\e6a3";
}
.uniui-gift:before {
content: "\e6a4";
}
.uniui-link:before {
content: "\e6a5";
}
.uniui-notification:before {
content: "\e6a6";
}
.uniui-staff:before {
content: "\e6a7";
}
.uniui-vip:before {
content: "\e6a8";
}
.uniui-folder-add:before {
content: "\e6a9";
}
.uniui-tune:before {
content: "\e6aa";
}
.uniui-auth:before {
content: "\e6ab";
}
.uniui-person:before {
content: "\e699";
}
.uniui-email-filled:before {
content: "\e69a";
}
.uniui-phone-filled:before {
content: "\e69b";
}
.uniui-phone:before {
content: "\e69c";
}
.uniui-email:before {
content: "\e69e";
}
.uniui-personadd:before {
content: "\e69f";
}
.uniui-chatboxes-filled:before {
content: "\e692";
}
.uniui-contact:before {
content: "\e693";
}
.uniui-chatbubble-filled:before {
content: "\e694";
}
.uniui-contact-filled:before {
content: "\e695";
}
.uniui-chatboxes:before {
content: "\e696";
}
.uniui-chatbubble:before {
content: "\e697";
}
.uniui-upload-filled:before {
content: "\e68e";
}
.uniui-upload:before {
content: "\e690";
}
.uniui-weixin:before {
content: "\e691";
}
.uniui-compose:before {
content: "\e67f";
}
.uniui-qq:before {
content: "\e680";
}
.uniui-download-filled:before {
content: "\e681";
}
.uniui-pyq:before {
content: "\e682";
}
.uniui-sound:before {
content: "\e684";
}
.uniui-trash-filled:before {
content: "\e685";
}
.uniui-sound-filled:before {
content: "\e686";
}
.uniui-trash:before {
content: "\e687";
}
.uniui-videocam-filled:before {
content: "\e689";
}
.uniui-spinner-cycle:before {
content: "\e68a";
}
.uniui-weibo:before {
content: "\e68b";
}
.uniui-videocam:before {
content: "\e68c";
}
.uniui-download:before {
content: "\e68d";
}
.uniui-help:before {
content: "\e679";
}
.uniui-navigate-filled:before {
content: "\e67a";
}
.uniui-plusempty:before {
content: "\e67b";
}
.uniui-smallcircle:before {
content: "\e67c";
}
.uniui-minus-filled:before {
content: "\e67d";
}
.uniui-micoff:before {
content: "\e67e";
}
.uniui-closeempty:before {
content: "\e66c";
}
.uniui-clear:before {
content: "\e66d";
}
.uniui-navigate:before {
content: "\e66e";
}
.uniui-minus:before {
content: "\e66f";
}
.uniui-image:before {
content: "\e670";
}
.uniui-mic:before {
content: "\e671";
}
.uniui-paperplane:before {
content: "\e672";
}
.uniui-close:before {
content: "\e673";
}
.uniui-help-filled:before {
content: "\e674";
}
.uniui-paperplane-filled:before {
content: "\e675";
}
.uniui-plus:before {
content: "\e676";
}
.uniui-mic-filled:before {
content: "\e677";
}
.uniui-image-filled:before {
content: "\e678";
}
.uniui-locked-filled:before {
content: "\e668";
}
.uniui-info:before {
content: "\e669";
}
.uniui-locked:before {
content: "\e66b";
}
.uniui-camera-filled:before {
content: "\e658";
}
.uniui-chat-filled:before {
content: "\e659";
}
.uniui-camera:before {
content: "\e65a";
}
.uniui-circle:before {
content: "\e65b";
}
.uniui-checkmarkempty:before {
content: "\e65c";
}
.uniui-chat:before {
content: "\e65d";
}
.uniui-circle-filled:before {
content: "\e65e";
}
.uniui-flag:before {
content: "\e65f";
}
.uniui-flag-filled:before {
content: "\e660";
}
.uniui-gear-filled:before {
content: "\e661";
}
.uniui-home:before {
content: "\e662";
}
.uniui-home-filled:before {
content: "\e663";
}
.uniui-gear:before {
content: "\e664";
}
.uniui-smallcircle-filled:before {
content: "\e665";
}
.uniui-map-filled:before {
content: "\e666";
}
.uniui-map:before {
content: "\e667";
}
.uniui-refresh-filled:before {
content: "\e656";
}
.uniui-refresh:before {
content: "\e657";
}
.uniui-cloud-upload:before {
content: "\e645";
}
.uniui-cloud-download-filled:before {
content: "\e646";
}
.uniui-cloud-download:before {
content: "\e647";
}
.uniui-cloud-upload-filled:before {
content: "\e648";
}
.uniui-redo:before {
content: "\e64a";
}
.uniui-images-filled:before {
content: "\e64b";
}
.uniui-undo-filled:before {
content: "\e64c";
}
.uniui-more:before {
content: "\e64d";
}
.uniui-more-filled:before {
content: "\e64e";
}
.uniui-undo:before {
content: "\e64f";
}
.uniui-images:before {
content: "\e650";
}
.uniui-paperclip:before {
content: "\e652";
}
.uniui-settings:before {
content: "\e653";
}
.uniui-search:before {
content: "\e654";
}
.uniui-redo-filled:before {
content: "\e655";
}
.uniui-list:before {
content: "\e644";
}
.uniui-mail-open-filled:before {
content: "\e63a";
}
.uniui-hand-down-filled:before {
content: "\e63c";
}
.uniui-hand-down:before {
content: "\e63d";
}
.uniui-hand-up-filled:before {
content: "\e63e";
}
.uniui-hand-up:before {
content: "\e63f";
}
.uniui-heart-filled:before {
content: "\e641";
}
.uniui-mail-open:before {
content: "\e643";
}
.uniui-heart:before {
content: "\e639";
}
.uniui-loop:before {
content: "\e633";
}
.uniui-pulldown:before {
content: "\e632";
}
.uniui-scan:before {
content: "\e62a";
}
.uniui-bars:before {
content: "\e627";
}
.uniui-checkbox:before {
content: "\e62b";
}
.uniui-checkbox-filled:before {
content: "\e62c";
}
.uniui-shop:before {
content: "\e62f";
}
.uniui-headphones:before {
content: "\e630";
}
.uniui-cart:before {
content: "\e631";
}

View File

@@ -0,0 +1,664 @@
export type IconsData = {
id : string
name : string
font_family : string
css_prefix_text : string
description : string
glyphs : Array<IconsDataItem>
}
export type IconsDataItem = {
font_class : string
unicode : string
}
export const fontData = [
{
"font_class": "arrow-down",
"unicode": "\ue6be"
},
{
"font_class": "arrow-left",
"unicode": "\ue6bc"
},
{
"font_class": "arrow-right",
"unicode": "\ue6bb"
},
{
"font_class": "arrow-up",
"unicode": "\ue6bd"
},
{
"font_class": "auth",
"unicode": "\ue6ab"
},
{
"font_class": "auth-filled",
"unicode": "\ue6cc"
},
{
"font_class": "back",
"unicode": "\ue6b9"
},
{
"font_class": "bars",
"unicode": "\ue627"
},
{
"font_class": "calendar",
"unicode": "\ue6a0"
},
{
"font_class": "calendar-filled",
"unicode": "\ue6c0"
},
{
"font_class": "camera",
"unicode": "\ue65a"
},
{
"font_class": "camera-filled",
"unicode": "\ue658"
},
{
"font_class": "cart",
"unicode": "\ue631"
},
{
"font_class": "cart-filled",
"unicode": "\ue6d0"
},
{
"font_class": "chat",
"unicode": "\ue65d"
},
{
"font_class": "chat-filled",
"unicode": "\ue659"
},
{
"font_class": "chatboxes",
"unicode": "\ue696"
},
{
"font_class": "chatboxes-filled",
"unicode": "\ue692"
},
{
"font_class": "chatbubble",
"unicode": "\ue697"
},
{
"font_class": "chatbubble-filled",
"unicode": "\ue694"
},
{
"font_class": "checkbox",
"unicode": "\ue62b"
},
{
"font_class": "checkbox-filled",
"unicode": "\ue62c"
},
{
"font_class": "checkmarkempty",
"unicode": "\ue65c"
},
{
"font_class": "circle",
"unicode": "\ue65b"
},
{
"font_class": "circle-filled",
"unicode": "\ue65e"
},
{
"font_class": "clear",
"unicode": "\ue66d"
},
{
"font_class": "close",
"unicode": "\ue673"
},
{
"font_class": "closeempty",
"unicode": "\ue66c"
},
{
"font_class": "cloud-download",
"unicode": "\ue647"
},
{
"font_class": "cloud-download-filled",
"unicode": "\ue646"
},
{
"font_class": "cloud-upload",
"unicode": "\ue645"
},
{
"font_class": "cloud-upload-filled",
"unicode": "\ue648"
},
{
"font_class": "color",
"unicode": "\ue6cf"
},
{
"font_class": "color-filled",
"unicode": "\ue6c9"
},
{
"font_class": "compose",
"unicode": "\ue67f"
},
{
"font_class": "contact",
"unicode": "\ue693"
},
{
"font_class": "contact-filled",
"unicode": "\ue695"
},
{
"font_class": "down",
"unicode": "\ue6b8"
},
{
"font_class": "bottom",
"unicode": "\ue6b8"
},
{
"font_class": "download",
"unicode": "\ue68d"
},
{
"font_class": "download-filled",
"unicode": "\ue681"
},
{
"font_class": "email",
"unicode": "\ue69e"
},
{
"font_class": "email-filled",
"unicode": "\ue69a"
},
{
"font_class": "eye",
"unicode": "\ue651"
},
{
"font_class": "eye-filled",
"unicode": "\ue66a"
},
{
"font_class": "eye-slash",
"unicode": "\ue6b3"
},
{
"font_class": "eye-slash-filled",
"unicode": "\ue6b4"
},
{
"font_class": "fire",
"unicode": "\ue6a1"
},
{
"font_class": "fire-filled",
"unicode": "\ue6c5"
},
{
"font_class": "flag",
"unicode": "\ue65f"
},
{
"font_class": "flag-filled",
"unicode": "\ue660"
},
{
"font_class": "folder-add",
"unicode": "\ue6a9"
},
{
"font_class": "folder-add-filled",
"unicode": "\ue6c8"
},
{
"font_class": "font",
"unicode": "\ue6a3"
},
{
"font_class": "forward",
"unicode": "\ue6ba"
},
{
"font_class": "gear",
"unicode": "\ue664"
},
{
"font_class": "gear-filled",
"unicode": "\ue661"
},
{
"font_class": "gift",
"unicode": "\ue6a4"
},
{
"font_class": "gift-filled",
"unicode": "\ue6c4"
},
{
"font_class": "hand-down",
"unicode": "\ue63d"
},
{
"font_class": "hand-down-filled",
"unicode": "\ue63c"
},
{
"font_class": "hand-up",
"unicode": "\ue63f"
},
{
"font_class": "hand-up-filled",
"unicode": "\ue63e"
},
{
"font_class": "headphones",
"unicode": "\ue630"
},
{
"font_class": "heart",
"unicode": "\ue639"
},
{
"font_class": "heart-filled",
"unicode": "\ue641"
},
{
"font_class": "help",
"unicode": "\ue679"
},
{
"font_class": "help-filled",
"unicode": "\ue674"
},
{
"font_class": "home",
"unicode": "\ue662"
},
{
"font_class": "home-filled",
"unicode": "\ue663"
},
{
"font_class": "image",
"unicode": "\ue670"
},
{
"font_class": "image-filled",
"unicode": "\ue678"
},
{
"font_class": "images",
"unicode": "\ue650"
},
{
"font_class": "images-filled",
"unicode": "\ue64b"
},
{
"font_class": "info",
"unicode": "\ue669"
},
{
"font_class": "info-filled",
"unicode": "\ue649"
},
{
"font_class": "left",
"unicode": "\ue6b7"
},
{
"font_class": "link",
"unicode": "\ue6a5"
},
{
"font_class": "list",
"unicode": "\ue644"
},
{
"font_class": "location",
"unicode": "\ue6ae"
},
{
"font_class": "location-filled",
"unicode": "\ue6af"
},
{
"font_class": "locked",
"unicode": "\ue66b"
},
{
"font_class": "locked-filled",
"unicode": "\ue668"
},
{
"font_class": "loop",
"unicode": "\ue633"
},
{
"font_class": "mail-open",
"unicode": "\ue643"
},
{
"font_class": "mail-open-filled",
"unicode": "\ue63a"
},
{
"font_class": "map",
"unicode": "\ue667"
},
{
"font_class": "map-filled",
"unicode": "\ue666"
},
{
"font_class": "map-pin",
"unicode": "\ue6ad"
},
{
"font_class": "map-pin-ellipse",
"unicode": "\ue6ac"
},
{
"font_class": "medal",
"unicode": "\ue6a2"
},
{
"font_class": "medal-filled",
"unicode": "\ue6c3"
},
{
"font_class": "mic",
"unicode": "\ue671"
},
{
"font_class": "mic-filled",
"unicode": "\ue677"
},
{
"font_class": "micoff",
"unicode": "\ue67e"
},
{
"font_class": "micoff-filled",
"unicode": "\ue6b0"
},
{
"font_class": "minus",
"unicode": "\ue66f"
},
{
"font_class": "minus-filled",
"unicode": "\ue67d"
},
{
"font_class": "more",
"unicode": "\ue64d"
},
{
"font_class": "more-filled",
"unicode": "\ue64e"
},
{
"font_class": "navigate",
"unicode": "\ue66e"
},
{
"font_class": "navigate-filled",
"unicode": "\ue67a"
},
{
"font_class": "notification",
"unicode": "\ue6a6"
},
{
"font_class": "notification-filled",
"unicode": "\ue6c1"
},
{
"font_class": "paperclip",
"unicode": "\ue652"
},
{
"font_class": "paperplane",
"unicode": "\ue672"
},
{
"font_class": "paperplane-filled",
"unicode": "\ue675"
},
{
"font_class": "person",
"unicode": "\ue699"
},
{
"font_class": "person-filled",
"unicode": "\ue69d"
},
{
"font_class": "personadd",
"unicode": "\ue69f"
},
{
"font_class": "personadd-filled",
"unicode": "\ue698"
},
{
"font_class": "personadd-filled-copy",
"unicode": "\ue6d1"
},
{
"font_class": "phone",
"unicode": "\ue69c"
},
{
"font_class": "phone-filled",
"unicode": "\ue69b"
},
{
"font_class": "plus",
"unicode": "\ue676"
},
{
"font_class": "plus-filled",
"unicode": "\ue6c7"
},
{
"font_class": "plusempty",
"unicode": "\ue67b"
},
{
"font_class": "pulldown",
"unicode": "\ue632"
},
{
"font_class": "pyq",
"unicode": "\ue682"
},
{
"font_class": "qq",
"unicode": "\ue680"
},
{
"font_class": "redo",
"unicode": "\ue64a"
},
{
"font_class": "redo-filled",
"unicode": "\ue655"
},
{
"font_class": "refresh",
"unicode": "\ue657"
},
{
"font_class": "refresh-filled",
"unicode": "\ue656"
},
{
"font_class": "refreshempty",
"unicode": "\ue6bf"
},
{
"font_class": "reload",
"unicode": "\ue6b2"
},
{
"font_class": "right",
"unicode": "\ue6b5"
},
{
"font_class": "scan",
"unicode": "\ue62a"
},
{
"font_class": "search",
"unicode": "\ue654"
},
{
"font_class": "settings",
"unicode": "\ue653"
},
{
"font_class": "settings-filled",
"unicode": "\ue6ce"
},
{
"font_class": "shop",
"unicode": "\ue62f"
},
{
"font_class": "shop-filled",
"unicode": "\ue6cd"
},
{
"font_class": "smallcircle",
"unicode": "\ue67c"
},
{
"font_class": "smallcircle-filled",
"unicode": "\ue665"
},
{
"font_class": "sound",
"unicode": "\ue684"
},
{
"font_class": "sound-filled",
"unicode": "\ue686"
},
{
"font_class": "spinner-cycle",
"unicode": "\ue68a"
},
{
"font_class": "staff",
"unicode": "\ue6a7"
},
{
"font_class": "staff-filled",
"unicode": "\ue6cb"
},
{
"font_class": "star",
"unicode": "\ue688"
},
{
"font_class": "star-filled",
"unicode": "\ue68f"
},
{
"font_class": "starhalf",
"unicode": "\ue683"
},
{
"font_class": "trash",
"unicode": "\ue687"
},
{
"font_class": "trash-filled",
"unicode": "\ue685"
},
{
"font_class": "tune",
"unicode": "\ue6aa"
},
{
"font_class": "tune-filled",
"unicode": "\ue6ca"
},
{
"font_class": "undo",
"unicode": "\ue64f"
},
{
"font_class": "undo-filled",
"unicode": "\ue64c"
},
{
"font_class": "up",
"unicode": "\ue6b6"
},
{
"font_class": "top",
"unicode": "\ue6b6"
},
{
"font_class": "upload",
"unicode": "\ue690"
},
{
"font_class": "upload-filled",
"unicode": "\ue68e"
},
{
"font_class": "videocam",
"unicode": "\ue68c"
},
{
"font_class": "videocam-filled",
"unicode": "\ue689"
},
{
"font_class": "vip",
"unicode": "\ue6a8"
},
{
"font_class": "vip-filled",
"unicode": "\ue6c6"
},
{
"font_class": "wallet",
"unicode": "\ue6b1"
},
{
"font_class": "wallet-filled",
"unicode": "\ue6c2"
},
{
"font_class": "weibo",
"unicode": "\ue68b"
},
{
"font_class": "weixin",
"unicode": "\ue691"
}
] as IconsDataItem[]
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)

View File

@@ -0,0 +1,649 @@
export const fontData = [
{
"font_class": "arrow-down",
"unicode": "\ue6be"
},
{
"font_class": "arrow-left",
"unicode": "\ue6bc"
},
{
"font_class": "arrow-right",
"unicode": "\ue6bb"
},
{
"font_class": "arrow-up",
"unicode": "\ue6bd"
},
{
"font_class": "auth",
"unicode": "\ue6ab"
},
{
"font_class": "auth-filled",
"unicode": "\ue6cc"
},
{
"font_class": "back",
"unicode": "\ue6b9"
},
{
"font_class": "bars",
"unicode": "\ue627"
},
{
"font_class": "calendar",
"unicode": "\ue6a0"
},
{
"font_class": "calendar-filled",
"unicode": "\ue6c0"
},
{
"font_class": "camera",
"unicode": "\ue65a"
},
{
"font_class": "camera-filled",
"unicode": "\ue658"
},
{
"font_class": "cart",
"unicode": "\ue631"
},
{
"font_class": "cart-filled",
"unicode": "\ue6d0"
},
{
"font_class": "chat",
"unicode": "\ue65d"
},
{
"font_class": "chat-filled",
"unicode": "\ue659"
},
{
"font_class": "chatboxes",
"unicode": "\ue696"
},
{
"font_class": "chatboxes-filled",
"unicode": "\ue692"
},
{
"font_class": "chatbubble",
"unicode": "\ue697"
},
{
"font_class": "chatbubble-filled",
"unicode": "\ue694"
},
{
"font_class": "checkbox",
"unicode": "\ue62b"
},
{
"font_class": "checkbox-filled",
"unicode": "\ue62c"
},
{
"font_class": "checkmarkempty",
"unicode": "\ue65c"
},
{
"font_class": "circle",
"unicode": "\ue65b"
},
{
"font_class": "circle-filled",
"unicode": "\ue65e"
},
{
"font_class": "clear",
"unicode": "\ue66d"
},
{
"font_class": "close",
"unicode": "\ue673"
},
{
"font_class": "closeempty",
"unicode": "\ue66c"
},
{
"font_class": "cloud-download",
"unicode": "\ue647"
},
{
"font_class": "cloud-download-filled",
"unicode": "\ue646"
},
{
"font_class": "cloud-upload",
"unicode": "\ue645"
},
{
"font_class": "cloud-upload-filled",
"unicode": "\ue648"
},
{
"font_class": "color",
"unicode": "\ue6cf"
},
{
"font_class": "color-filled",
"unicode": "\ue6c9"
},
{
"font_class": "compose",
"unicode": "\ue67f"
},
{
"font_class": "contact",
"unicode": "\ue693"
},
{
"font_class": "contact-filled",
"unicode": "\ue695"
},
{
"font_class": "down",
"unicode": "\ue6b8"
},
{
"font_class": "bottom",
"unicode": "\ue6b8"
},
{
"font_class": "download",
"unicode": "\ue68d"
},
{
"font_class": "download-filled",
"unicode": "\ue681"
},
{
"font_class": "email",
"unicode": "\ue69e"
},
{
"font_class": "email-filled",
"unicode": "\ue69a"
},
{
"font_class": "eye",
"unicode": "\ue651"
},
{
"font_class": "eye-filled",
"unicode": "\ue66a"
},
{
"font_class": "eye-slash",
"unicode": "\ue6b3"
},
{
"font_class": "eye-slash-filled",
"unicode": "\ue6b4"
},
{
"font_class": "fire",
"unicode": "\ue6a1"
},
{
"font_class": "fire-filled",
"unicode": "\ue6c5"
},
{
"font_class": "flag",
"unicode": "\ue65f"
},
{
"font_class": "flag-filled",
"unicode": "\ue660"
},
{
"font_class": "folder-add",
"unicode": "\ue6a9"
},
{
"font_class": "folder-add-filled",
"unicode": "\ue6c8"
},
{
"font_class": "font",
"unicode": "\ue6a3"
},
{
"font_class": "forward",
"unicode": "\ue6ba"
},
{
"font_class": "gear",
"unicode": "\ue664"
},
{
"font_class": "gear-filled",
"unicode": "\ue661"
},
{
"font_class": "gift",
"unicode": "\ue6a4"
},
{
"font_class": "gift-filled",
"unicode": "\ue6c4"
},
{
"font_class": "hand-down",
"unicode": "\ue63d"
},
{
"font_class": "hand-down-filled",
"unicode": "\ue63c"
},
{
"font_class": "hand-up",
"unicode": "\ue63f"
},
{
"font_class": "hand-up-filled",
"unicode": "\ue63e"
},
{
"font_class": "headphones",
"unicode": "\ue630"
},
{
"font_class": "heart",
"unicode": "\ue639"
},
{
"font_class": "heart-filled",
"unicode": "\ue641"
},
{
"font_class": "help",
"unicode": "\ue679"
},
{
"font_class": "help-filled",
"unicode": "\ue674"
},
{
"font_class": "home",
"unicode": "\ue662"
},
{
"font_class": "home-filled",
"unicode": "\ue663"
},
{
"font_class": "image",
"unicode": "\ue670"
},
{
"font_class": "image-filled",
"unicode": "\ue678"
},
{
"font_class": "images",
"unicode": "\ue650"
},
{
"font_class": "images-filled",
"unicode": "\ue64b"
},
{
"font_class": "info",
"unicode": "\ue669"
},
{
"font_class": "info-filled",
"unicode": "\ue649"
},
{
"font_class": "left",
"unicode": "\ue6b7"
},
{
"font_class": "link",
"unicode": "\ue6a5"
},
{
"font_class": "list",
"unicode": "\ue644"
},
{
"font_class": "location",
"unicode": "\ue6ae"
},
{
"font_class": "location-filled",
"unicode": "\ue6af"
},
{
"font_class": "locked",
"unicode": "\ue66b"
},
{
"font_class": "locked-filled",
"unicode": "\ue668"
},
{
"font_class": "loop",
"unicode": "\ue633"
},
{
"font_class": "mail-open",
"unicode": "\ue643"
},
{
"font_class": "mail-open-filled",
"unicode": "\ue63a"
},
{
"font_class": "map",
"unicode": "\ue667"
},
{
"font_class": "map-filled",
"unicode": "\ue666"
},
{
"font_class": "map-pin",
"unicode": "\ue6ad"
},
{
"font_class": "map-pin-ellipse",
"unicode": "\ue6ac"
},
{
"font_class": "medal",
"unicode": "\ue6a2"
},
{
"font_class": "medal-filled",
"unicode": "\ue6c3"
},
{
"font_class": "mic",
"unicode": "\ue671"
},
{
"font_class": "mic-filled",
"unicode": "\ue677"
},
{
"font_class": "micoff",
"unicode": "\ue67e"
},
{
"font_class": "micoff-filled",
"unicode": "\ue6b0"
},
{
"font_class": "minus",
"unicode": "\ue66f"
},
{
"font_class": "minus-filled",
"unicode": "\ue67d"
},
{
"font_class": "more",
"unicode": "\ue64d"
},
{
"font_class": "more-filled",
"unicode": "\ue64e"
},
{
"font_class": "navigate",
"unicode": "\ue66e"
},
{
"font_class": "navigate-filled",
"unicode": "\ue67a"
},
{
"font_class": "notification",
"unicode": "\ue6a6"
},
{
"font_class": "notification-filled",
"unicode": "\ue6c1"
},
{
"font_class": "paperclip",
"unicode": "\ue652"
},
{
"font_class": "paperplane",
"unicode": "\ue672"
},
{
"font_class": "paperplane-filled",
"unicode": "\ue675"
},
{
"font_class": "person",
"unicode": "\ue699"
},
{
"font_class": "person-filled",
"unicode": "\ue69d"
},
{
"font_class": "personadd",
"unicode": "\ue69f"
},
{
"font_class": "personadd-filled",
"unicode": "\ue698"
},
{
"font_class": "personadd-filled-copy",
"unicode": "\ue6d1"
},
{
"font_class": "phone",
"unicode": "\ue69c"
},
{
"font_class": "phone-filled",
"unicode": "\ue69b"
},
{
"font_class": "plus",
"unicode": "\ue676"
},
{
"font_class": "plus-filled",
"unicode": "\ue6c7"
},
{
"font_class": "plusempty",
"unicode": "\ue67b"
},
{
"font_class": "pulldown",
"unicode": "\ue632"
},
{
"font_class": "pyq",
"unicode": "\ue682"
},
{
"font_class": "qq",
"unicode": "\ue680"
},
{
"font_class": "redo",
"unicode": "\ue64a"
},
{
"font_class": "redo-filled",
"unicode": "\ue655"
},
{
"font_class": "refresh",
"unicode": "\ue657"
},
{
"font_class": "refresh-filled",
"unicode": "\ue656"
},
{
"font_class": "refreshempty",
"unicode": "\ue6bf"
},
{
"font_class": "reload",
"unicode": "\ue6b2"
},
{
"font_class": "right",
"unicode": "\ue6b5"
},
{
"font_class": "scan",
"unicode": "\ue62a"
},
{
"font_class": "search",
"unicode": "\ue654"
},
{
"font_class": "settings",
"unicode": "\ue653"
},
{
"font_class": "settings-filled",
"unicode": "\ue6ce"
},
{
"font_class": "shop",
"unicode": "\ue62f"
},
{
"font_class": "shop-filled",
"unicode": "\ue6cd"
},
{
"font_class": "smallcircle",
"unicode": "\ue67c"
},
{
"font_class": "smallcircle-filled",
"unicode": "\ue665"
},
{
"font_class": "sound",
"unicode": "\ue684"
},
{
"font_class": "sound-filled",
"unicode": "\ue686"
},
{
"font_class": "spinner-cycle",
"unicode": "\ue68a"
},
{
"font_class": "staff",
"unicode": "\ue6a7"
},
{
"font_class": "staff-filled",
"unicode": "\ue6cb"
},
{
"font_class": "star",
"unicode": "\ue688"
},
{
"font_class": "star-filled",
"unicode": "\ue68f"
},
{
"font_class": "starhalf",
"unicode": "\ue683"
},
{
"font_class": "trash",
"unicode": "\ue687"
},
{
"font_class": "trash-filled",
"unicode": "\ue685"
},
{
"font_class": "tune",
"unicode": "\ue6aa"
},
{
"font_class": "tune-filled",
"unicode": "\ue6ca"
},
{
"font_class": "undo",
"unicode": "\ue64f"
},
{
"font_class": "undo-filled",
"unicode": "\ue64c"
},
{
"font_class": "up",
"unicode": "\ue6b6"
},
{
"font_class": "top",
"unicode": "\ue6b6"
},
{
"font_class": "upload",
"unicode": "\ue690"
},
{
"font_class": "upload-filled",
"unicode": "\ue68e"
},
{
"font_class": "videocam",
"unicode": "\ue68c"
},
{
"font_class": "videocam-filled",
"unicode": "\ue689"
},
{
"font_class": "vip",
"unicode": "\ue6a8"
},
{
"font_class": "vip-filled",
"unicode": "\ue6c6"
},
{
"font_class": "wallet",
"unicode": "\ue6b1"
},
{
"font_class": "wallet-filled",
"unicode": "\ue6c2"
},
{
"font_class": "weibo",
"unicode": "\ue68b"
},
{
"font_class": "weixin",
"unicode": "\ue691"
}
]
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)

View File

@@ -0,0 +1,89 @@
{
"id": "uni-icons",
"displayName": "uni-icons 图标",
"version": "2.0.10",
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
"keywords": [
"uni-ui",
"uniui",
"icon",
"图标"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": "^3.2.14"
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "n"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y",
"app-uvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
## Icons 图标
> **组件名uni-icons**
> 代码块: `uIcons`
用于展示 icons 图标 。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons)
#### 如使用过程中有任何问题或者您对uni-ui有一些好的建议欢迎加入 uni-ui 交流群871950839

View File

@@ -0,0 +1,25 @@
## 1.3.62024-10-15
- 修复 微信小程序中的getSystemInfo警告
## 1.3.52024-10-12
- 修复 微信小程序中的getSystemInfo警告
## 1.3.42024-10-12
- 修复 微信小程序中的getSystemInfo警告
## 1.3.32022-01-20
- 新增 showText属性 ,是否显示文本
## 1.3.22022-01-19
- 修复 nvue 平台下不显示文本的bug
## 1.3.12022-01-19
- 修复 微信小程序平台样式选择器报警告的问题
## 1.3.02021-11-19
- 优化 组件UI并提供设计资源详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
## 1.2.12021-08-24
- 新增 支持国际化
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.82021-05-12
- 新增 组件示例地址
## 1.1.72021-03-30
- 修复 uni-load-more 在首页使用时h5 平台报 'uni is not defined' 的 bug
## 1.1.62021-02-05
- 调整为uni_modules目录规范

Some files were not shown because too many files have changed in this diff Show More