初始上传
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<unipopup ref="couponCategoryPop" type="center">
|
||||
<view class="coupon-category-pop">
|
||||
<view class="header flex justify-between">
|
||||
<view class="title">选择分类</view>
|
||||
<!-- <view class="pop-header-close" @click="$refs.couponCategoryPop.close()">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- :checkStrictly="true" -->
|
||||
<view :overflow-y="true" class="body">
|
||||
<scroll-view class="tree" :overflow-y="true">
|
||||
<DaTreeVue2
|
||||
ref="DaTreeRef"
|
||||
:data="treeData"
|
||||
labelField="category_name"
|
||||
valueField="category_id"
|
||||
childrenField="child_list"
|
||||
:themeColors="'var(--primary-color)'"
|
||||
expandChecked
|
||||
showCheckbox
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue"
|
||||
@change="handleTreeChange"></DaTreeVue2>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="footer flex justify-end">
|
||||
<button type="default" class="confirm btn" @click="confirm">确认</button>
|
||||
<button type="default" class="btn" @click="$refs.couponCategoryPop.close()">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</unipopup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DaTreeVue2 from '@/components/da-tree-vue2/index.vue'
|
||||
import unipopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import index from './index.js';
|
||||
export default {
|
||||
components: {
|
||||
DaTreeVue2,
|
||||
unipopup,
|
||||
},
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
87
addon/cashier/source/os/components/coupon-category-popup/index.js
Executable file
87
addon/cashier/source/os/components/coupon-category-popup/index.js
Executable file
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
getGoodsCategory
|
||||
} from '@/api/goods.js'
|
||||
export default {
|
||||
name: 'couponCategoryPopup',
|
||||
data() {
|
||||
return {
|
||||
treeData: [],
|
||||
defaultCheckedKeysValue: [],
|
||||
checkList: [], //选中以及半选中数据
|
||||
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getGoodsCategoryFn()
|
||||
},
|
||||
methods: {
|
||||
getGoodsCategoryFn() {
|
||||
getGoodsCategory({
|
||||
level: 3
|
||||
}).then(res => {
|
||||
this.treeData = res.data
|
||||
})
|
||||
},
|
||||
open(value) {
|
||||
this.defaultCheckedKeysValue = this.$util.deepClone(value)
|
||||
this.$refs.couponCategoryPop.open()
|
||||
},
|
||||
handleTreeChange(val) {
|
||||
this.defaultCheckedKeysValue = this.$util.deepClone(val)
|
||||
let halfCheckList = this.$refs.DaTreeRef.getHalfCheckedKeys()||[]
|
||||
this.checkList = this.$util.deepClone(val.concat(halfCheckList))
|
||||
},
|
||||
//处理数据
|
||||
getSelectedIdsAndNames(tree_selected, tree_all) {
|
||||
let name_arr = [];
|
||||
let id_arr = [];
|
||||
let selected_num = 0;
|
||||
for (let i in tree_selected) {
|
||||
let item_selected = tree_selected[i];
|
||||
let item_all = null;
|
||||
tree_all.forEach((item) => {
|
||||
if (item.category_id === item_selected.category_id) {
|
||||
item_all = item;
|
||||
return;
|
||||
}
|
||||
})
|
||||
if (!item_all) throw '对比数据有误';
|
||||
let title = item_selected.category_name;
|
||||
id_arr.push(item_selected.category_id);
|
||||
if (item_selected.child_num > 0) {
|
||||
let res = this.getSelectedIdsAndNames(item_selected.child_list, item_all.child_list);
|
||||
if (res.selected_num == item_all.child_num) {
|
||||
selected_num++;
|
||||
} else {
|
||||
title += '(' + res.name_arr.join('、') + ')';
|
||||
}
|
||||
id_arr = id_arr.concat(res.id_arr);
|
||||
} else {
|
||||
selected_num++;
|
||||
}
|
||||
name_arr.push(title);
|
||||
}
|
||||
return {
|
||||
selected_num: selected_num,
|
||||
name_arr: name_arr,
|
||||
id_arr: id_arr,
|
||||
};
|
||||
},
|
||||
confirm() {
|
||||
if(!this.checkList.length){
|
||||
this.$util.showToast({
|
||||
title: "请选择商品分类"
|
||||
});
|
||||
return false
|
||||
}
|
||||
getGoodsCategory({
|
||||
level: 3,
|
||||
category_ids:this.checkList.join(',')
|
||||
}).then(res => {
|
||||
let selectedData = this.getSelectedIdsAndNames(res.data, this.treeData);
|
||||
this.$emit('confirm',selectedData)
|
||||
this.$refs.couponCategoryPop.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
42
addon/cashier/source/os/components/coupon-category-popup/index.scss
Executable file
42
addon/cashier/source/os/components/coupon-category-popup/index.scss
Executable file
@@ -0,0 +1,42 @@
|
||||
.coupon-category-pop{
|
||||
width: 7rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.06rem;
|
||||
.header{
|
||||
padding: 0.15rem 0.2rem;
|
||||
font-size: 0.14rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
|
||||
}
|
||||
.body{
|
||||
padding: 0.2rem 0.3rem;
|
||||
padding-bottom: 0.15rem;
|
||||
box-sizing: border-box;
|
||||
height: 4rem;
|
||||
.tree{
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.footer{
|
||||
padding: 0 0.3rem;
|
||||
padding-bottom: 0.15rem;
|
||||
.btn {
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
padding: 0 0.2rem;
|
||||
height: 0.36rem;
|
||||
line-height: .36rem;
|
||||
font-size: 0.14rem;
|
||||
border-radius: 3px;
|
||||
|
||||
&.confirm{
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
margin-right: 0.15rem;
|
||||
&::after{
|
||||
border-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
addon/cashier/source/os/components/da-tree-vue2/changelog.md
Executable file
110
addon/cashier/source/os/components/da-tree-vue2/changelog.md
Executable file
@@ -0,0 +1,110 @@
|
||||
# 1.4.1
|
||||
|
||||
## 版本调整
|
||||
|
||||
建议更新,但需要注意,异步数据的时候,后台需返回 leaf 字段来判断是否末项数据
|
||||
|
||||
1. **调整数据项格式,新增 `leaf` 字段,来判断是否为末节点**
|
||||
2. **调整数据项格式,新增 `sort` 字段,来排序节点位置**
|
||||
3. **注意:异步加载数据,当为末项的时候,需要服务端数据返回 `leaf` 字段**
|
||||
4. 新增 `alwaysFirstLoad` ,即异步数据总会在第一次展开节点时,拉取一次后台数据,来比对是否一致
|
||||
5. 拆分 `field` 属性,**注意: 1.5.0 版本后将移除 `field` 属性**
|
||||
6. 新增 `labelField` 同 `field.label`,指定节点对象中某个属性为**标签**字段,默认`label`
|
||||
7. 新增 `valueField` 同 `field.key`,指定节点对象中某个属性为**值**字段,默认`value`
|
||||
8. 新增 `childrenField` 同 `field.children`,指定节点对象中某个属性为**子树节点**字段,默认`children`
|
||||
9. 新增 `disabledField` 同 `field.disabled`,指定节点对象中某个属性为**禁用**字段,默认`disabled`
|
||||
10. 新增 `appendField` 同 `field.append`,指定节点对象中某个属性为**副标签**字段,默认`append`
|
||||
11. 新增 `leafField` 同 `field.label`,指定节点对象中某个属性为**末级节点**字段,默认`leaf`
|
||||
12. 新增 `sortField` 同 `field.label`,指定节点对象中某个属性为**排序**字段,默认`sort`
|
||||
13. 新增 `isLeafFn` ,用来自定义控制数据项的末项
|
||||
14. 更多的项目示例
|
||||
15. 支持单选取消选中
|
||||
16. 修复节点展开时可能存在的 bug
|
||||
17. 修复节点选择可能存在的 bug
|
||||
18. 调整为子节点默认继承父节点禁用属性
|
||||
19. `setExpandedKeys` 添加参数一为 `all` 即可支持一键展开/收起全部节点
|
||||
20. 其它更多优化
|
||||
|
||||
# 1.3.4
|
||||
|
||||
优化
|
||||
|
||||
1. 优化图标字体命名
|
||||
|
||||
# 1.3.3
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.3.2
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.3.1.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复 APP 兼容性引起的报错
|
||||
|
||||
# 1.3.1
|
||||
|
||||
## 建议更新
|
||||
|
||||
### 1.2.2~1.3.1 更新预览
|
||||
|
||||
1. 新增支持主题换色
|
||||
2. 新增支持点击标签也能选中节点
|
||||
3. 新增`field`字段 `append` 用于在标签后面显示小提示
|
||||
4. 方法`setExpandedKeys`支持加载动态数据
|
||||
5. 支持单选的`onlyRadioLeaf`为`true`时可点父节点展开/收起
|
||||
6. 新增 `expandChecked`,控制选择时是否展开当前已选的所有下级节点
|
||||
7. 新增 `checkedDisabled`,支持渲染禁用值
|
||||
8. 新增 `packDisabledkey`,支持返回已选中的禁用的 key
|
||||
9. 更多细节修复、优化请移步 Vue3 版的更新日志
|
||||
|
||||
后续版本仍不会实时同步 Vue3 版本,如急需新功能,请移步 Vue3 版
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.2.2
|
||||
|
||||
## 建议更新,优化诸多问题
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.2.1
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.2.0.1
|
||||
|
||||
优化
|
||||
|
||||
1. 优化小程序兼容
|
||||
|
||||
# 1.2.0
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.1.1.1
|
||||
|
||||
修复
|
||||
|
||||
1. 修复同步版本的错误写法引起的报错
|
||||
|
||||
# 1.1.1
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.1.0
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.0.6
|
||||
|
||||
新增
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384&update_log)
|
||||
|
||||
# 1.0.5
|
||||
|
||||
版本同步于 Vue3 版,[查看 Vue3 版更新日志](https://ext.dcloud.net.cn/plugin?id=12384),基于 Vue2 进行开发,支持单选、多选,全平台兼容。
|
||||
1105
addon/cashier/source/os/components/da-tree-vue2/index.vue
Executable file
1105
addon/cashier/source/os/components/da-tree-vue2/index.vue
Executable file
File diff suppressed because it is too large
Load Diff
183
addon/cashier/source/os/components/da-tree-vue2/props.js
Executable file
183
addon/cashier/source/os/components/da-tree-vue2/props.js
Executable file
@@ -0,0 +1,183 @@
|
||||
// @ts-nocheck
|
||||
export default {
|
||||
/**
|
||||
* 树的数据
|
||||
*/
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
/**
|
||||
* 主题色
|
||||
*/
|
||||
themeColors: {
|
||||
type: String,
|
||||
default: '#007aff',
|
||||
},
|
||||
/**
|
||||
* 是否开启多选,默认单选
|
||||
*/
|
||||
showCheckbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认选中的节点,注意单选时为单个key,多选时为key的数组
|
||||
*/
|
||||
defaultCheckedKeys: {
|
||||
type: [Array, String, Number],
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 选择框的位置,可选 left/right
|
||||
*/
|
||||
checkboxPlacement: {
|
||||
type: String,
|
||||
default: 'left',
|
||||
},
|
||||
/**
|
||||
* 是否默认展开全部
|
||||
*/
|
||||
defaultExpandAll: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 默认展开的节点
|
||||
*/
|
||||
defaultExpandedKeys: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否自动展开到选中的节点,默认不展开
|
||||
*/
|
||||
expandChecked: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 子项缩进距离,默认40,单位rpx
|
||||
*/
|
||||
indent: {
|
||||
type: Number,
|
||||
default: 0.4,
|
||||
},
|
||||
/**
|
||||
* (旧)字段对应内容,默认为 {label: 'label',key: 'key', children: 'children', disabled: 'disabled', append: 'append'}
|
||||
* 注意:1.5.0版本后不再兼容
|
||||
*/
|
||||
field: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 标签字段(新,拆分了)
|
||||
*/
|
||||
labelField: {
|
||||
type: String,
|
||||
default: 'label',
|
||||
},
|
||||
/**
|
||||
* 值字段(新,拆分了)
|
||||
*/
|
||||
valueField: {
|
||||
type: String,
|
||||
default: 'value',
|
||||
},
|
||||
/**
|
||||
* 下级字段(新,拆分了)
|
||||
*/
|
||||
childrenField: {
|
||||
type: String,
|
||||
default: 'children',
|
||||
},
|
||||
/**
|
||||
* 禁用字段(新,拆分了)
|
||||
*/
|
||||
disabledField: {
|
||||
type: String,
|
||||
default: 'disabled',
|
||||
},
|
||||
/**
|
||||
* 末级节点字段(新,拆分了)
|
||||
*/
|
||||
leafField: {
|
||||
type: String,
|
||||
default: 'leaf',
|
||||
},
|
||||
/**
|
||||
* 副标签字段(新,拆分了)
|
||||
*/
|
||||
appendField: {
|
||||
type: String,
|
||||
default: 'append',
|
||||
},
|
||||
/**
|
||||
* 排序字段(新,拆分了)
|
||||
*/
|
||||
sortField: {
|
||||
type: String,
|
||||
default: 'sort',
|
||||
},
|
||||
isLeafFn: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否显示单选图标,默认显示
|
||||
*/
|
||||
showRadioIcon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/**
|
||||
* 单选时只允许选中末级,默认可随意选中
|
||||
*/
|
||||
onlyRadioLeaf: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 多选时,是否执行父子不关联的任意勾选,默认父子关联
|
||||
*/
|
||||
checkStrictly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 为 true 时,空的 children 数组会显示展开图标
|
||||
*/
|
||||
loadMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 异步加载接口
|
||||
*/
|
||||
loadApi: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
/**
|
||||
* 是否总在首次的时候加载一下内容,来比对是否一致
|
||||
*/
|
||||
alwaysFirstLoad: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否渲染(操作)禁用值
|
||||
*/
|
||||
checkedDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
/**
|
||||
* 是否返回已禁用的但已选中的key
|
||||
*/
|
||||
packDisabledkey: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
}
|
||||
303
addon/cashier/source/os/components/da-tree-vue2/readme.md
Executable file
303
addon/cashier/source/os/components/da-tree-vue2/readme.md
Executable file
@@ -0,0 +1,303 @@
|
||||
# da-tree-vue2
|
||||
|
||||
一个基于 Vue2 的 tree(树)组件,同时支持主题换色,可能是最适合你的 tree(树)组件
|
||||
|
||||
`内容同步于 Vue3 版本,在此查看 ===>` **[Vue3 版](https://ext.dcloud.net.cn/plugin?id=12384)**
|
||||
|
||||
_与 Vue3 版本版本不同的是,此版本兼容更全面,比如 360 小程序、快应用等均支持_
|
||||
|
||||
### 关于使用
|
||||
|
||||
可在右侧的`使用 HBuilderX 导入插件`或`下载示例项目ZIP`,方便快速上手。
|
||||
|
||||
可通过下方的示例及文档说明,进一步了解使用组件相关细节参数。
|
||||
|
||||
插件地址:https://ext.dcloud.net.cn/plugin?id=12692
|
||||
|
||||
### 组件示例
|
||||
|
||||
```jsx
|
||||
<template>
|
||||
<view>
|
||||
<view>多选</view>
|
||||
<view><button @click="doCheckedTree(['2'],true)">全选</button></view>
|
||||
<view><button @click="doCheckedTree(['2'],false)">取消全选</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],true)">选中指定节点</button></view>
|
||||
<view><button @click="doCheckedTree(['211','222'],false)">取消选中指定节点</button></view>
|
||||
<view><button @click="doExpandTree('all',true)">展开全部节点</button></view>
|
||||
<view><button @click="doExpandTree('all',false)">收起全部节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],true)">展开节点</button></view>
|
||||
<view><button @click="doExpandTree(['22','23'],false)">收起节点</button></view>
|
||||
<DaTreeVue2
|
||||
ref="DaTreeRef"
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
showCheckbox
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange" />
|
||||
|
||||
<view>单选</view>
|
||||
<DaTreeVue2
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
defaultExpandAll
|
||||
:defaultCheckedKeys="defaultCheckedKeysValue2"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange" />
|
||||
<view>默认展开指定节点</view>
|
||||
<DaTreeVue2
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
:defaultExpandedKeys="defaultExpandKeysValue3"
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange" />
|
||||
<view>异步加载数据</view>
|
||||
<DaTreeVue2
|
||||
:data="roomTreeData"
|
||||
labelField="name"
|
||||
valueField="id"
|
||||
showCheckbox
|
||||
loadMode
|
||||
:loadApi="GetApiData"
|
||||
defaultExpandAll
|
||||
@change="handleTreeChange"
|
||||
@expand="handleExpandChange" />
|
||||
</view>
|
||||
</template>
|
||||
```
|
||||
|
||||
```js
|
||||
/**
|
||||
* 模拟创建一个接口数据
|
||||
*/
|
||||
function GetApiData(currentNode) {
|
||||
const { key } = currentNode
|
||||
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 模拟返回空数据
|
||||
if (key.indexOf('-') > -1) {
|
||||
return resolve(null)
|
||||
// return resolve([])
|
||||
}
|
||||
|
||||
return resolve([
|
||||
{
|
||||
id: `${key}-1`,
|
||||
name: `行政部X${key}-1`,
|
||||
},
|
||||
{
|
||||
id: `${key}-2`,
|
||||
name: `财务部X${key}-2`,
|
||||
append: '定义了末项数据',
|
||||
leaf: true,
|
||||
},
|
||||
{
|
||||
id: `${key}-3`,
|
||||
name: `资源部X${key}-3`,
|
||||
},
|
||||
{
|
||||
id: `${key}-4`,
|
||||
name: `资源部X${key}-3`,
|
||||
append: '被禁用,无展开图标',
|
||||
disabled: true,
|
||||
},
|
||||
])
|
||||
}, 2000)
|
||||
})
|
||||
}
|
||||
|
||||
import DaTreeVue2 from '@/components/da-tree-vue2/index.vue'
|
||||
export default {
|
||||
components: { DaTreeVue2 },
|
||||
data() {
|
||||
return {
|
||||
GetApiData,
|
||||
// key的类型必须对应树数据key的类型
|
||||
defaultCheckedKeysValue: ['211', '222'],
|
||||
defaultCheckedKeysValue2: '222',
|
||||
defaultExpandKeysValue3: ['212', '231'],
|
||||
roomTreeData: [
|
||||
{
|
||||
id: '2',
|
||||
name: '行政中心',
|
||||
children: [
|
||||
{
|
||||
id: '21',
|
||||
name: '行政部',
|
||||
children: [
|
||||
{
|
||||
id: '211',
|
||||
name: '行政一部',
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
id: '212',
|
||||
name: '行政二部',
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '22',
|
||||
name: '财务部',
|
||||
children: [
|
||||
{
|
||||
id: '221',
|
||||
name: '财务一部',
|
||||
children: [],
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
id: '222',
|
||||
name: '财务二部',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '23',
|
||||
name: '人力资源部',
|
||||
children: [
|
||||
{
|
||||
id: '231',
|
||||
name: '人力一部',
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
id: '232',
|
||||
name: '人力二部',
|
||||
append: '更多示例,请下载示例项目查看',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doExpandTree(keys, expand) {
|
||||
this.$refs.DaTreeRef?.setExpandedKeys(keys, expand)
|
||||
|
||||
const gek = this.$refs.DaTreeRef?.getExpandedKeys()
|
||||
console.log('当前已展开的KEY ==>', gek)
|
||||
},
|
||||
doCheckedTree(keys, checked) {
|
||||
this.$refs.DaTreeRef?.setCheckedKeys(keys, checked)
|
||||
|
||||
const gek = this.$refs.DaTreeRef?.getCheckedKeys()
|
||||
console.log('当前已选中的KEY ==>', gek)
|
||||
},
|
||||
handleTreeChange(allSelectedKeys, currentItem) {
|
||||
console.log('handleTreeChange ==>', allSelectedKeys, currentItem)
|
||||
},
|
||||
handleExpandChange(expand, currentItem) {
|
||||
console.log('handleExpandChange ==>', expand, currentItem)
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
** 更多示例请下载/导入示例项目 ZIP 查看 **
|
||||
|
||||
### 组件参数
|
||||
|
||||
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|
||||
| :------------------ | :------------------------------ | :--------- | :--- | :--------------------------------------------------------------------------- |
|
||||
| data | `Array` | - | 是 | 树的数据 |
|
||||
| themeColor | `String` | `#007aff` | 否 | 主题色,十六进制 |
|
||||
| defaultCheckedKeys | `Array` \| `Number` \| `String` | - | 否 | 默认选中的节点,单选为单个 key,多选为 key 的数组 |
|
||||
| showCheckbox | `Boolean` | `false` | 否 | 是否开启多选,默认单选 |
|
||||
| checkStrictly | `Boolean` | `false` | 否 | 多选时,是否执行父子不关联的任意勾选,默认父子关联 |
|
||||
| showRadioIcon | `Boolean` | `true` | 否 | 是否显示单选图标,默认显示 |
|
||||
| onlyRadioLeaf | `Boolean` | `true` | 否 | 单选时只允许选中末级,默认可随意选中 |
|
||||
| defaultExpandAll | `Boolean` | `false` | 否 | 是否默认展开全部 |
|
||||
| defaultExpandedKeys | `Array` | - | 否 | 默认展开的节点 |
|
||||
| indent | `Number` | `40` | 否 | 子项缩进距离,单位 rpx |
|
||||
| checkboxPlacement | `String` | `left` | 否 | 选择框的位置,可选 left/right |
|
||||
| loadMode | `Boolean` | `false` | 否 | 为 true 时,空的 children 数组会显示展开图标 |
|
||||
| loadApi | `Function` | - | 否 | 选择框的位置,可选 left/right |
|
||||
| checkedDisabled | `Boolean` | `false` | 否 | 是否渲染禁用值,默认不渲染 |
|
||||
| packDisabledkey | `Boolean` | `true` | 否 | 是否返回已禁用的但已选中的 key,默认返回禁用已选值 |
|
||||
| expandChecked | `Boolean` | `false` | 否 | 是否自动展开到选中的节点,默认不展开 |
|
||||
| alwaysFirstLoad | `Boolean` | `false` | 否 | 是否总在首次的时候加载一下内容,默认不加载,否则只有展开末级节点才会加载数据 |
|
||||
| isLeafFn | `Function` | - | 否 | 自定义函数返回来控制数据项的末项 |
|
||||
| field | `Object` | - | 否 | 字段对应内容,格式参考下方(1.5.0 后移除,请用单独的字段匹配) |
|
||||
| labelField | `String` | `label` | 否 | 指定节点对象中某个属性为标签字段,默认`label` |
|
||||
| valueField | `String` | `value` | 否 | 指定节点对象中某个属性为值字段,默认`value` |
|
||||
| childrenField | `String` | `children` | 否 | 指定节点对象中某个属性为子树节点字段,默认`children` |
|
||||
| disabledField | `String` | `disabled` | 否 | 指定节点对象中某个属性为禁用字段,默认`disabled` |
|
||||
| appendField | `String` | `append` | 否 | 指定节点对象中某个属性为副标签字段,默认`append` |
|
||||
| leafField | `String` | `leaf` | 否 | 指定节点对象中某个属性为末级节点字段,默认`leaf` |
|
||||
| sortField | `String` | `sort` | 否 | 指定节点对象中某个属性为排序字段,默认`sort` |
|
||||
|
||||
**field 格式(1.5.0 后移除,请用单独的字段匹配)**
|
||||
|
||||
```js
|
||||
{
|
||||
label: 'label',
|
||||
key: 'key',
|
||||
children: 'children',
|
||||
disabled: 'disabled',
|
||||
append: 'append'
|
||||
}
|
||||
```
|
||||
|
||||
### 组件事件
|
||||
|
||||
| 事件名称 | 回调参数 | 说明 |
|
||||
| :------- | :-------------------------------------- | :-------------- |
|
||||
| change | `(allCheckedKeys, currentItem) => void` | 选中时回调 |
|
||||
| expand | `(expandState, currentItem) => void` | 展开/收起时回调 |
|
||||
|
||||
### 组件方法
|
||||
|
||||
| 方法名称 | 参数 | 说明 |
|
||||
| :------------------ | :--------------- | :------------------------------------------------------------------------------------------------ |
|
||||
| setCheckedKeys | `(keys,checked)` | 设置指定 key 的节点选中/取消选中的状态。注: keys 单选时为 key,多选时为 key 的数组 |
|
||||
| setExpandedKeys | `(keys,expand)` | 设置指定 key 的节点展开/收起的状态,当 keys 为 all 时即代表展开/收起全部。注:keys 为数组或 `all` |
|
||||
| getCheckedKeys | - | 返回已选的 key |
|
||||
| getHalfCheckedKeys | - | 返回半选的 key |
|
||||
| getUncheckedKeys | - | 返回未选的 key |
|
||||
| getCheckedNodes | - | 返回已选的节点 |
|
||||
| getUncheckedNodes | - | 返回未选的节点 |
|
||||
| getHalfCheckedNodes | - | 返回半选的节点 |
|
||||
| getExpandedKeys | - | 返回已展开的 key |
|
||||
| getUnexpandedKeys | - | 返回未展开的 key |
|
||||
| getExpandedNodes | - | 返回已展开的节点 |
|
||||
| getUnexpandedNodes | - | 返回未展开的节点 |
|
||||
|
||||
### 组件版本
|
||||
|
||||
v1.4.1
|
||||
|
||||
### 差异化
|
||||
|
||||
已通过测试
|
||||
|
||||
> - H5 页面
|
||||
> - 微信小程序
|
||||
> - 支付宝、钉钉小程序
|
||||
> - 字节跳动、抖音、今日头条小程序
|
||||
> - 百度小程序
|
||||
> - 飞书小程序
|
||||
> - QQ 小程序
|
||||
> - 京东小程序
|
||||
> - 快应用
|
||||
> - 360 小程序
|
||||
|
||||
未测试
|
||||
|
||||
> - 快手小程序由于非企业用户暂无演示
|
||||
|
||||
### 开发组
|
||||
|
||||
[@CRLANG](https://crlang.com)
|
||||
151
addon/cashier/source/os/components/da-tree-vue2/utils.js
Executable file
151
addon/cashier/source/os/components/da-tree-vue2/utils.js
Executable file
@@ -0,0 +1,151 @@
|
||||
// @ts-nocheck
|
||||
/** 未选 */
|
||||
export const unCheckedStatus = 0
|
||||
/** 半选 */
|
||||
export const halfCheckedStatus = 1
|
||||
/** 选中 */
|
||||
export const isCheckedStatus = 2
|
||||
|
||||
/**
|
||||
* 深拷贝内容
|
||||
* @param originData 拷贝对象
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function deepClone(originData) {
|
||||
const type = Object.prototype.toString.call(originData)
|
||||
let data
|
||||
if (type === '[object Array]') {
|
||||
data = []
|
||||
for (let i = 0; i < originData.length; i++) {
|
||||
data.push(deepClone(originData[i]))
|
||||
}
|
||||
} else if (type === '[object Object]') {
|
||||
data = {}
|
||||
for (const prop in originData) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (originData.hasOwnProperty(prop)) { // 非继承属性
|
||||
data[prop] = deepClone(originData[prop])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = originData
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的节点
|
||||
* @param type
|
||||
* @param value
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodes(list, type, value, packDisabledkey = true) {
|
||||
if (!list || list.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const res = []
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i]
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有指定的key值
|
||||
* @param type
|
||||
* @param value
|
||||
* @author crlang(https://crlang.com)
|
||||
*/
|
||||
export function getAllNodeKeys(list, type, value, packDisabledkey = true) {
|
||||
if (!list || list.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const res = []
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i]
|
||||
if (item[type] === value) {
|
||||
if ((packDisabledkey && item.disabled) || !item.disabled) {
|
||||
res.push(item.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.length ? res : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误输出
|
||||
*
|
||||
* @param msg
|
||||
*/
|
||||
export function logError(msg, ...args) {
|
||||
console.error(`DaTree: ${msg}`, ...args)
|
||||
}
|
||||
|
||||
const toString = Object.prototype.toString
|
||||
|
||||
export function is(val, type) {
|
||||
return toString.call(val) === `[object ${type}]`
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否对象(Object)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isObject(val) {
|
||||
return val !== null && is(val, 'Object')
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数字(Number)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isNumber(val) {
|
||||
return is(val, 'Number')
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否字符串(String)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isString(val) {
|
||||
return is(val, 'String')
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否函数方法(Function)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isFunction(val) {
|
||||
return typeof val === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否布尔(Boolean)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isBoolean(val) {
|
||||
return is(val, 'Boolean')
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数组(Array)
|
||||
* @param val
|
||||
|
||||
*/
|
||||
export function isArray(val) {
|
||||
return val && Array.isArray(val)
|
||||
}
|
||||
159
addon/cashier/source/os/components/ns-card/index.js
Executable file
159
addon/cashier/source/os/components/ns-card/index.js
Executable file
@@ -0,0 +1,159 @@
|
||||
import {getCardList} from '@/api/card.js';
|
||||
import {mapGetters} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'nsCard',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'oncecard'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsType: '',
|
||||
pageSize: 35,
|
||||
onceCardData: {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
},
|
||||
timeCardData: {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
},
|
||||
commonCardData: {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
},
|
||||
itemNum: 3,
|
||||
mediaQueryOb: null,
|
||||
selectCardSkuId: [],
|
||||
isLoad: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.goodsType = this.type;
|
||||
this.init();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['buyCardGoodsData'])
|
||||
},
|
||||
watch: {
|
||||
buyCardGoodsData: {
|
||||
// 每个属性值发生变化就会调用这个函数
|
||||
handler(newVal, oldVal) {
|
||||
this.selectCardSkuId = [];
|
||||
if(!Object.values(this.buyCardGoodsData).length) return false;
|
||||
Object.values(this.buyCardGoodsData).forEach((item,index)=>{
|
||||
this.selectCardSkuId.push(item.sku_id);
|
||||
});
|
||||
},
|
||||
// 深度监听 属性的变化
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.mediaQueryOb = uni.createMediaQueryObserver(this);
|
||||
|
||||
this.mediaQueryOb.observe({maxWidth: 1500}, matches => {
|
||||
if (matches) this.itemNum = 2;
|
||||
});
|
||||
|
||||
this.mediaQueryOb.observe({minWidth: 1501, maxWidth: 1700}, matches => {
|
||||
if (matches) this.itemNum = 3;
|
||||
});
|
||||
|
||||
this.mediaQueryOb.observe({minWidth: 1701}, matches => {
|
||||
if (matches) this.itemNum = 4;
|
||||
});
|
||||
},
|
||||
destroyed() {
|
||||
this.mediaQueryOb.disconnect();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.isLoad = false;
|
||||
this.onceCardData.page = 0;
|
||||
this.timeCardData.page = 0;
|
||||
this.commonCardData.page = 0;
|
||||
this.getOnceCard();
|
||||
this.getTimeCard();
|
||||
this.getCommonCard();
|
||||
},
|
||||
switchGoodsType(type) {
|
||||
this.goodsType = type;
|
||||
},
|
||||
//卡项相关
|
||||
goodsSelect(data) {
|
||||
if (data.stock <= 0) return;
|
||||
|
||||
let _buyCardGoodsData = this.$util.deepClone(this.buyCardGoodsData);
|
||||
|
||||
if (_buyCardGoodsData['sku_' + data.sku_id]) {
|
||||
_buyCardGoodsData['sku_' + data.sku_id].num += 1;
|
||||
} else {
|
||||
_buyCardGoodsData['sku_' + data.sku_id] = data;
|
||||
_buyCardGoodsData['sku_' + data.sku_id].num = 1;
|
||||
}
|
||||
this.$store.commit('buycard/setGoodsData', _buyCardGoodsData);
|
||||
this.$store.commit('buycard/setActive', 'SelectGoodsAfter');
|
||||
},
|
||||
getOnceCard() {
|
||||
this.isLoad = false;
|
||||
if (this.onceCardData.page + 1 > this.onceCardData.total) return;
|
||||
this.onceCardData.page += 1;
|
||||
getCardList({
|
||||
page: this.onceCardData.page,
|
||||
page_size: this.pageSize,
|
||||
card_type: 'oncecard',
|
||||
goods_state: 1,
|
||||
status: 1,
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.isLoad = true;
|
||||
this.onceCardData.total = res.data.page_count || 1;
|
||||
if (this.onceCardData.page == 1) this.onceCardData.list = [];
|
||||
if (res.data.list.length) this.onceCardData.list = this.onceCardData.list.concat(res.data.list);
|
||||
}
|
||||
});
|
||||
},
|
||||
getTimeCard() {
|
||||
if (this.timeCardData.page + 1 > this.timeCardData.total) return;
|
||||
this.timeCardData.page += 1;
|
||||
getCardList({
|
||||
page: this.timeCardData.page,
|
||||
card_type: 'timecard',
|
||||
goods_state: 1,
|
||||
page_size: this.pageSize,
|
||||
status: 1,
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.timeCardData.total = res.data.page_count || 1;
|
||||
if (this.timeCardData.page == 1) this.timeCardData.list = [];
|
||||
if (res.data.list.length) this.timeCardData.list = this.timeCardData.list.concat(
|
||||
res.data.list);
|
||||
}
|
||||
});
|
||||
},
|
||||
getCommonCard() {
|
||||
if (this.commonCardData.page + 1 > this.commonCardData.total) return;
|
||||
this.commonCardData.page += 1;
|
||||
getCardList({
|
||||
page: this.commonCardData.page,
|
||||
card_type: 'commoncard',
|
||||
goods_state: 1,
|
||||
page_size: this.pageSize,
|
||||
status: 1,
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.commonCardData.total = res.data.page_count || 1;
|
||||
if (this.commonCardData.page == 1) this.commonCardData.list = [];
|
||||
if (res.data.list.length) this.commonCardData.list = this.commonCardData.list.concat(res.data.list);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
};
|
||||
228
addon/cashier/source/os/components/ns-card/index.scss
Executable file
228
addon/cashier/source/os/components/ns-card/index.scss
Executable file
@@ -0,0 +1,228 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header-action {
|
||||
padding: 0.22rem 0.24rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #fff;
|
||||
border-radius: 0.04rem;
|
||||
|
||||
.header-action-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 0.44rem;
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-radius: 0.22rem;
|
||||
|
||||
view {
|
||||
min-width: 1.02rem;
|
||||
height: 0.44rem;
|
||||
line-height: 0.44rem;
|
||||
text-align: center;
|
||||
font-size: 0.14rem;
|
||||
border-left-width: 0;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
border-radius: 0.22rem;
|
||||
color: $primary-color;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-left-width: 0.01rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-top: .2rem;
|
||||
box-sizing: border-box;
|
||||
height: calc(100% - 1.08rem);
|
||||
transform: rotate(0);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.list-wrap {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.table-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.table-item {
|
||||
border: 0.01rem solid #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0.18rem 0.1rem 0.1rem;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.12rem;
|
||||
margin-right: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: border-color, background-color 0.3s;
|
||||
position: relative;
|
||||
border-radius: 0.04rem;
|
||||
&.item-mum-2{
|
||||
width: calc((100% - 0.25rem) / 2);
|
||||
}
|
||||
&.item-mum-3{
|
||||
width: calc((100% - 0.37rem) / 3);
|
||||
}
|
||||
&.item-mum-4{
|
||||
width: calc((100% - 0.49rem) / 4);
|
||||
}
|
||||
.item-other {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: 0.1rem;
|
||||
}
|
||||
|
||||
.item-img {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
-ms-flex-negative: 0;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
border-radius: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
height: 0.4rem;
|
||||
line-height: 0.2rem;
|
||||
max-width: 1.58rem;
|
||||
margin-bottom: 0.05rem;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.no-stock {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
cursor: not-allowed;
|
||||
image{
|
||||
height: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-info {
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
.item-time {
|
||||
font-size: 0.12rem;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.item-money {
|
||||
font-size: 0.14rem;
|
||||
color: $primary-color;
|
||||
height: 0.19rem;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
.item-stock {
|
||||
height: 0.17rem;
|
||||
font-size: 0.12rem;
|
||||
color: #808695;
|
||||
line-height: 0.17rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.table-item.yes-stock {
|
||||
&:hover {
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
&.focus,
|
||||
&:focus {
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-color: $primary-color;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $primary-color;
|
||||
background-color: $primary-color;
|
||||
color: #fff;
|
||||
|
||||
.item-time,
|
||||
.item-money,
|
||||
.item-stock {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding-top: 1.2rem;
|
||||
|
||||
image {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-scroll-view {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
background-color: rgba($color: #000000, $alpha: 0);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 0.06rem;
|
||||
box-shadow: inset 0 0 0.06rem rgba(45, 43, 43, 0.45);
|
||||
background-color: #ddd;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
111
addon/cashier/source/os/components/ns-card/ns-card.vue
Executable file
111
addon/cashier/source/os/components/ns-card/ns-card.vue
Executable file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header-action common-wrap">
|
||||
<view class="header-action-left">
|
||||
<view :class="{ active: goodsType == 'oncecard' }" @click="switchGoodsType('oncecard')">限次卡</view>
|
||||
<view :class="{ active: goodsType == 'timecard' }" @click="switchGoodsType('timecard')">限时卡</view>
|
||||
<view :class="{ active: goodsType == 'commoncard' }" @click="switchGoodsType('commoncard')">通用卡</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<scroll-view scroll-y="true" class="list-wrap" @scrolltolower="getOncecard()" v-show="goodsType == 'oncecard'">
|
||||
<view class="table-list" v-show="onceCardData.list.length > 0">
|
||||
<view class="table-item" :class="{'yes-stock': item.stock>0, 'item-mum-2': itemNum == 2, 'item-mum-3': itemNum == 3, 'item-mum-4': itemNum == 4, 'active': selectCardSkuId.indexOf(item.sku_id) > -1 }" v-for="(item, index) in onceCardData.list" :key="index" @click="goodsSelect(item)">
|
||||
<view class="item-info">
|
||||
<view class="item-img">
|
||||
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" @error="item.goods_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="item-other flex-1">
|
||||
<view class="item-name">{{ item.goods_name }}</view>
|
||||
<view class="w-full self-end">
|
||||
<view class="item-money">
|
||||
<text class="util">¥</text>
|
||||
{{ item.discount_price | moneyFormat }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="no-stock" v-if="item.stock <= 0">
|
||||
<image src="@/static/stock/stock_empty.png" mode="heightFix"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-if="isLoad && !onceCardData.list.length">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无卡项</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<scroll-view scroll-y="true" class="list-wrap" @scrolltolower="getTimecard()" v-show="goodsType == 'timecard'">
|
||||
<view class="table-list" v-show="timeCardData.list.length > 0">
|
||||
<view class="table-item" :class="{'yes-stock': item.stock>0, 'item-mum-2': itemNum == 2, 'item-mum-3': itemNum == 3, 'item-mum-4': itemNum == 4,}" v-for="(item, index) in timeCardData.list" :key="index" @click="goodsSelect(item)">
|
||||
<view class="item-info">
|
||||
<view class="item-img">
|
||||
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" @error="item.goods_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="item-other flex-1">
|
||||
<view class="item-name">{{ item.goods_name }}</view>
|
||||
<view class="w-full self-end">
|
||||
<view class="item-money">
|
||||
<text class="util">¥</text>
|
||||
{{ item.discount_price | moneyFormat }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="no-stock" v-if="item.stock <= 0">
|
||||
<image src="@/static/stock/stock_empty.png" mode="heightFix"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-if="!timeCardData.list.length">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无卡项</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<scroll-view scroll-y="true" class="list-wrap" @scrolltolower="getCommoncard()" v-show="goodsType == 'commoncard'">
|
||||
<view class="table-list" v-show="commonCardData.list.length > 0">
|
||||
<view class="table-item" :class="{'yes-stock': item.stock>0, 'item-mum-2': itemNum == 2, 'item-mum-3': itemNum == 3, 'item-mum-4': itemNum == 4,}" v-for="(item, index) in commonCardData.list" :key="index" @click="goodsSelect(item)">
|
||||
<view class="item-info">
|
||||
<view class="item-img">
|
||||
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" @error="item.goods_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="item-other flex-1">
|
||||
<view class="item-name">{{ item.goods_name }}</view>
|
||||
<view class="w-full self-end">
|
||||
<view class="item-money">
|
||||
<text class="util">¥</text>
|
||||
{{ item.discount_price | moneyFormat }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="no-stock" v-if="item.stock <= 0">
|
||||
<image src="@/static/stock/stock_empty.png" mode="heightFix"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-if="!commonCardData.list.length">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无卡项</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from './index.js';
|
||||
export default {
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
520
addon/cashier/source/os/components/ns-goods-sku-select/ns-goods-sku-select.vue
Executable file
520
addon/cashier/source/os/components/ns-goods-sku-select/ns-goods-sku-select.vue
Executable file
@@ -0,0 +1,520 @@
|
||||
<template>
|
||||
<unipopup ref="dialogRef" type="center" :maskClick="false">
|
||||
<view class="stock-dialog-wrap">
|
||||
<view class="stock-dialog-head">
|
||||
<text>商品选择</text>
|
||||
<text class="iconfont iconguanbi1" @click="$emit('change', false)"></text>
|
||||
</view>
|
||||
<view class="stock-dialog-body">
|
||||
<view class="tree">
|
||||
<scroll-view scroll-y="true" class="list-wrap">
|
||||
<view class="item" :class="{ 'active': option.category_id === '' }" @click="itemClick({ category_id: '', child_num: 0 })">
|
||||
<view class="icon"></view>
|
||||
<view>全部分类</view>
|
||||
</view>
|
||||
<view v-for="(item, key) in goodsCategoryList" :key="key">
|
||||
<view class="item" :class="{ 'active': option.category_id === item.category_id }" @click="itemClick(item)">
|
||||
<view class="icon" :class="{ 'active': activeList.indexOf(item.category_id) != -1 }">
|
||||
<text v-if="item.child_num" class="iconfont iconsanjiao_xia"></text>
|
||||
</view>
|
||||
<view>{{ item.title }}</view>
|
||||
</view>
|
||||
<template v-if="item.child_num">
|
||||
<view v-show="activeList.indexOf(item.category_id) != -1" v-for="(item2, key2) in item.children" :key="key2" class="level">
|
||||
<view class="item" :class="{ 'active': option.category_id === item2.category_id }" @click="itemClick(item2)">
|
||||
<view class="icon" :class="{ 'active': activeList.indexOf(item2.category_id) != -1 }">
|
||||
<text v-if="item2.child_num" class="iconfont iconsanjiao_xia"></text>
|
||||
</view>
|
||||
<view>{{ item2.title }}</view>
|
||||
</view>
|
||||
<template>
|
||||
<view v-show="activeList.indexOf(item2.category_id) != -1" v-for="(item3, key3) in item2.children" :key="key3" class="level">
|
||||
<view class="item item2" @click="itemClick(item3)">
|
||||
<view class="icon"></view>
|
||||
<view>{{ item3.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="stock-dialog-table">
|
||||
<view class="search common-form">
|
||||
<view class="common-form-item">
|
||||
<view class="form-input-inline" v-if="isInstallSupply == 1">
|
||||
<select-lay :zindex="10" :value="option.supplier_id" name="supplier_id" placeholder="请选择供应商" :options="supplierList" @selectitem="selectSupplier"/>
|
||||
</view>
|
||||
<view class="form-input-inline">
|
||||
<select-lay :zindex="10" :value="option.brand_id" name="brand_id" placeholder="请选择品牌" :options="brandList" @selectitem="selectBrand"/>
|
||||
</view>
|
||||
<view class="form-input-inline">
|
||||
<select-lay :zindex="10" :value="option.goods_class" name="goods_class" placeholder="请选择类型" :options="goodsClassList" @selectitem="selectGoodsClass"/>
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<view class="form-input-inline">
|
||||
<input type="text" v-model="option.search_text" @confirm="getStoreGoods" placeholder="请输入名称/编码" class="form-input" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-inline common-btn-wrap">
|
||||
<button type="default" class="screen-btn" @click="getStoreGoods">筛选</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uniDataTable class="goods-table" pk="sku_id" :url="url" :option="option" :cols="cols" :pagesize="8" ref="goodsListTable"></uniDataTable>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btn">
|
||||
<button type="primary" class="primary-btn submit" @click="submit('close')">选中</button>
|
||||
<button type="primary" class="default-btn" @click="$emit('change', false)">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</unipopup>
|
||||
</template>
|
||||
<script>
|
||||
import unipopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import uniDataTable from '@/components/uni-data-table/uni-data-table-new.vue';
|
||||
import {getManageGoodsCategory,getGoodsSceen,getSkuListBySelect} from '@/api/goods.js';
|
||||
|
||||
export default {
|
||||
name: 'stockDialog',
|
||||
components: {
|
||||
unipopup,
|
||||
uniDataTable
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: ()=>{
|
||||
return {}
|
||||
}
|
||||
},
|
||||
goodsClass:{
|
||||
type: Array,
|
||||
default: ()=>{
|
||||
return [1,4,5,6];
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsCategoryList: {},
|
||||
activeList: [],//下拉激活
|
||||
option: {
|
||||
category_id: '',
|
||||
search_text: '',
|
||||
is_weigh: 0,
|
||||
page_size: 8,
|
||||
goods_class_all:'',
|
||||
goods_class:'',
|
||||
supplier_id:'',
|
||||
brand_id:'',
|
||||
},
|
||||
checkList: {},
|
||||
cols: [],
|
||||
url: '',
|
||||
goodsClassList: [],
|
||||
isInstallSupply:0,
|
||||
supplierList:[],
|
||||
brandList:[],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler: function (val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.option = Object.assign(this.option, this.params);
|
||||
if (this.params.temp_store_id && this.params.temp_store_id == '') {
|
||||
delete this.option.temp_store_id
|
||||
}
|
||||
this.$refs.dialogRef.open()
|
||||
})
|
||||
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.option = Object(this.option, {
|
||||
category_id: '',
|
||||
search_text: '',
|
||||
is_weigh: 0,
|
||||
page: 1,
|
||||
page_size: 8,
|
||||
});
|
||||
this.checkList = {};
|
||||
this.$refs.dialogRef.close()
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.skuConfig();
|
||||
this.getGoodsCategory();
|
||||
this.getScreen();
|
||||
this.getGoodsClassList();
|
||||
},
|
||||
methods: {
|
||||
skuConfig(){
|
||||
this.cols = [{
|
||||
width: 20,
|
||||
align: 'center',
|
||||
checkbox: true,
|
||||
}, {
|
||||
field: 'account_data',
|
||||
width: 50,
|
||||
title: '商品信息',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
let img = this.$util.img(data.sku_image);
|
||||
let html = `
|
||||
<view class="goods-content">
|
||||
<image class="goods-img" src="${img}" mode="aspectFit"/>
|
||||
<text class="goods-name multi-hidden" title="${data.sku_name}">${data.sku_name}</text>
|
||||
</view>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
field: 'stock',
|
||||
width: 22,
|
||||
title: '库存',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
return (data.stock || 0);
|
||||
}
|
||||
}, {
|
||||
width: 22,
|
||||
title: '单位',
|
||||
templet: data => {
|
||||
return (data.unit || '件');
|
||||
}
|
||||
}];
|
||||
this.url = '/cashier/storeapi/goods/getSkuListBySelect';
|
||||
},
|
||||
selectGoodsClass(index) {
|
||||
this.option.goods_class = index == -1 ? '' : this.goodsClassList[index].value.toString();
|
||||
this.getStoreGoods();
|
||||
},
|
||||
selectBrand(index){
|
||||
this.option.brand_id = index == -1 ? '' : this.brandList[index].value.toString();
|
||||
this.getStoreGoods();
|
||||
},
|
||||
selectSupplier(index){
|
||||
this.option.supplier_id = index == -1 ? '' : this.supplierList[index].value.toString();
|
||||
this.getStoreGoods();
|
||||
},
|
||||
getGoodsCategory() {
|
||||
getManageGoodsCategory().then(res=>{
|
||||
uni.hideLoading();
|
||||
if (res.data && Object.keys(res.data)) {
|
||||
this.goodsCategoryList = res.data
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
getScreen(){
|
||||
getGoodsSceen().then(res=>{
|
||||
this.isInstallSupply = res.data.is_install_supply;
|
||||
(res.data.supplier_list || []).forEach((item) => {
|
||||
this.supplierList.push({
|
||||
value : item.supplier_id,
|
||||
label : item.title,
|
||||
})
|
||||
})
|
||||
res.data.brand_list.forEach((item) => {
|
||||
this.brandList.push({
|
||||
value : item.brand_id,
|
||||
label : item.brand_name,
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
getGoodsClassList(){
|
||||
let goodsClassList = [
|
||||
{
|
||||
value: this.$util.goodsClassDict.real,
|
||||
label: '实物商品'
|
||||
}, {
|
||||
value: this.$util.goodsClassDict.service,
|
||||
label: '服务项目'
|
||||
}, {
|
||||
value: this.$util.goodsClassDict.card,
|
||||
label: '卡项套餐'
|
||||
}, {
|
||||
value: this.$util.goodsClassDict.weigh,
|
||||
label: '称重商品'
|
||||
}
|
||||
];
|
||||
let goods_class_all = [];
|
||||
goodsClassList.forEach((item)=>{
|
||||
if(this.goodsClass.indexOf(item.value) > -1){
|
||||
this.goodsClassList.push(item);
|
||||
goods_class_all.push(item.value);
|
||||
}
|
||||
})
|
||||
this.option.goods_class_all = goods_class_all.toString();
|
||||
},
|
||||
itemClick(item) {//tree点击
|
||||
this.option.category_id = item.category_id;
|
||||
var index = this.activeList.indexOf(item.category_id);
|
||||
if (item.child_num && index === -1) {
|
||||
this.activeList.push(item.category_id);
|
||||
} else if (item.child_num && index != -1) {
|
||||
this.activeList.splice(index, 1);
|
||||
}
|
||||
this.$forceUpdate();
|
||||
this.getStoreGoods();
|
||||
},
|
||||
getStoreGoods() {//表格查询
|
||||
this.$refs.goodsListTable.load({
|
||||
page: 1
|
||||
});
|
||||
},
|
||||
submit(action) {
|
||||
let res = this.$refs.goodsListTable.getSelectData();
|
||||
if(res.selectedNum == 0){
|
||||
this.$util.showToast({
|
||||
title: '请选择商品'
|
||||
});
|
||||
return false
|
||||
}
|
||||
|
||||
if(res.allSelected){
|
||||
let option = this.$util.deepClone(this.option);
|
||||
option.unselected_sku_ids = Object.keys(res.unselectedData).toString();
|
||||
option.page_size = 0;
|
||||
uni.showLoading({
|
||||
title: '数据获取中'
|
||||
});
|
||||
getSkuListBySelect(option).then(res=>{
|
||||
uni.hideLoading();
|
||||
this.$emit('selectGoods', res.data.list);
|
||||
this.$refs.goodsListTable.clearCheck();
|
||||
if(action == 'close'){
|
||||
this.$emit('change', false);
|
||||
}
|
||||
})
|
||||
}else{
|
||||
this.$emit('selectGoods', Object.values(res.selectedData));
|
||||
this.$refs.goodsListTable.clearCheck();
|
||||
if(action == 'close'){
|
||||
this.$emit('change', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.stock-dialog-wrap {
|
||||
background-color: #fff;
|
||||
border-radius: 0.05rem;
|
||||
width: 100%;
|
||||
height: 75vh;
|
||||
|
||||
|
||||
.stock-dialog-head {
|
||||
padding: 0 0.15rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 0.15rem;
|
||||
height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconguanbi1 {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-dialog-body {
|
||||
width: 100%;
|
||||
// height: 7.3rem;
|
||||
height: calc(100% - 0.45rem - 0.58rem);
|
||||
padding: 0.1rem 0.2rem 0 0.2rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
.tree {
|
||||
width: 1.8rem;
|
||||
// height: 7.1rem;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
border-right: 0.01rem solid #e8eaec;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
flex-grow: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.list-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
>view {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
view.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
line-height: 0.3rem;
|
||||
min-height: 0.3rem;
|
||||
font-weight: 500;
|
||||
|
||||
&.active {
|
||||
|
||||
.icon,
|
||||
view {
|
||||
color: $primary-color !important;
|
||||
}
|
||||
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 0.2rem;
|
||||
height: 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: rotate(-90deg);
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.active {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.level {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.item {
|
||||
padding-left: 0.2rem;
|
||||
}
|
||||
|
||||
.item2 {
|
||||
padding-left: 0.4rem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.stock-dialog-table {
|
||||
width: 6.6rem;
|
||||
margin-left: 0.2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
.search {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.goods-table /deep/{
|
||||
flex: 1;
|
||||
height: 0;
|
||||
.tbody{
|
||||
height: calc( 100% - 0.5rem - 0.5rem );
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
&::-webkit-scrollbar-button{
|
||||
display: none;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb{
|
||||
border-radius: 0.06rem;
|
||||
box-shadow: inset 0 0 0.06rem rgba(45, 43, 43, 0.45);
|
||||
background-color: #ddd;
|
||||
}
|
||||
&::-webkit-scrollbar-track{
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-top: 0.01rem solid #e8eaec;
|
||||
padding: 0.1rem 0.2rem 0.1rem 0.2rem;
|
||||
box-sizing: border-box;
|
||||
height: 0.58rem;
|
||||
|
||||
.default-btn,
|
||||
.primary-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.default-btn {
|
||||
border: 0.01rem solid #e8eaec !important;
|
||||
}
|
||||
.submit{
|
||||
margin-right: 0.15rem;
|
||||
}
|
||||
.default-btn::after {
|
||||
display: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.common-form{
|
||||
.common-btn-wrap {
|
||||
margin-left: 0;
|
||||
.screen-btn {
|
||||
margin-right: 0;
|
||||
padding-left:14px;
|
||||
padding-right:14px;
|
||||
}
|
||||
}
|
||||
.common-form-item {
|
||||
margin-bottom: 0.1rem;
|
||||
.form-input-inline {
|
||||
width: 1.3rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .goods-content {
|
||||
display: flex;
|
||||
|
||||
.goods-img {
|
||||
margin-right: 0.1rem;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<view class="ns-record">
|
||||
<view class="title">
|
||||
库存记录
|
||||
<text class="iconfont iconguanbi1" @click="close"></text>
|
||||
</view>
|
||||
<view class="table">
|
||||
<view class="table-th">
|
||||
<view class="table-td" style="width: 15%;">规格名称</view>
|
||||
<view class="table-td" style="width: 12%;">业务类型</view>
|
||||
<view class="table-td" style="width: 14%;">原始数量</view>
|
||||
<view class="table-td" style="width: 14%;">变动数量</view>
|
||||
<view class="table-td" style="width: 14%;">剩余数量</view>
|
||||
<view class="table-td" style="width: 14%;">入库单价</view>
|
||||
<view class="table-td" style="width: 17%;">创建时间</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="table-tb">
|
||||
<view class="table-tr" v-for="(item, index) in list" :key="index">
|
||||
<view class="table-td" style="width: 15%;">{{ item.spec_name ? item.spec_name : item.goods_name }}</view>
|
||||
<view class="table-td" style="width: 12%;">{{ item.name }}</view>
|
||||
<view class="table-td" style="width: 14%;">{{ item.before_store_stock }}</view>
|
||||
<view class="table-td" style="width: 14%;">{{ item.goods_num }}</view>
|
||||
<view class="table-td" style="width: 14%;">{{ item.after_store_stock }}</view>
|
||||
<view class="table-td" style="width: 14%;">{{ item.goods_price }}</view>
|
||||
<view class="table-td" style="width: 17%;">{{ $util.timeFormat(item.create_time) }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 分页 -->
|
||||
<view class="pagination">
|
||||
<uni-pagination @change="changePage" :pageSize="page_size" show-icon="true" :total="total" :current="page"/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getStockGoodsRecords} from '@/api/stock.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
page: 1,
|
||||
page_size: 8,
|
||||
list: [],
|
||||
total: 0
|
||||
};
|
||||
},
|
||||
props: {
|
||||
goodsId: {
|
||||
type: Number,
|
||||
default: () => {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getData();
|
||||
},
|
||||
methods: {
|
||||
// 分页发生变化
|
||||
changePage(e) {
|
||||
this.page = e.current;
|
||||
this.getData();
|
||||
},
|
||||
// 获取数据
|
||||
getData() {
|
||||
getStockGoodsRecords({
|
||||
page: this.page,
|
||||
page_size: this.page_size,
|
||||
goods_id: this.goodsId,
|
||||
}).then(res => {
|
||||
if (res.code >= 0) {
|
||||
this.total = res.data.count;
|
||||
this.list = res.data.list.map((item, index) => {
|
||||
let unit = '';
|
||||
if (item.type == 'input') {
|
||||
unit = '+';
|
||||
} else {
|
||||
unit = '-';
|
||||
}
|
||||
item.goods_num = unit + item.goods_num;
|
||||
return item;
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
// 弹窗关闭
|
||||
close() {
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ns-record {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 0.04rem;
|
||||
min-height: 2rem;
|
||||
padding-bottom: 0.4rem;
|
||||
.title {
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
font-size: 0.16rem;
|
||||
line-height: 0.5rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
.iconguanbi1 {
|
||||
font-size: 0.2rem;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0.15rem;
|
||||
transform: translateY(-50%);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
.table {
|
||||
width: 100%;
|
||||
height: 4rem;
|
||||
padding: 0 0.15rem;
|
||||
box-sizing: border-box;
|
||||
.table-th {
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f7f8fa;
|
||||
padding: 0 0.15rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.table-tb {
|
||||
width: 100%;
|
||||
height: calc(100% - 0.5rem);
|
||||
.table-tr {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
padding: 0 0.15rem;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-date-single {
|
||||
height: 0.3rem;
|
||||
}
|
||||
.table-td {
|
||||
height: 100%;
|
||||
line-height: 0.5rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
.pagination {
|
||||
width: 100%;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
</style>
|
||||
268
addon/cashier/source/os/components/ns-goods-sku/ns-goods-sku.vue
Executable file
268
addon/cashier/source/os/components/ns-goods-sku/ns-goods-sku.vue
Executable file
@@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<view class="ns-record">
|
||||
<view class="title">
|
||||
价格库存
|
||||
<text class="iconfont iconguanbi1" @click="close"></text>
|
||||
</view>
|
||||
<view class="table">
|
||||
<view class="table-th">
|
||||
<view class="table-td" style="min-width: 35%;max-width: 35%;">规格名称</view>
|
||||
<view class="table-td">统一售价</view>
|
||||
<view class="table-td" v-if="isUnifyPrice == 0">独立售价</view>
|
||||
<view class="table-td">库存</view>
|
||||
<view class="table-td" v-if="disabled">限制起送</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="table-tb">
|
||||
<view class="table-tr" v-for="(item, index) in skuList" :key="index">
|
||||
<view class="table-td" style="min-width: 35%;max-width: 35%;">
|
||||
{{ item.spec_name ? item.spec_name : item.goods_name }}</view>
|
||||
<view class="table-td">{{ item.discount_price }}</view>
|
||||
<view class="table-td input-wrap" v-if="isUnifyPrice == 0">
|
||||
<input class="input" v-model="item.store_price" type="digit" />
|
||||
<view class="unit">元</view>
|
||||
</view>
|
||||
<view class="table-td input-wrap" v-if="!disabled">
|
||||
<block v-if="globalStoreInfo.stock_type == 'store'">
|
||||
<input class="input" v-model="item.stock" type="digit" :disabled="disabled" />
|
||||
<view class="unit">{{ item.unit ? item.unit : '件' }}</view>
|
||||
</block>
|
||||
<view v-else>{{ item.stock }}</view>
|
||||
</view>
|
||||
<view class="table-td input-wrap" v-else>
|
||||
<view>{{ item.stock }}</view>
|
||||
</view>
|
||||
<view class="table-td input-wrap" v-if="disabled">
|
||||
<switch @change="changeswitch($event,index)" color="#FA6400" style="transform:scale(0.7)"
|
||||
:checked="item.is_delivery_restrictions == 1" />
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
<view class="pop-bottom"><button class="primary-btn" @click="save()">确定</button></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
editGoods,
|
||||
setGoodsLocalRestrictions
|
||||
} from '@/api/goods.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
goodsSkuList: [],
|
||||
flag: true
|
||||
};
|
||||
},
|
||||
props: {
|
||||
skuList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
isUnifyPrice: {
|
||||
type: Number,
|
||||
default: () => {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: () => {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
methods: {
|
||||
changeswitch(e, index) {
|
||||
this.skuList[index].is_delivery_restrictions = e.detail.value ? 1 : 0
|
||||
},
|
||||
getGoodsSku() {
|
||||
this.goodsSkuList = [];
|
||||
Object.keys(this.skuList).forEach(key => {
|
||||
let data = this.skuList[key];
|
||||
let obj = {}
|
||||
if (this.disabled) {
|
||||
obj.sku_id = data.sku_id
|
||||
obj.is_delivery_restrictions = data.is_delivery_restrictions
|
||||
} else {
|
||||
obj.sku_id = data.sku_id
|
||||
obj.price = data.store_price ? data.store_price : data.discount_price
|
||||
}
|
||||
if (this.globalStoreInfo.stock_type == 'store') {
|
||||
obj.stock = data.stock;
|
||||
}
|
||||
this.goodsSkuList.push(obj);
|
||||
});
|
||||
},
|
||||
save() {
|
||||
this.getGoodsSku();
|
||||
if (!this.flag) return false;
|
||||
this.flag = false;
|
||||
uni.showLoading({
|
||||
title: '请求处理中'
|
||||
});
|
||||
if (this.disabled) {
|
||||
setGoodsLocalRestrictions({
|
||||
goods_sku_list: JSON.stringify(this.goodsSkuList)
|
||||
}).then(res => {
|
||||
uni.hideLoading();
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.$root.$refs.goodsListTable.load();
|
||||
this.close();
|
||||
} else {
|
||||
this.flag = true;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
editGoods({
|
||||
goods_sku_list: JSON.stringify(this.goodsSkuList)
|
||||
}).then(res => {
|
||||
uni.hideLoading();
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.$root.$refs.goodsListTable.load();
|
||||
this.close();
|
||||
} else {
|
||||
this.flag = true;
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 弹窗关闭
|
||||
close() {
|
||||
this.$emit('close');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ns-record {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #ffffff;
|
||||
border-radius: 0.04rem;
|
||||
min-height: 2rem;
|
||||
|
||||
.title {
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
font-size: 0.16rem;
|
||||
line-height: 0.5rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
|
||||
.iconguanbi1 {
|
||||
font-size: 0.2rem;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0.15rem;
|
||||
transform: translateY(-50%);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
height: 4rem;
|
||||
padding: 0.15rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.table-th {
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #f7f8fa;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.table-td {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 0 0.15rem;
|
||||
}
|
||||
|
||||
.table-tb {
|
||||
width: 100%;
|
||||
height: calc(100% - 0.5rem);
|
||||
|
||||
.table-tr {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-date-single {
|
||||
height: 0.3rem;
|
||||
}
|
||||
|
||||
.input-wrap {
|
||||
height: 100%;
|
||||
line-height: 0.5rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 0.14rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.input {
|
||||
width: 0.7rem;
|
||||
height: 0.35rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
padding: 0 0.1rem;
|
||||
border-top-left-radius: 0.03rem;
|
||||
border-bottom-left-radius: 0.03rem;
|
||||
}
|
||||
|
||||
.unit {
|
||||
background-color: #eee;
|
||||
height: 0.35rem;
|
||||
width: 0.35rem;
|
||||
text-align: center;
|
||||
line-height: 0.35rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-left: 0;
|
||||
border-top-right-radius: 0.03rem;
|
||||
border-bottom-right-radius: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.save {
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
padding: 0.1rem 0.2rem;
|
||||
border-top: 0.01rem solid #eee;
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
line-height: 0.35rem;
|
||||
height: 0.35rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
828
addon/cashier/source/os/components/ns-goods/index.js
Executable file
828
addon/cashier/source/os/components/ns-goods/index.js
Executable file
@@ -0,0 +1,828 @@
|
||||
var self;
|
||||
|
||||
import {
|
||||
getGoodsList,
|
||||
getGoodsCategory,
|
||||
getServiceCategory,
|
||||
getServiceList,
|
||||
getGoodsSkuList,
|
||||
getElectronicScaleInformation,
|
||||
getGoodsInfoByCode
|
||||
} from '@/api/goods'
|
||||
import {mapGetters} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'nsGoods',
|
||||
props: {
|
||||
indexFocus: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'goods',
|
||||
serviceCategory: [],
|
||||
serviceCategoryId: 'all',
|
||||
serviceData: {
|
||||
size: 12,
|
||||
index: 1,
|
||||
total: 0,
|
||||
list: []
|
||||
},
|
||||
goodsCategoryId: 'all',
|
||||
goodsCategory: [],
|
||||
goodsData: {
|
||||
size: 30,
|
||||
index: 1,
|
||||
total: 0,
|
||||
list: []
|
||||
},
|
||||
skuInfo: null,
|
||||
allSku: null,
|
||||
searchText: '',
|
||||
itemNum: 3,
|
||||
mediaQueryOb: null,
|
||||
paymentMoney: '',
|
||||
cashierScale: null,
|
||||
actionIndex: 0,
|
||||
inputFocus: false,
|
||||
goodsCategoryShow: false,
|
||||
goodsCategoryIndex: 0,
|
||||
serviceCategoryShow: false,
|
||||
serviceCategoryIndex: 0,
|
||||
scanCode: {
|
||||
code: '',
|
||||
lastTime: 0
|
||||
},
|
||||
isGoodsLoad: false,
|
||||
goodsItems:{},//点击商品后如果是可转换库存商品存储商品数据
|
||||
scanCodeSearch:false,
|
||||
goodsNextPage: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
serviceCategoryId: function (nval) {
|
||||
this.serviceData.page = 0;
|
||||
this.serviceData.index = 1;
|
||||
this.$refs.loading.show();
|
||||
this.getService();
|
||||
},
|
||||
goodsCategoryId: function (nval) {
|
||||
this.goodsData.page = 0;
|
||||
this.goodsData.index = 1;
|
||||
this.$refs.goodsLoading.show();
|
||||
this.getGoods();
|
||||
},
|
||||
type: function () {
|
||||
this.searchText = '';
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
goodsSpec() {
|
||||
if (this.allSku && this.skuInfo) {
|
||||
let data = [];
|
||||
if (this.skuInfo.goods_class != 6 || (this.skuInfo.goods_class == 6 && this.skuInfo.goods_spec_format)) {
|
||||
data = this.allSku['sku_id_' + this.skuInfo.sku_id].goods_spec_format;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
return [];
|
||||
},
|
||||
...mapGetters(['billingGoodsIds', 'billingGoodsData', 'billingActive', 'billingIsScanTrigger','billingIsShowCashBox'])
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
this.addScanCodeEvent();
|
||||
this.addKeyDownEvent();
|
||||
},
|
||||
mounted() {
|
||||
this.mediaQueryOb = uni.createMediaQueryObserver(this);
|
||||
|
||||
this.mediaQueryOb.observe({maxWidth: 1500}, matches => {
|
||||
if (matches) this.itemNum = 2;
|
||||
});
|
||||
|
||||
this.mediaQueryOb.observe({minWidth: 1501, maxWidth: 1700}, matches => {
|
||||
if (matches) this.itemNum = 3;
|
||||
});
|
||||
|
||||
this.mediaQueryOb.observe({minWidth: 1701}, matches => {
|
||||
if (matches) this.itemNum = 4;
|
||||
});
|
||||
|
||||
document.addEventListener('click', this.isListShow)
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener("click", this.isListShow);
|
||||
},
|
||||
methods: {
|
||||
nextGoodsLiist(){
|
||||
if(!this.goodsNextPage) return;
|
||||
this.goodsData.index ++;
|
||||
this.getGoods();
|
||||
},
|
||||
init() {
|
||||
self = this;
|
||||
this.getServiceCategoryFn();
|
||||
this.getGoodsCategoryFn();
|
||||
this.getService();
|
||||
this.getGoods();
|
||||
},
|
||||
getServiceCategoryFn() {
|
||||
getServiceCategory().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.serviceCategory = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
getGoodsCategoryFn() {
|
||||
getGoodsCategory().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.goodsCategory = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
getService() {
|
||||
getServiceList({
|
||||
page: this.serviceData.index,
|
||||
page_size: this.serviceData.size,
|
||||
category: this.serviceCategoryId,
|
||||
search_text: this.searchText,
|
||||
status: 1
|
||||
}).then(res => {
|
||||
if (this.$refs.loading) this.$refs.loading.hide();
|
||||
if (res.code == 0) {
|
||||
this.serviceData.total = res.data.count;
|
||||
this.serviceData.list = res.data.list || [];
|
||||
this.searchText = '';
|
||||
}
|
||||
});
|
||||
},
|
||||
getGoods() {
|
||||
this.isGoodsLoad = false;
|
||||
getGoodsList({
|
||||
page: this.goodsData.index,
|
||||
page_size: this.goodsData.size,
|
||||
category: this.goodsCategoryId,
|
||||
search_text: this.searchText,
|
||||
goods_class: '1,6',
|
||||
status: 1,
|
||||
scene:'billing',
|
||||
}).then((res) => {
|
||||
if (this.$refs.goodsLoading) this.$refs.goodsLoading.hide();
|
||||
if (res.code == 0) {
|
||||
this.goodsData.total = res.data.count;
|
||||
// this.goodsData.list = res.data.list || [];
|
||||
res.data.list.forEach(item => {
|
||||
item.adjust = {}; // 存储规格调价
|
||||
});
|
||||
if (this.goodsData.index == 1) this.goodsData.list = []; //如果是第一页需手动制空列表
|
||||
this.goodsData.list.push(...res.data.list);
|
||||
if(res.data.list.length) this.goodsNextPage = true;
|
||||
else this.goodsNextPage = false;
|
||||
if(this.scanCodeSearch) this.searchText = '';
|
||||
this.scanCodeSearch = false;
|
||||
}
|
||||
this.isGoodsLoad = true;
|
||||
})
|
||||
},
|
||||
goodsSelect(data, index) {
|
||||
if (this.type == 'goods' && !data.stock) return;
|
||||
if (index != undefined) this.actionIndex = index;
|
||||
|
||||
if (data.goods_class != 6 && data.adjust && data.adjust['sku_id_' + data.sku_id]) {
|
||||
data.adjust_price = data.adjust['sku_id_' + data.sku_id].adjust_price;
|
||||
data.is_adjust = data.adjust['sku_id_' + data.sku_id].is_adjust;
|
||||
}
|
||||
|
||||
// 满足条件:多规格,称重商品计重模式,编辑数量
|
||||
if (data.goods_spec_format || (data.goods_class == 6 && data.pricing_type == 'weight') || (data.status && data.status == 'edit')) {
|
||||
this.setActive('SelectGoodsSku');
|
||||
getGoodsSkuList(data.goods_id).then(res => {
|
||||
if (res.code == 0) {
|
||||
let obj = {};
|
||||
res.data.forEach(item => {
|
||||
try{
|
||||
item.goods_spec_format = JSON.parse(item.goods_spec_format);
|
||||
}catch(e){
|
||||
item.goods_spec_format = [];
|
||||
}
|
||||
obj['sku_id_' + item.sku_id] = item;
|
||||
});
|
||||
this.allSku = obj;
|
||||
this.skuInfo = obj['sku_id_' + data.sku_id];
|
||||
// 调整价格,称重商品不参与永久调价,每次都是初始原价
|
||||
if (data.goods_class != 6 && data.adjust_price) {
|
||||
this.skuInfo.adjust_price = data.adjust_price; // 使用调价
|
||||
} else {
|
||||
this.skuInfo.adjust_price = data.price; // 未调价,使用原价
|
||||
}
|
||||
|
||||
this.skuInfo.adjust_price = parseFloat(this.skuInfo.adjust_price).toFixed(2);
|
||||
|
||||
this.$set(this.skuInfo, 'status', data.status || '');
|
||||
this.$set(this.skuInfo, 'editKey', data.editKey || '');
|
||||
|
||||
if (data.goods_class != 6) {
|
||||
this.skuInfo.num = data.num || 1; // 默认购买数量为1
|
||||
}
|
||||
|
||||
// 称重商品,计重模式
|
||||
if (data.goods_class == 6 && data.pricing_type == 'weight') {
|
||||
let num = data.num || '';
|
||||
|
||||
if (num) {
|
||||
this.$set(this.skuInfo, 'weigh', num);
|
||||
Object.values(this.allSku).forEach((item, index) => {
|
||||
this.$set(item, 'weigh', num);
|
||||
});
|
||||
}
|
||||
|
||||
// 打开收银秤
|
||||
this.openCashierScale()
|
||||
}
|
||||
|
||||
this.$refs.skuPopup.open();
|
||||
|
||||
setTimeout(() => {
|
||||
this.inputFocus = true;
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.handleSelectGoods(data);
|
||||
this.scanCode = {
|
||||
lastTime: 0,
|
||||
code: ''
|
||||
};
|
||||
this.$store.commit('billing/setActive', 'SelectGoodsAfter'); // 记录页面当前活跃值:选择完商品
|
||||
}
|
||||
},
|
||||
skuSelect(sku_id) {
|
||||
if (!this.skuInfo.status) {
|
||||
this.skuInfo = this.allSku['sku_id_' + sku_id];
|
||||
this.goodsItems.sku_id = sku_id
|
||||
let skuData = this.goodsData.list[this.actionIndex];
|
||||
|
||||
// 调整价格
|
||||
if (skuData.adjust && skuData.adjust['sku_id_' + sku_id]) {
|
||||
this.skuInfo.adjust_price = skuData.adjust['sku_id_' + sku_id].adjust_price;
|
||||
this.skuInfo.is_adjust = skuData.adjust['sku_id_' + sku_id].is_adjust;
|
||||
} else {
|
||||
// 使用原价
|
||||
this.skuInfo.adjust_price = this.skuInfo.price;
|
||||
}
|
||||
this.skuInfo.adjust_price = parseFloat(this.skuInfo.adjust_price).toFixed(2);
|
||||
|
||||
if (this.skuInfo.goods_class != 6) {
|
||||
this.skuInfo.num = this.skuInfo.num || 1; // 默认购买数量为1
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
skuConfirm() {
|
||||
if (!this.skuInfo) return;
|
||||
if (this.skuInfo.stock <= 0) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.skuInfo.price.length == 0 || this.skuInfo.adjust_price.length == 0) {
|
||||
this.$util.showToast({
|
||||
title: '请输入单价'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.skuInfo.price < 0 || this.skuInfo.adjust_price < 0) {
|
||||
this.$util.showToast({
|
||||
title: '单价不能小于0'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.skuInfo.goods_class != 6) {
|
||||
if (Number.parseInt(this.skuInfo.num) <= 0 || !/^\d{0,10}$/.test(Number.parseInt(this.skuInfo.num))) {
|
||||
this.$util.showToast({
|
||||
title: '请输入合法的数值,数值要大于零'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.skuInfo.stock < this.skuInfo.num) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this.skuInfo.goods_class == 6 && this.skuInfo.pricing_type == 'weight') {
|
||||
if (Number.parseFloat(this.skuInfo.weigh) <= 0 || !/^\d{0,10}(.?\d{0,3})$/.test(Number.parseFloat(this.skuInfo.weigh))) {
|
||||
this.$util.showToast({
|
||||
title: '请输入合法的数值,数值要大于零且小数位不能超过三位'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.skuInfo.stock < this.skuInfo.weigh) {
|
||||
this.$util.showToast({
|
||||
title: '商品库存不足'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.$pos.send('CloseWeigher');
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
this.skuInfo.is_adjust = this.skuInfo.adjust_price != this.skuInfo.price;
|
||||
|
||||
// 设置右侧商品的调价
|
||||
if (!this.goodsData.list[this.actionIndex].adjust['sku_id_' + this.skuInfo.sku_id]) {
|
||||
this.goodsData.list[this.actionIndex].adjust['sku_id_' + this.skuInfo.sku_id] = {};
|
||||
}
|
||||
this.goodsData.list[this.actionIndex].adjust['sku_id_' + this.skuInfo.sku_id].adjust_price = this.skuInfo.adjust_price;
|
||||
this.goodsData.list[this.actionIndex].adjust['sku_id_' + this.skuInfo.sku_id].is_adjust = this.skuInfo.is_adjust;
|
||||
|
||||
this.handleSelectGoods(this.skuInfo);
|
||||
this.scanCode = {
|
||||
lastTime: 0,
|
||||
code: ''
|
||||
};
|
||||
this.$store.commit('billing/setActive', 'SelectGoodsAfter'); // 记录页面当前活跃值:选择完商品
|
||||
this.$refs.skuPopup.close();
|
||||
},
|
||||
search() {
|
||||
switch (this.type) {
|
||||
case 'service':
|
||||
this.serviceData.page = 0;
|
||||
this.serviceData.index = 1;
|
||||
this.$refs.loading.show();
|
||||
this.getService();
|
||||
break;
|
||||
case 'goods':
|
||||
this.goodsData.page = 0;
|
||||
this.goodsData.index = 1;
|
||||
this.$refs.goodsLoading.show();
|
||||
this.getGoods();
|
||||
break;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.mediaQueryOb.disconnect();
|
||||
},
|
||||
switchStoreAfter() {
|
||||
this.serviceCategory = [];
|
||||
this.serviceCategoryId = 'all';
|
||||
this.serviceData = {
|
||||
size: 12,
|
||||
index: 1,
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
};
|
||||
this.goodsCategoryId = 'all';
|
||||
this.goodsCategory = [];
|
||||
this.goodsData = {
|
||||
size: 30,
|
||||
index: 1,
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
};
|
||||
this.getServiceCategoryFn();
|
||||
this.getGoodsCategoryFn();
|
||||
this.getService();
|
||||
this.getGoods();
|
||||
},
|
||||
pageChange(e) {
|
||||
if (this.type == 'goods') {
|
||||
this.goodsData.index = e.current;
|
||||
this.getGoods();
|
||||
} else if (this.type == 'service') {
|
||||
this.serviceData.index = e.current;
|
||||
this.getService();
|
||||
}
|
||||
},
|
||||
switchItem(type) {
|
||||
this.type = type;
|
||||
if (this.type == 'goods') {
|
||||
this.goodsData.index = 1;
|
||||
this.getGoods();
|
||||
} else if (this.type == 'service') {
|
||||
this.serviceData.index = 1;
|
||||
this.getService();
|
||||
} else if (this.type == 'money') {
|
||||
// 无码商品
|
||||
this.setActive('UnnumberedGoods');
|
||||
}
|
||||
},
|
||||
keydown(value) {
|
||||
let arr = this.paymentMoney.split('.');
|
||||
if (arr[1]) {
|
||||
if (value == '.' || arr[1].length == 2) return;
|
||||
if (value == '00' && arr[1].length == 1) value = '0';
|
||||
}
|
||||
if (parseFloat(this.paymentMoney + value) > 1000000) {
|
||||
this.$util.showToast({
|
||||
title: '最大不能超过1000000'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.paymentMoney += value;
|
||||
},
|
||||
deleteCode() {
|
||||
this.paymentMoney = this.paymentMoney.substr(0, this.paymentMoney.length - 1);
|
||||
},
|
||||
paymentMoneyConfirm() {
|
||||
if (!this.paymentMoney.length) {
|
||||
this.$util.showToast({
|
||||
title: '请输入收款金额'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (isNaN(parseFloat(this.paymentMoney)) || !/^(([0-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2})))$/.test(parseFloat(this.paymentMoney))) {
|
||||
this.$util.showToast({
|
||||
title: '收款金额格式错误'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.paymentMoney <= 0) {
|
||||
this.$util.showToast({
|
||||
title: '收款金额不能小于等于0'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (parseFloat(this.paymentMoney) > 1000000) {
|
||||
this.$util.showToast({
|
||||
title: '最大不能超过1000000'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.handleSelectGoods({
|
||||
goods_id: parseInt(new Date().getTime() / 1000),
|
||||
sku_id: parseInt(new Date().getTime() / 1000),
|
||||
num: 1,
|
||||
money: parseFloat(this.paymentMoney)
|
||||
});
|
||||
this.scanCode = {
|
||||
lastTime: 0,
|
||||
code: ''
|
||||
};
|
||||
this.$store.commit('billing/setActive', 'SelectGoodsAfter'); // 记录页面当前活跃值:选择完商品
|
||||
this.paymentMoney = '';
|
||||
},
|
||||
/**
|
||||
* 打开收银秤
|
||||
*/
|
||||
openCashierScale() {
|
||||
if (this.addon.includes('scale')) {
|
||||
if (!this.cashierScale) {
|
||||
getElectronicScaleInformation().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.cashierScale = res.data.config;
|
||||
try {
|
||||
this.$pos.send('OpenWeigher', `OS2X:${this.cashierScale.serialport}:${this.cashierScale.baudrate}`);
|
||||
} catch (e) {
|
||||
this.cashierScale = null
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
try {
|
||||
this.$pos.send('OpenWeigher', `OS2X:${this.cashierScale.serialport}:${this.cashierScale.baudrate}`);
|
||||
} catch (e) {
|
||||
this.cashierScale = null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 去皮
|
||||
*/
|
||||
tare() {
|
||||
this.$pos.send('Tare')
|
||||
},
|
||||
/**
|
||||
* 清零
|
||||
*/
|
||||
zero() {
|
||||
this.$pos.send('Zero');
|
||||
},
|
||||
setActive(key) {
|
||||
this.$store.commit('billing/setActive', key);
|
||||
},
|
||||
paymentMoneyChange(event) {
|
||||
if (this.paymentMoney.length == 0) {
|
||||
// 如果没有输入则结账
|
||||
this.setActive('SelectGoodsAfter')
|
||||
} else {
|
||||
this.setActive('UnnumberedGoods')
|
||||
}
|
||||
},
|
||||
// 商品数量减少
|
||||
dec(data) {
|
||||
if (this.skuInfo) {
|
||||
if (this.skuInfo.num <= 1 && this.skuInfo.stock > 0) {
|
||||
this.skuInfo.num = 1;
|
||||
} else if(this.skuInfo.stock > 0) {
|
||||
this.skuInfo.num--;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
// 商品数量增加
|
||||
inc(data) {
|
||||
if (this.skuInfo) {
|
||||
if (this.skuInfo.num >= this.skuInfo.stock && this.skuInfo.stock > 0) {
|
||||
this.skuInfo.num = this.skuInfo.stock;
|
||||
} else if(this.skuInfo.stock > 0){
|
||||
this.skuInfo.num++;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
// 打开钱箱
|
||||
openCashBox() {
|
||||
this.$emit('openCashBox')
|
||||
},
|
||||
setGoodsCategoryShow(id, index) {
|
||||
if (!this.goodsCategoryShow) {
|
||||
if (id === 'all') {
|
||||
if (this.goodsCategory.length > 13) {
|
||||
this.goodsCategoryShow = !this.goodsCategoryShow
|
||||
} else {
|
||||
this.goodsCategoryId = id
|
||||
}
|
||||
} else {
|
||||
this.goodsCategoryId = id
|
||||
}
|
||||
} else {
|
||||
this.goodsCategoryId = id;
|
||||
this.goodsCategoryIndex = index;
|
||||
this.goodsCategoryShow = false
|
||||
}
|
||||
},
|
||||
setServiceCategoryShow(id, index) {
|
||||
if (!this.serviceCategoryShow) {
|
||||
if (id === 'all') {
|
||||
if (this.serviceCategory.length > 13) {
|
||||
this.serviceCategoryShow = !this.serviceCategoryShow
|
||||
} else {
|
||||
this.serviceCategoryId = id
|
||||
}
|
||||
|
||||
} else {
|
||||
this.serviceCategoryId = id
|
||||
}
|
||||
} else {
|
||||
this.serviceCategoryId = id;
|
||||
this.serviceCategoryIndex = index;
|
||||
this.serviceCategoryShow = false
|
||||
}
|
||||
},
|
||||
isListShow() {
|
||||
this.goodsCategoryShow = false;
|
||||
this.serviceCategoryShow = false;
|
||||
},
|
||||
// 获取商品信息通过条形码
|
||||
getSkuByCode(code) {
|
||||
if (this.type != 'goods' || this.billingActive == 'ShowMember' || this.billingActive == 'OrderCreate') return;
|
||||
|
||||
code = code.toString().trim();
|
||||
getGoodsInfoByCode(code).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (res.data) {
|
||||
if (res.data.goods_state == 0) {
|
||||
this.$util.showToast({
|
||||
title: '该商品已下架'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (res.data.stock == 0) {
|
||||
this.$util.showToast({
|
||||
title: '该商品库存不足!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.handleSelectGoods(res.data);
|
||||
this.scanCode = {
|
||||
lastTime: 0,
|
||||
code: ''
|
||||
};
|
||||
this.$store.commit('billing/setActive', 'SelectGoodsAfter'); // 记录页面当前活跃值:选择完商品
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: '未找到该商品!'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message,
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
// 处理选中商品数据
|
||||
handleSelectGoods(data) {
|
||||
let key = 'sku_' + data.sku_id;
|
||||
let num = data.num || 1;
|
||||
num = parseInt(num);
|
||||
|
||||
// 项目服务和称重商品每次都是新增,重新定义key
|
||||
if (data.goods_class == 4 || data.goods_class == 6) {
|
||||
if (data.status == 'edit') {
|
||||
// 编辑
|
||||
key = data.editKey;
|
||||
} else {
|
||||
//新增
|
||||
var index = 0;
|
||||
Object.keys(this.billingGoodsData).forEach(k => {
|
||||
if (k.indexOf(key) != -1) {
|
||||
index++;
|
||||
}
|
||||
});
|
||||
key += '_' + index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 称重商品,计价方式:计重
|
||||
if (data.goods_class == 6 && data.pricing_type == 'weight') num = Number.parseFloat(data.weigh);
|
||||
|
||||
let _billingGoodsData = this.$util.deepClone(this.billingGoodsData);
|
||||
|
||||
// 已加入清单,追加数量
|
||||
if (_billingGoodsData[key]) {
|
||||
_billingGoodsData[key].num += num;
|
||||
} else {
|
||||
// 第一次加入清单,设置数据
|
||||
_billingGoodsData[key] = this.$util.deepClone(data);
|
||||
_billingGoodsData[key].num = num;
|
||||
}
|
||||
|
||||
// 编辑商品数量
|
||||
if (data.status && data.status == 'edit') {
|
||||
_billingGoodsData[key].num = num;
|
||||
}
|
||||
|
||||
// 称重商品每次覆盖数量
|
||||
if (data.goods_class == 6 && data.pricing_type == 'weight') {
|
||||
_billingGoodsData[key].num = parseFloat(_billingGoodsData[key].num.toFixed(3))
|
||||
}
|
||||
|
||||
// 调整单价
|
||||
if (data.adjust_price) {
|
||||
_billingGoodsData[key].price = parseFloat(data.adjust_price);
|
||||
_billingGoodsData[key].adjust_price = parseFloat(data.adjust_price);
|
||||
}
|
||||
|
||||
_billingGoodsData[key].is_adjust = data.is_adjust || false;
|
||||
|
||||
this.$store.commit('billing/setGoodsData', _billingGoodsData);
|
||||
|
||||
},
|
||||
/**
|
||||
* 添加扫码监听事件
|
||||
*/
|
||||
addScanCodeEvent() {
|
||||
// #ifdef APP-PLUS
|
||||
plus.key.addEventListener('keyup', this.listenerScanCode, true);
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
window.addEventListener('keypress', this.listenerScanCode, true);
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 移除扫码监听事件
|
||||
*/
|
||||
removeScanCodeEvent() {
|
||||
// #ifdef APP-PLUS
|
||||
plus.key.removeEventListener('keyup', this.listenerScanCode, true);
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
window.removeEventListener('keypress', this.listenerScanCode, true);
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 监听扫码事件
|
||||
* @param {Object} e
|
||||
*/
|
||||
listenerScanCode(e) {
|
||||
const clearBarCode = () => {
|
||||
this.scanCode = {
|
||||
lastTime: 0,
|
||||
code: ''
|
||||
};
|
||||
this.$store.commit('billing/setIsScanTrigger', false);
|
||||
};
|
||||
|
||||
// #ifdef H5
|
||||
var currCode = e.keyCode || e.which || e.charCode;
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const keyArr = {
|
||||
'keycode_7': 0,
|
||||
'keycode_8': 1,
|
||||
'keycode_9': 2,
|
||||
'keycode_10': 3,
|
||||
'keycode_11': 4,
|
||||
'keycode_12': 5,
|
||||
'keycode_13': 6,
|
||||
'keycode_14': 7,
|
||||
'keycode_15': 8,
|
||||
'keycode_16': 9
|
||||
};
|
||||
var currCode = keyArr['keycode_' + e.keyCode] || '';
|
||||
// #endif
|
||||
|
||||
var currTime = new Date().getTime();
|
||||
if (this.scanCode.lastTime > 0) {
|
||||
if (currTime - this.scanCode.lastTime <= 100) {
|
||||
this.scanCode.code += String.fromCharCode(currCode);
|
||||
this.$store.commit('billing/setIsScanTrigger', true);
|
||||
} else if (currTime - this.scanCode.lastTime > 500) {
|
||||
// 输入间隔500毫秒清空
|
||||
clearBarCode();
|
||||
}
|
||||
} else {
|
||||
this.scanCode.code = String.fromCharCode(currCode);
|
||||
}
|
||||
this.scanCode.lastTime = currTime;
|
||||
|
||||
// #ifdef H5
|
||||
var code = 13;
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
var code = 66;
|
||||
// #endif
|
||||
|
||||
if (currCode == code) {
|
||||
|
||||
// 扫码枪
|
||||
if (this.scanCode.code && this.scanCode.code.length >= 8) {
|
||||
this.scanCodeSearch = true;
|
||||
this.getSkuByCode(this.scanCode.code);
|
||||
this.$store.commit('billing/setIsScanTrigger', true);
|
||||
}
|
||||
|
||||
// 回车输入后清空
|
||||
clearBarCode();
|
||||
}
|
||||
|
||||
},
|
||||
/**
|
||||
* 添加键盘监听事件
|
||||
*/
|
||||
addKeyDownEvent() {
|
||||
// #ifdef H5
|
||||
window.addEventListener("keydown", this.listenerKeyDown, true);
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 移除键盘监听事件
|
||||
*/
|
||||
removeKeyDownEvent() {
|
||||
// #ifdef H5
|
||||
window.removeEventListener("keydown", this.listenerKeyDown, true);
|
||||
// #endif
|
||||
},
|
||||
// 监听键盘按下事件
|
||||
listenerKeyDown(e) {
|
||||
var code = e.code;
|
||||
|
||||
if (this.billingActive == 'SelectGoodsSku') {
|
||||
|
||||
// 打开商品规格项弹出框
|
||||
if (code == 'Enter' || code == 'NumpadEnter') {
|
||||
this.skuConfirm();
|
||||
}
|
||||
|
||||
} else if (this.billingActive == 'UnnumberedGoods') {
|
||||
// 无码商品
|
||||
|
||||
if (code == 'Enter' || code == 'NumpadEnter') {
|
||||
|
||||
if (!this.billingIsScanTrigger) this.paymentMoneyConfirm();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
/**
|
||||
* 监听重量变化
|
||||
* @param {Object} text
|
||||
*/
|
||||
window.WEIGHER_DATA_CALLBACK = function (text) {
|
||||
let data = text.split(':');
|
||||
self.$set(self.skuInfo, 'weigh', data[0] != '-' ? data[0] : '')
|
||||
};
|
||||
628
addon/cashier/source/os/components/ns-goods/index.scss
Executable file
628
addon/cashier/source/os/components/ns-goods/index.scss
Executable file
@@ -0,0 +1,628 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header-action {
|
||||
padding: 0.22rem 0.24rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-radius: 0.04rem;
|
||||
margin-bottom: 0.2rem;
|
||||
height: 0.88rem;
|
||||
|
||||
.header-action-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 0.44rem;
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-radius: 0.22rem;
|
||||
|
||||
view {
|
||||
min-width: 1.02rem;
|
||||
height: 0.44rem;
|
||||
line-height: 0.44rem;
|
||||
text-align: center;
|
||||
font-size: 0.14rem;
|
||||
border-left-width: 0;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
border-radius: 0.22rem;
|
||||
color: $primary-color;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-action-center {
|
||||
margin-left: 0.29rem;
|
||||
|
||||
.left {
|
||||
margin-right: 0.24rem;
|
||||
}
|
||||
|
||||
view {
|
||||
min-width: 1.02rem;
|
||||
height: 0.44rem;
|
||||
line-height: 0.44rem;
|
||||
text-align: center;
|
||||
font-size: 0.14rem;
|
||||
border-left-width: 0;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
border-radius: 0.22rem;
|
||||
color: #fff;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.header-action-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 0.4rem;
|
||||
border-radius: 0.2rem;
|
||||
border: 0.01rem solid #CCCCCC;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
input {
|
||||
background: #ffffff;
|
||||
border-radius: 0.02rem;
|
||||
height: 0.36rem;
|
||||
padding-left: 0.24rem;
|
||||
font-size: 0.14rem;
|
||||
width: 2.80rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
width: 0.36rem;
|
||||
height: 0.36rem;
|
||||
background: #ffffff;
|
||||
border-radius: 0.02rem;
|
||||
border-left: 0;
|
||||
text-align: center;
|
||||
line-height: 0.36rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
height: calc(100% - 1.08rem);
|
||||
transform: rotate(0);
|
||||
display: flex;
|
||||
|
||||
.table-pages {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 1.72rem;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
padding: 0.24rem 0.20rem;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.type-switch {
|
||||
width: 1.52rem;
|
||||
margin-right: 0.2rem;
|
||||
padding: 0.24rem 0;
|
||||
font-size: 0.14rem;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.04rem;
|
||||
position: relative;
|
||||
|
||||
.list {
|
||||
height: calc(100% - 0.6rem) !important;
|
||||
}
|
||||
|
||||
.list-all {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
box-shadow: 0.04rem 0 0.12rem 0 rgba(0, 0, 0, 0.04);
|
||||
transition: width 0.3s;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
border-radius: 0.04rem;
|
||||
|
||||
&.show {
|
||||
width: 4.08rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
width: 4.08rem;
|
||||
height: 100%;
|
||||
padding: 0.24rem;
|
||||
overflow-y: auto;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.switch-item {
|
||||
margin-right: 0.24rem;
|
||||
width: 1.04rem;
|
||||
&:nth-child(2n+2){
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/deep/ .uni-scroll-view-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// align-items: center;
|
||||
}
|
||||
|
||||
// /deep/ .uni-scroll-view {
|
||||
// width: 1.1rem !important;
|
||||
// }
|
||||
|
||||
.switch-item {
|
||||
width: 1.04rem;
|
||||
border-radius: 0.04rem;
|
||||
padding: 0.1rem 0.1rem;
|
||||
font-size: 0.14rem;
|
||||
text-align: center;
|
||||
margin-left: 0.24rem;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
border: 0.01rem solid #DCDEE2;
|
||||
.item-title{
|
||||
white-space: normal;
|
||||
max-height: 0.4rem;
|
||||
overflow: hidden;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
.all-category{
|
||||
.switch-item {
|
||||
height: 0.4rem;
|
||||
width: 1.04rem;
|
||||
border-radius: 0.04rem;
|
||||
padding: 0 0.1rem;
|
||||
font-size: 0.14rem;
|
||||
text-align: center;
|
||||
line-height: 0.4rem;
|
||||
margin-left: 0.24rem;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border: 0.01rem solid #DCDEE2;
|
||||
}
|
||||
}
|
||||
.switch-item.active {
|
||||
background-color: $primary-color;
|
||||
border-color: $primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.switch-item:not(:last-child) {
|
||||
margin-bottom: 0.20rem;
|
||||
}
|
||||
}
|
||||
|
||||
.list-wrap {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding-bottom: 0.78rem;
|
||||
}
|
||||
|
||||
.money-pages {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.money-wrap {
|
||||
background: #fff;
|
||||
border-radius: 0.05rem;
|
||||
padding-top: 0.3rem;
|
||||
|
||||
.head {
|
||||
height: 0.6rem;
|
||||
line-height: 0.6rem;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
|
||||
text {
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.iconguanbi1 {
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.22rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
display: flex;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
height: 0.6rem;
|
||||
align-items: center;
|
||||
margin: 0 0.2rem;
|
||||
padding: 0 0.15rem;
|
||||
|
||||
.unit {
|
||||
font-size: 0.25rem;
|
||||
}
|
||||
|
||||
.money {
|
||||
margin-left: 0.05rem;
|
||||
font-size: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.keyboard-wrap {
|
||||
width: 4rem;
|
||||
padding: 0 0.2rem 0.3rem 0.2rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-list {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
width: calc(100% + 0.12rem);
|
||||
|
||||
.table-item {
|
||||
border: 0.01rem solid #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0.18rem 0.1rem 0.1rem;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.12rem;
|
||||
margin-right: 0.12rem;
|
||||
cursor: pointer;
|
||||
transition: border-color, background-color 0.3s;
|
||||
position: relative;
|
||||
border-radius: 0.04rem;
|
||||
&.item-mum-2{
|
||||
width: calc((100% - 0.25rem) / 2);
|
||||
}
|
||||
&.item-mum-3{
|
||||
width: calc((100% - 0.37rem) / 3);
|
||||
}
|
||||
&.item-mum-4{
|
||||
width: calc((100% - 0.49rem) / 4);
|
||||
}
|
||||
&:focus{
|
||||
outline: none;
|
||||
}
|
||||
.item-other {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-left: 0.1rem;
|
||||
|
||||
}
|
||||
|
||||
.item-img {
|
||||
width: 0.9rem;
|
||||
height: 0.9rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
-ms-flex-negative: 0;
|
||||
-webkit-flex-shrink: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
border-radius: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
height: 0.4rem;
|
||||
line-height: 0.2rem;
|
||||
max-width: 1.58rem;
|
||||
margin-bottom: 0.05rem;
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
.item-time {
|
||||
font-size: 0.12rem;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.item-money {
|
||||
font-size: 0.14rem;
|
||||
color: $primary-color;
|
||||
height: 0.19rem;
|
||||
line-height: 0.19rem;
|
||||
}
|
||||
|
||||
.item-stock {
|
||||
height: 0.17rem;
|
||||
font-size: 0.12rem;
|
||||
color: #808695;
|
||||
line-height: 0.17rem;
|
||||
}
|
||||
}
|
||||
|
||||
.no-stock {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
cursor: not-allowed;
|
||||
|
||||
image {
|
||||
height: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.table-item.yes-stock {
|
||||
&:hover {
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
&.focus,
|
||||
&:focus {
|
||||
background-color: var(--primary-color-light-9);
|
||||
border-color: $primary-color;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $primary-color;
|
||||
background-color: $primary-color;
|
||||
color: #fff;
|
||||
|
||||
.item-time,
|
||||
.item-money,
|
||||
.item-stock {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sku-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 7rem;
|
||||
height: 4rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.04rem;
|
||||
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
.header,
|
||||
.footer {
|
||||
height: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
padding: 0.15rem;
|
||||
|
||||
scroll-view {
|
||||
height: 2.55rem;
|
||||
}
|
||||
}
|
||||
|
||||
.spec {
|
||||
line-height: 0.35rem;
|
||||
font-weight: bold;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.spec-value {
|
||||
.value-item {
|
||||
display: inline-block;
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
margin: 0.05rem 0.1rem 0 0;
|
||||
padding: 0 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-radius: 0.04rem;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background: var(--primary-color-light-9);
|
||||
border-color: $primary-color;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
background: #f7f7f7;
|
||||
border-color: #f7f7f7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.spec-value-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.spec-value-input {
|
||||
margin-right: 0.05rem;
|
||||
border-width: 0.01rem;
|
||||
border-style: solid;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
padding-left: 0.1rem;
|
||||
height: 0.38rem;
|
||||
line-height: 0.38rem;
|
||||
font-size: 0.14rem;
|
||||
border-color: #e6e6e6;
|
||||
border-radius: 0.02rem;
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.num-dec {
|
||||
width: 0.25rem;
|
||||
height: 0.25rem;
|
||||
background: #e6e6e6;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-right: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.num-inc {
|
||||
width: 0.25rem;
|
||||
height: 0.25rem;
|
||||
background: $primary-color;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-left: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.scale-action {
|
||||
button {
|
||||
width: .8rem;
|
||||
margin: .15rem .15rem 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
display: flex;
|
||||
|
||||
.image {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
margin-right: 0.1rem;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
.price {
|
||||
line-height: 1;
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
border: 0;
|
||||
height: 0.6rem;
|
||||
|
||||
button {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding-top: 1.2rem;
|
||||
|
||||
image {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 450px) and (max-width: 950px) {
|
||||
.type-switch .list-all.show {
|
||||
width: 2.78rem;
|
||||
.center{
|
||||
width: 2.78rem;
|
||||
.switch-item:nth-child(2n+2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.switch-item:nth-child(3n+3) {
|
||||
margin-right: 0.24rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1201px) and (max-width: 1900px) {
|
||||
.type-switch .list-all.show {
|
||||
width: 6.6rem;
|
||||
.center{
|
||||
width: 6.6rem;
|
||||
.switch-item:nth-child(5n+5) {
|
||||
margin-right: 0;
|
||||
}
|
||||
.switch-item:nth-child(3n+3) {
|
||||
margin-right: 0.24rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
239
addon/cashier/source/os/components/ns-goods/ns-goods.vue
Executable file
239
addon/cashier/source/os/components/ns-goods/ns-goods.vue
Executable file
@@ -0,0 +1,239 @@
|
||||
<template>
|
||||
<view class="container goods-container">
|
||||
<view class="header-action common-wrap">
|
||||
<view class="flex items-center">
|
||||
<view class="header-action-left">
|
||||
<view class="flex-1" :class="{ active: type == 'goods' }" @click="switchItem('goods')">商品</view>
|
||||
<view class="flex-1" :class="{ active: type == 'service' }" @click="switchItem('service')">项目</view>
|
||||
<view class="flex-1" :class="{ active: type == 'money' }" @click="switchItem('money')">无码商品</view>
|
||||
</view>
|
||||
<view class="header-action-center flex" v-if="billingIsShowCashBox">
|
||||
<view class="flex-1" @click="openCashBox()">打开钱箱</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="header-action-right">
|
||||
<input placeholder="请输入商品/项目名称/编码" placeholder-style="font-size:0.14rem;color:#ACACAC;" v-model="searchText" @focus="setActive('inputSearchText')" @blur="setActive('')" @confirm="search" />
|
||||
<view class="search-btn" @click="search">
|
||||
<text class="iconfont icon31sousuo"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<view class="type-switch common-wrap flex-shrink-0 flex uni-column" v-if="serviceCategory.length && type == 'service'">
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: serviceCategoryId == 'all' }" @click.stop="setServiceCategoryShow('all',0)">所有分类</view>
|
||||
<scroll-view scroll-y="true" :show-scrollbar="false" :scroll-into-view="'serviceCategory-' + serviceCategoryIndex" class="list flex-shrink-0 common-scrollbar">
|
||||
<view :id="'serviceCategory-' + index" class="switch-item flex-shrink-0" :class="{ active: serviceCategoryId == item.category_id }" v-for="(item, index) in serviceCategory" :key="index" @click.stop="setServiceCategoryShow(item.category_id,index)">
|
||||
<view class="item-title">{{ item.category_name }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view v-if="serviceCategory.length > 13" class="list-all common-wrap" :class="{ 'show': serviceCategoryShow }" @click.stop="() => { return false }">
|
||||
<view class="all-category center flex content-start">
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: serviceCategoryId == 'all' }" @click="setServiceCategoryShow('all', 0)">所有分类</view>
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: serviceCategoryId == item.category_id }" v-for="(item, index) in serviceCategory" :key="index" @click="setServiceCategoryShow(item.category_id, index)">
|
||||
<view class="item-title">{{ item.category_name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="type-switch common-wrap flex-shrink-0 flex uni-column" v-if="goodsCategory.length && type == 'goods'">
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: goodsCategoryId == 'all' }" @click.stop.prevent="setGoodsCategoryShow('all',0)">所有分类</view>
|
||||
<scroll-view scroll-y="true" :show-scrollbar="false" :scroll-into-view="'goodsCategory-' + goodsCategoryIndex" class="list flex-shrink-0 common-scrollbar" v-show="goodsCategory.length && type == 'goods'">
|
||||
<view :id="'goodsCategory-' + index" class="switch-item flex-shrink-0" :class="{ active: goodsCategoryId == item.category_id }" v-for="(item, index) in goodsCategory" :key="index" @click.stop="setGoodsCategoryShow(item.category_id,index)">
|
||||
<view class="item-title">{{ item.category_name }}</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view v-if="goodsCategory.length > 13" class="list-all common-wrap" :class="{ 'show': goodsCategoryShow }" @click.stop="() => { return false }">
|
||||
<view class="all-category center flex content-start">
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: goodsCategoryId == 'all' }" @click="setGoodsCategoryShow('all')">所有分类</view>
|
||||
<view class="switch-item flex-shrink-0" :class="{ active: goodsCategoryId == item.category_id }" v-for="(item, index) in goodsCategory" :key="index" @click="setGoodsCategoryShow(item.category_id, index)">
|
||||
<view class="item-title">{{ item.category_name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="list-wrap goods" v-show="type == 'goods'" @scrolltolower="nextGoodsLiist">
|
||||
<view class="table-list" v-show="goodsData.list.length" data-focus="true">
|
||||
<view class="table-item goods-select-focus goods-focus"
|
||||
:class="{ 'yes-stock': item.stock>0, 'item-mum-2': itemNum == 2, 'item-mum-3': itemNum == 3, 'item-mum-4': itemNum == 4, active: billingGoodsIds.indexOf(item.goods_id) != -1, focus: indexFocus == index }"
|
||||
v-for="(item, index) in goodsData.list" :key="index" @click="goodsSelect(item, index)" tabindex="0" :data-tab-index="index">
|
||||
|
||||
<view class="item-info">
|
||||
<view class="item-img">
|
||||
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" @error="item.goods_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="item-other flex-1">
|
||||
<view class="item-name multi-hidden">{{ item.goods_name }}</view>
|
||||
<view class="w-full flex justify-between items-center self-end">
|
||||
<view class="item-money">¥{{ item.price | moneyFormat }}</view>
|
||||
<view class="item-stock">库存:{{ item.stock }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="no-stock" v-if="item.stock <= 0">
|
||||
<image src="@/static/stock/stock_empty.png" mode="heightFix"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-show="isGoodsLoad && !goodsData.list.length">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无商品</view>
|
||||
</view>
|
||||
<ns-loading :layer-background="{ background: 'rgba(255,255,255,.6)' }" :default-show="false" ref="goodsLoading"></ns-loading>
|
||||
</scroll-view>
|
||||
|
||||
<scroll-view scroll-y="true" class="list-wrap service" v-show="type == 'service'">
|
||||
<view class="table-list" v-show="serviceData.list.length">
|
||||
|
||||
<view class="table-item goods-select-focus service-focus"
|
||||
:class="{ 'yes-stock': item.stock > 0, 'item-mum-2': itemNum == 2, 'item-mum-3': itemNum == 3, 'item-mum-4': itemNum == 4, active: billingGoodsIds.indexOf(item.goods_id) != -1, focus: indexFocus == index }"
|
||||
v-for="(item, index) in serviceData.list" :key="index" @click="goodsSelect(item, index)" tabindex="0" :data-tab-index="index">
|
||||
|
||||
<view class="item-info">
|
||||
<view class="item-img">
|
||||
<image v-if="item.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.goods_image.split(',')[0], { size: 'small' })" @error="item.goods_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="item-other">
|
||||
<view class="item-name multi-hidden">{{ item.goods_name }}</view>
|
||||
<view class="w-full flex justify-between items-center self-end">
|
||||
<view class="item-money">¥{{ item.price | moneyFormat }}</view>
|
||||
<view class="item-time" v-if="item.service_length">时长:{{ item.service_length }}分钟</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="no-stock" v-if="item.stock <= 0">
|
||||
<image src="@/static/stock/stock_empty.png" mode="heightFix"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-show="!serviceData.list.length">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无商品</view>
|
||||
</view>
|
||||
<ns-loading :layer-background="{ background: 'rgba(255,255,255,.6)' }" :default-show="false" ref="loading"></ns-loading>
|
||||
</scroll-view>
|
||||
|
||||
<view class="table-pages" v-show="type == 'service' && serviceData.list.length">
|
||||
<uni-pagination :total="serviceData.total" :showIcon="true" @change="pageChange" :pageSize="serviceData.size" :value="serviceData.index" />
|
||||
</view>
|
||||
<!-- <view class="table-pages" v-show="type == 'goods' && goodsData.list.length">
|
||||
<uni-pagination :total="goodsData.total" :showIcon="true" @change="pageChange" :pageSize="goodsData.size" :value="goodsData.index" />
|
||||
</view> -->
|
||||
|
||||
<view class="money-pages" v-show="type == 'money'">
|
||||
<view class="money-wrap">
|
||||
<view class="content-wrap">
|
||||
<view class="unit">¥</view>
|
||||
<input type="text" class="money" v-model="paymentMoney" @input="paymentMoneyChange" />
|
||||
</view>
|
||||
<view class="keyboard-wrap">
|
||||
<view class="num-wrap">
|
||||
<view class="key-item" @click="keydown('1')">1</view>
|
||||
<view class="key-item" @click="keydown('2')">2</view>
|
||||
<view class="key-item" @click="keydown('3')">3</view>
|
||||
<view class="key-item" @click="keydown('4')">4</view>
|
||||
<view class="key-item" @click="keydown('5')">5</view>
|
||||
<view class="key-item" @click="keydown('6')">6</view>
|
||||
<view class="key-item" @click="keydown('7')">7</view>
|
||||
<view class="key-item" @click="keydown('8')">8</view>
|
||||
<view class="key-item" @click="keydown('9')">9</view>
|
||||
<view class="key-item" @click="keydown('00')">00</view>
|
||||
<view class="key-item" @click="keydown('0')">0</view>
|
||||
<view class="key-item" @click="keydown('.')">.</view>
|
||||
</view>
|
||||
<view class="action-wrap">
|
||||
<view class="delete" @click="deleteCode">删除</view>
|
||||
<view class="delete" @click="paymentMoney = ''">清空</view>
|
||||
<view class="confirm" @click="paymentMoneyConfirm">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-popup ref="skuPopup" type="center">
|
||||
<view class="sku-wrap">
|
||||
<view class="header">
|
||||
<text class="title">{{ skuInfo && skuInfo.status == 'edit' ? '调整' : '选择' }}</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.skuPopup.close()"></text>
|
||||
</view>
|
||||
<view class="body">
|
||||
<scroll-view scroll-y="true">
|
||||
<view class="goods-info" v-if="skuInfo">
|
||||
<view class="image">
|
||||
<image v-if="skuInfo.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(skuInfo.sku_image, { size: 'small' })" @error="skuInfo.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="multi-hidden">{{ skuInfo.goods_name }}</view>
|
||||
<view class="price">¥{{ skuInfo.adjust_price }} / {{ skuInfo.unit ? skuInfo.unit : '件' }}</view>
|
||||
<view>库存:{{ skuInfo.stock }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-for="(item, index) in goodsSpec" :key="index">
|
||||
<view class="spec">{{ item.spec_name }}</view>
|
||||
<view class="spec-value">
|
||||
<view class="value-item" :class="{ active: spec.selected, disabled: (!spec.selected && skuInfo.status == 'edit') }" v-for="(spec, sindex) in item.value" :key="sindex" @click="skuSelect(spec.sku_id)">
|
||||
{{ spec.spec_value_name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block v-if="skuInfo">
|
||||
<view class="spec">单价</view>
|
||||
<view class="spec-value spec-value-form">
|
||||
<input type="text" class="spec-value-input" v-model="skuInfo.adjust_price" placeholder="请输入单价" />
|
||||
<text>元</text>
|
||||
</view>
|
||||
<block v-if="skuInfo.goods_class != 6">
|
||||
<view class="spec">数量</view>
|
||||
<view class="spec-value spec-value-form">
|
||||
<view class="num-dec" @click.stop="dec">-</view>
|
||||
<input type="text" class="spec-value-input" v-model="skuInfo.num" placeholder="请输入数量" :focus="inputFocus" @focus="inputFocus = true" @blur="inputFocus = false" />
|
||||
<view class="num-inc" @click.stop="inc">+</view>
|
||||
<text>{{ skuInfo.unit }}</text>
|
||||
</view>
|
||||
</block>
|
||||
<block v-if="skuInfo.goods_class == 6 && skuInfo.pricing_type == 'weight'">
|
||||
<view class="info">
|
||||
<view class="spec">剩余库存</view>
|
||||
<view>{{ skuInfo.stock }}<text>{{ skuInfo.unit }}</text></view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="spec">称重</view>
|
||||
<view class="spec-value spec-value-form">
|
||||
<input type="text" class="spec-value-input" v-model="skuInfo.weigh" placeholder="请输入重量" :focus="inputFocus" @focus="inputFocus = true" @blur="inputFocus = false" />
|
||||
<text>{{ skuInfo.unit }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex scale-action" v-if="addon.includes('scale') && cashierScale">
|
||||
<button type="primary" class="default-btn" plain @click="zero">归零</button>
|
||||
<button type="primary" class="default-btn" plain @click="tare">去皮</button>
|
||||
</view>
|
||||
</block>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<button type="default" class="primary-btn" @click="skuConfirm" :disabled="skuInfo && skuInfo.stock <= 0">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from './index.js';
|
||||
export default {
|
||||
mixins: [index],
|
||||
components:{
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
116
addon/cashier/source/os/components/ns-loading/ns-loading.vue
Executable file
116
addon/cashier/source/os/components/ns-loading/ns-loading.vue
Executable file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view class="loading-layer" v-if="isShow" :style="layerBackground">
|
||||
<view class="loading-anim">
|
||||
<view class="box item"><view class="border out item color-base-border-top color-base-border-left"></view></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'nsLoading',
|
||||
props: {
|
||||
layerBackground: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
defaultShow: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShow: true
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.isShow = this.defaultShow;
|
||||
},
|
||||
methods: {
|
||||
show() {
|
||||
this.isShow = true;
|
||||
},
|
||||
hide() {
|
||||
this.isShow = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.loading-layer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 997;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.loading-anim {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 40%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.loading-anim > .item {
|
||||
position: relative;
|
||||
width: 0.3rem;
|
||||
height: 0.3rem;
|
||||
perspective: 8rem;
|
||||
transform-style: preserve-3d;
|
||||
transition: all 0.2s ease-out;
|
||||
}
|
||||
|
||||
.loading-anim .border {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
border: 0.03rem solid $primary-color;
|
||||
}
|
||||
|
||||
.loading-anim .out {
|
||||
top: 15%;
|
||||
left: 15%;
|
||||
width: 70%;
|
||||
height: 70%;
|
||||
// border-left-color: red !important;
|
||||
border-right-color: rgba($color: #000000, $alpha: 0) !important;
|
||||
// border-top-color: rgba($color: #000000, $alpha: 0) !important;
|
||||
border-bottom-color: rgba($color: #000000, $alpha: 0) !important;
|
||||
animation: spin 0.6s linear normal infinite;
|
||||
}
|
||||
|
||||
.loading-anim .in {
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
border-top-color: transparent !important;
|
||||
border-bottom-color: transparent !important;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.loading-anim .mid {
|
||||
top: 40%;
|
||||
left: 40%;
|
||||
width: 20%;
|
||||
height: 20%;
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
</style>
|
||||
195
addon/cashier/source/os/components/ns-member-card-popup/index.js
Executable file
195
addon/cashier/source/os/components/ns-member-card-popup/index.js
Executable file
@@ -0,0 +1,195 @@
|
||||
import {
|
||||
getMemberCardList
|
||||
} from '@/api/member'
|
||||
import {mapGetters} from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
memberCardData: {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: [],
|
||||
index: 0,
|
||||
currData: {},
|
||||
selected: {}
|
||||
},
|
||||
itemNum: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['billingGoodsData'])
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.$refs.memberCardPopup.open();
|
||||
this.memberCardData.page = 0;
|
||||
this.memberCardData.index = 0;
|
||||
this.memberCardData.list = [];
|
||||
this.memberCardData.currData = {};
|
||||
this.memberCardData.selected = {};
|
||||
this.getMemberCard()
|
||||
},
|
||||
// 获取会员项目
|
||||
getMemberCard() {
|
||||
if (this.memberCardData.page + 1 > this.memberCardData.total) return;
|
||||
this.memberCardData.page += 1;
|
||||
getMemberCardList({
|
||||
status: 1,
|
||||
page: this.memberCardData.page,
|
||||
member_id: this.globalMemberInfo.member_id
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.memberCardData.total = res.data.page_count || 1;
|
||||
Object.values(this.billingGoodsData).forEach(data => {
|
||||
if (data.card_id) {
|
||||
res.data.list.forEach((card)=>{
|
||||
if(card.card_id == data.card_id){
|
||||
// 通用卡:选择商品,总数量发生变化
|
||||
if (data.card_type == 'commoncard') {
|
||||
card.total_use_num += data.num;
|
||||
} else if (data.card_type == 'oncecard') {
|
||||
// 限次卡:选择商品后,商品和总数量都要发生变化
|
||||
card.total_use_num += data.num;
|
||||
card.item_list.forEach((card_item)=>{
|
||||
if(card_item.item_id == data.item_id){
|
||||
card_item.use_num += data.num;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
if (res.data.list.length) this.memberCardData.list = this.memberCardData.list.concat(res.data.list);
|
||||
if (this.memberCardData.page == 1) {
|
||||
// 默认展示第一个卡项信息
|
||||
if (res.data.count) this.selectMemberCard(this.memberCardData.list[0], 0);
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 选择会员套餐
|
||||
* @param {Object} data
|
||||
* @param {Object} index
|
||||
*/
|
||||
selectMemberCard(data, index) {
|
||||
this.memberCardData.index = index;
|
||||
this.memberCardData.currData = this.$util.deepClone(data);
|
||||
this.memberCardData.selected = {};
|
||||
},
|
||||
/**
|
||||
* 选择会员套餐商品项
|
||||
* @param {Object} data
|
||||
* @param {Object} index
|
||||
*/
|
||||
selectMemberCardItem(data, index) {
|
||||
if (this.memberCardData.selected['item_' + data.item_id]) {
|
||||
if (data.card_type == 'commoncard') {
|
||||
this.memberCardData.currData.total_use_num -= this.memberCardData.selected['item_' + data.item_id].input_num;
|
||||
}
|
||||
delete this.memberCardData.selected['item_' + data.item_id];
|
||||
} else {
|
||||
if (!this.checkStatus(data)) return;
|
||||
this.memberCardData.selected['item_' + data.item_id] = this.$util.deepClone(data);
|
||||
this.memberCardData.selected['item_' + data.item_id].input_num = 1;
|
||||
this.memberCardData.selected['item_' + data.item_id].index = index;
|
||||
this.memberCardData.selected['item_' + data.item_id].card_name = this.memberCardData.currData.goods_name;
|
||||
if (data.card_type == 'commoncard') {
|
||||
this.memberCardData.currData.total_use_num += 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.$forceUpdate();
|
||||
},
|
||||
/**
|
||||
* 加入购物车
|
||||
*/
|
||||
selectGoods() {
|
||||
if (!Object.keys(this.memberCardData.selected).length) {
|
||||
this.$util.showToast({
|
||||
title: '请选择服务/商品',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let billingGoodsData = this.$util.deepClone(this.billingGoodsData);
|
||||
let billingGoodsKeys = Object.keys(billingGoodsData);
|
||||
Object.keys(this.memberCardData.selected).forEach((key) => {
|
||||
|
||||
let data = this.memberCardData.selected[key];
|
||||
data.card_index = this.memberCardData.index;
|
||||
this.memberCardData.list[this.memberCardData.index].total_use_num += data.input_num;
|
||||
this.memberCardData.list[this.memberCardData.index].item_list[data.index].use_num += data.input_num;
|
||||
this.memberCardData.currData.item_list[data.index].use_num += data.input_num;
|
||||
//服务商品每个都是一个订单项,需要循环处理
|
||||
if(data.goods_class == this.$util.goodsClassDict.service){
|
||||
let addNum = 0;
|
||||
Object.values(billingGoodsData).forEach((item)=>{
|
||||
if(item.sku_id == data.sku_id){
|
||||
addNum ++;
|
||||
}
|
||||
})
|
||||
data.num = 1;
|
||||
for(let num = 1;num <= data.input_num;num ++){
|
||||
let skuKey = 'sku_' + data.sku_id + '_item_' + data.item_id + '_' + addNum;
|
||||
billingGoodsData[skuKey] = this.$util.deepClone(data);
|
||||
addNum ++;
|
||||
}
|
||||
}else{
|
||||
data.num = data.input_num;
|
||||
let skuKey = 'sku_' + data.sku_id + '_item_' + data.item_id;
|
||||
if(billingGoodsData.hasOwnProperty(skuKey)){
|
||||
data.num += billingGoodsData[skuKey].num;
|
||||
}
|
||||
billingGoodsData[skuKey] = this.$util.deepClone(data);
|
||||
}
|
||||
});
|
||||
|
||||
this.$store.commit('billing/setGoodsData', billingGoodsData);
|
||||
|
||||
this.memberCardData.selected = {};
|
||||
},
|
||||
/**
|
||||
* 数量减
|
||||
* @param {Object} data
|
||||
*/
|
||||
itemDec(data) {
|
||||
let currData = this.memberCardData.currData;
|
||||
if (this.memberCardData.selected['item_' + data.item_id].input_num > 1) {
|
||||
this.memberCardData.selected['item_' + data.item_id].input_num -= 1;
|
||||
if (data.card_type == 'commoncard') {
|
||||
currData.total_use_num -= 1;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 数量加
|
||||
* @param {Object} data
|
||||
*/
|
||||
itemInc(data) {
|
||||
let currData = this.memberCardData.currData;
|
||||
if (data.card_type == 'commoncard') {
|
||||
if ((currData.total_num - currData.total_use_num - 1) < 0) return;
|
||||
} else if (data.card_type == 'oncecard') {
|
||||
if ((data.num - data.use_num - this.memberCardData.selected['item_' + data.item_id].input_num - 1) < 0) return;
|
||||
}
|
||||
if (data.card_type == 'commoncard') {
|
||||
currData.total_use_num += 1;
|
||||
}
|
||||
this.memberCardData.selected['item_' + data.item_id].input_num += 1;
|
||||
this.$forceUpdate();
|
||||
},
|
||||
checkStatus(data) {
|
||||
let currData = this.memberCardData.currData;
|
||||
if (data.card_type == 'commoncard') {
|
||||
return currData.total_num > currData.total_use_num;
|
||||
} else if (data.card_type == 'oncecard') {
|
||||
return data.num > data.use_num;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
376
addon/cashier/source/os/components/ns-member-card-popup/index.scss
Executable file
376
addon/cashier/source/os/components/ns-member-card-popup/index.scss
Executable file
@@ -0,0 +1,376 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 0.66rem;
|
||||
line-height: 0.66rem;
|
||||
text-align: left;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
color: #303133;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.info-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 6.5rem;
|
||||
padding: 0 0.2rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.headimg-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.headimg {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info {
|
||||
margin-left: 0.15rem;
|
||||
width: calc(100% - 0.85rem);
|
||||
|
||||
.name {
|
||||
font-size: 0.16rem;
|
||||
color: #303133;
|
||||
|
||||
text {
|
||||
background: #ffffff;
|
||||
border: 0.01rem solid $primary-color;
|
||||
border-radius: 0.02rem;
|
||||
font-size: 0.12rem;
|
||||
color: $primary-color;
|
||||
margin-left: 0.15rem;
|
||||
padding: 0.01rem 0.04rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header-info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.1rem;
|
||||
justify-content: space-between;
|
||||
|
||||
view {
|
||||
text-align: left;
|
||||
font-size: 0.14rem;
|
||||
color: #303133;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding-top: 1.2rem;
|
||||
margin: 0 auto;
|
||||
|
||||
image {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.member-card-wrap {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.card-wrap {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
display: flex;
|
||||
padding-top: 0.2rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
width: 2rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
margin-right: 0.1rem;
|
||||
padding: 0.1rem 0;
|
||||
|
||||
.card-item {
|
||||
width: calc(100% - 0.2rem);
|
||||
height: 1rem;
|
||||
border: 0.01rem solid $primary-color;
|
||||
margin: 0 0.1rem 0.1rem 0.1rem;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.05rem;
|
||||
cursor: pointer;
|
||||
padding: 0.15rem 0.1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
background-color: var(--primary-color-light-8);
|
||||
|
||||
&.active {
|
||||
background-color: $primary-color;
|
||||
color: #fff;
|
||||
|
||||
.card-name {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.card-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
|
||||
& > view {
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-list {
|
||||
flex: 1;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 0;
|
||||
|
||||
.content {
|
||||
padding: 0 0.1rem;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding-top: 0.8rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
line-height: 0.3rem;
|
||||
padding: 0.1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.num {
|
||||
color: $primary-color;
|
||||
margin: 0 0.02rem;
|
||||
}
|
||||
}
|
||||
|
||||
.button-wrap {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
box-shadow: 0 0.04rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
padding: 0.1rem 0;
|
||||
|
||||
button {
|
||||
height: 0.4rem;
|
||||
line-height: 0.4rem;
|
||||
margin: 0 0.1rem 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.item-wrap {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
display: flex;
|
||||
|
||||
.uni-flex {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.card-item {
|
||||
display: flex;
|
||||
width: calc(50% - 0.05rem);
|
||||
padding: 0.1rem;
|
||||
border: 0.01rem solid #eee;
|
||||
border-radius: 0.03rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
.image {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
margin-right: 0.1rem;
|
||||
overflow: hidden;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 0;
|
||||
|
||||
.num {
|
||||
margin-top: 0.05rem;
|
||||
color: #999;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 0.14rem;
|
||||
color: #fe2278;
|
||||
line-height: 1;
|
||||
|
||||
.util {
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
word-break: break-all;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.5;
|
||||
|
||||
.tag {
|
||||
border-radius: 0.02rem;
|
||||
padding: 0.01rem 0.05rem;
|
||||
background-color: var(--primary-color-light-8);
|
||||
color: $primary-color;
|
||||
font-size: 0.12rem;
|
||||
margin-right: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 0.12rem;
|
||||
margin-top: 0.05rem;
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.number-wrap {
|
||||
display: none;
|
||||
height: 0.25rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 0.02rem;
|
||||
overflow: hidden;
|
||||
|
||||
input {
|
||||
height: 0.25rem;
|
||||
line-height: 0.25rem;
|
||||
width: 0.25rem;
|
||||
border: 1px solid #e6e6e6;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
height: 0.25rem;
|
||||
width: 0.25rem;
|
||||
text-align: center;
|
||||
line-height: 0.25rem;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.card-item.active {
|
||||
background-color: var(--primary-color-light-2);
|
||||
|
||||
.num {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.price {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #fff;
|
||||
|
||||
.tag {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.number-wrap {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.not-select {
|
||||
background: #eee;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pop弹框
|
||||
.pop-box {
|
||||
background: #ffffff;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
|
||||
.pop-header {
|
||||
padding: 0 0.15rem 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #f0f0f0;
|
||||
font-size: 0.14rem;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
border-radius: 0.02rem 0.2rem 0 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.pop-header-text {
|
||||
}
|
||||
|
||||
.pop-header-close {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 0.18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 1rem);
|
||||
overflow-y: scroll;
|
||||
padding: 0.1rem 0.2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
129
addon/cashier/source/os/components/ns-member-card-popup/ns-member-card-popup.vue
Executable file
129
addon/cashier/source/os/components/ns-member-card-popup/ns-member-card-popup.vue
Executable file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<uni-popup ref="memberCardPopup">
|
||||
|
||||
<view class="pop-box member-info-wrap">
|
||||
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">会员卡项</view>
|
||||
<view class="pop-header-close" @click="$refs.memberCardPopup.close()">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-wrap" v-if="globalMemberInfo">
|
||||
<view class="headimg-content">
|
||||
<view class="headimg">
|
||||
<image :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)" @error="globalMemberInfo.headimg = defaultImg.head"/>
|
||||
</view>
|
||||
<view class="header-info">
|
||||
<view class="name">
|
||||
{{ globalMemberInfo.nickname }}
|
||||
<text v-if="globalMemberInfo.member_level">{{ globalMemberInfo.member_level_name }}</text>
|
||||
</view>
|
||||
<view class="header-info-item">
|
||||
<view>电话:{{ globalMemberInfo.mobile }}</view>
|
||||
<view>性别:{{ globalMemberInfo.sex == 0 ? '未知' : globalMemberInfo.sex == 1 ? '男' : '女' }}</view>
|
||||
<view>生日:{{ globalMemberInfo.birthday }}</view>
|
||||
<view>注册时间:{{ globalMemberInfo.reg_time | timeFormat }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="member-card-wrap">
|
||||
<view class="card-wrap">
|
||||
<scroll-view scroll-y="true" class="card-list" @scrolltolower="getMemberCard()">
|
||||
<block v-if="memberCardData.list.length">
|
||||
<view class="card-item" :class="{ active: memberCardData.index == index }" v-for="(item, index) in memberCardData.list" :key="index" @click="selectMemberCard(item, index)">
|
||||
<view class="card-name">{{ item.goods_name }}</view>
|
||||
<view class="info">
|
||||
<view v-if="item.total_num > 0">可用{{ item.total_num - item.total_use_num }}次</view>
|
||||
<view v-else>不限次</view>
|
||||
<view v-if="item.end_time > 0">至{{ $util.timeFormat(item.end_time, 'Y/m/d') }}</view>
|
||||
<view v-else>长期有效</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-else class="empty">
|
||||
<image src="@/static/card/card_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无可用卡项</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="item-list">
|
||||
<view class="title">
|
||||
<view>可用服务/商品</view>
|
||||
<view v-if="memberCardData.currData.card_type == 'commoncard'">
|
||||
<text>以下服务/商品剩余可用</text>
|
||||
<text class="num">{{ memberCardData.currData.total_num - memberCardData.currData.total_use_num }}</text>
|
||||
<text>次</text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="item-wrap">
|
||||
<view class="uni-flex justify-between content" v-if="memberCardData.currData.item_list">
|
||||
<view class="card-item" :class="{
|
||||
active: memberCardData.selected['item_' + item.item_id],
|
||||
'not-select': !checkStatus(item) && !memberCardData.selected['item_' + item.item_id]
|
||||
}" @click="selectMemberCardItem(item, index)" v-for="(item, index) in memberCardData.currData.item_list">
|
||||
<view class="image">
|
||||
<image v-if="item.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
|
||||
<image v-else :src="$util.img(item.sku_image.split(',')[0], { size: 'small' })" @error="item.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
|
||||
</view>
|
||||
<view class="info">
|
||||
<view>
|
||||
<view class="name">
|
||||
<text class="tag">{{ item.is_virtual ? '服务' : '商品' }}</text>
|
||||
<text>{{ item.sku_name }}</text>
|
||||
</view>
|
||||
<block v-if="memberCardData.currData.card_type != 'commoncard'">
|
||||
<view class="num" v-if="item.num > 0">剩余可用{{ item.num - item.use_num }}次</view>
|
||||
<view class="num" v-else>不限次</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="action-wrap">
|
||||
<view class="price">
|
||||
<text class="util">¥</text>
|
||||
{{ item.price }}
|
||||
</view>
|
||||
<view class="number-wrap" v-if="memberCardData.selected['item_' + item.item_id]">
|
||||
<text class="iconfont iconjian" @click.stop="itemDec(memberCardData.selected['item_' + item.item_id])"></text>
|
||||
<input type="number" v-model="memberCardData.selected['item_' + item.item_id].input_num" />
|
||||
<text class="iconfont iconjia" @click.stop="itemInc(memberCardData.selected['item_' + item.item_id])"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-else>
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无相关数据</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="button-wrap">
|
||||
<button type="default" class="primary-btn" :disabled="memberCardData.itemIndex == -1" @click="selectGoods()">加入购物车</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniDataCheckbox from '@/components/uni-data-checkbox/uni-data-checkbox.vue';
|
||||
import UniPopup from "../uni-popup/uni-popup";
|
||||
import index from './index.js';
|
||||
|
||||
export default {
|
||||
name: 'nsMember',
|
||||
components: {
|
||||
UniPopup,
|
||||
uniDataCheckbox
|
||||
},
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
@@ -0,0 +1,398 @@
|
||||
<template>
|
||||
<view class="member-detail-wrap">
|
||||
<!-- 卡包 -->
|
||||
<uni-popup ref="cardListPop">
|
||||
<view class="pop-box card-list-pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">卡包</view>
|
||||
<view class="pop-header-close" @click="close('cardlist')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<dataTable url="/cardservice/storeapi/membercard/lists" :cols="card" ref="table" :option="option" :pagesize="pageSize">
|
||||
<template v-slot:action="dataTable">
|
||||
<text class="view-detail" @click="viewDetails(dataTable.value.card_id)">查看详情</text>
|
||||
</template>
|
||||
</dataTable>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<uni-popup ref="cardDetailPop">
|
||||
<view class="pop-box cardDetailPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">详情</view>
|
||||
<view class="pop-header-close" @click="$refs.cardDetailPop.close()">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pop-content">
|
||||
<view class="tab-head">
|
||||
<text v-for="(item, index) in tabObj.list" :key="index" :class="{ active: tabObj.index == item.value }" v-if="(item.value == 3 && card_detail.card_log && card_detail.card_log.length > 0) || item.value != 3" @click="tabObj.index = item.value">
|
||||
{{ item.name }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="tab-content">
|
||||
<view class="basic-info" v-if="tabObj.index == 0">
|
||||
<view class="basic-item using-hidden">卡项名称:{{ basicInfo.goods_name }}</view>
|
||||
<view class="basic-item">价格:{{ basicInfo.price }}</view>
|
||||
<view class="basic-item">
|
||||
卡类型:{{ (basicInfo.card_type == 'oncecard' && '限次卡') || (basicInfo.card_type == 'timecard' && '限时卡') || (basicInfo.card_type == 'commoncard' && '通用卡') }}
|
||||
</view>
|
||||
<view class="basic-item">总次数/已使用:{{ basicInfo.card_type == 'timecard' ? '不限' : basicInfo.total_num }}/{{ basicInfo.total_use_num }}</view>
|
||||
<view class="basic-item">获取时间:{{ $util.timeFormat(basicInfo.create_time) }}</view>
|
||||
<view class="basic-item">到期时间:{{ basicInfo.end_time > 0 ? $util.timeFormat(basicInfo.end_time) : '永久有效' }}</view>
|
||||
</view>
|
||||
<view class="other-information" v-if="tabObj.index == 1 && basicInfo && basicInfo.card_item">
|
||||
<view class="information-head">
|
||||
<text>商品名称</text>
|
||||
<text>总次数/已使用</text>
|
||||
<text>有效期</text>
|
||||
</view>
|
||||
<view class="information-body">
|
||||
<view class="information-tr" v-for="(item, index) in basicInfo.card_item" :key="index">
|
||||
<text class="using-hidden">{{ item.sku_name }}</text>
|
||||
<text>{{ item.card_type == 'timecard' ? '不限' : item.num }} /{{ item.use_num }}</text>
|
||||
<text>{{ item.end_time > 0 ? $util.timeFormat(item.end_time) : '永久有效' }}</text>
|
||||
</view>
|
||||
<view class="information-tr empty" v-if="!basicInfo.card_item.length">
|
||||
<view class="iconfont iconwushuju"></view>
|
||||
<view>暂无数据</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-info" v-if="tabObj.index == 2">
|
||||
<dataTable url="/cardservice/storeapi/membercard/records" :cols="cardInfo.card" ref="table" :option="cardInfo.option" :pagesize="cardInfo.pageSize"></dataTable>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getMemberCardDetail } from '@/api/member'
|
||||
import dataTable from '@/components/uni-data-table/uni-data-table.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
dataTable
|
||||
},
|
||||
props: {
|
||||
option: {}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageSize: 8,
|
||||
card: [{
|
||||
width: 20,
|
||||
title: '名称',
|
||||
align: 'left',
|
||||
field: 'goods_name'
|
||||
}, {
|
||||
width: 18,
|
||||
title: '卡号',
|
||||
align: 'center',
|
||||
field: 'card_code'
|
||||
}, {
|
||||
width: 8,
|
||||
title: '卡类型',
|
||||
align: 'left',
|
||||
templet: function (data) {
|
||||
if (data.card_type == 'oncecard') return '限次卡';
|
||||
if (data.card_type == 'timecard') return '限时卡';
|
||||
if (data.card_type == 'commoncard') return '通用卡';
|
||||
}
|
||||
}, {
|
||||
width: 12,
|
||||
title: '总次数/已使用',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
var totalNum = data.card_type == 'timecard' ? '不限' : data.total_num;
|
||||
return totalNum + '/' + data.total_use_num;
|
||||
}
|
||||
}, {
|
||||
width: 17,
|
||||
title: '创建时间',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
return this.$util.timeFormat(data.create_time);
|
||||
}
|
||||
}, {
|
||||
width: 17,
|
||||
title: '到期时间',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
if (data.end_time) return this.$util.timeFormat(data.end_time);
|
||||
else return '长期有效';
|
||||
}
|
||||
}, {
|
||||
width: 8,
|
||||
title: '操作',
|
||||
align: 'right',
|
||||
action: true
|
||||
}],
|
||||
tabObj: {
|
||||
list: [{
|
||||
value: 0,
|
||||
name: '基础信息'
|
||||
}, {
|
||||
value: 1,
|
||||
name: '商品/项目'
|
||||
}, {
|
||||
value: 2,
|
||||
name: '使用记录'
|
||||
}],
|
||||
index: 1
|
||||
},
|
||||
currCardId: 0,
|
||||
basicInfo: {},
|
||||
cardInfo: {
|
||||
card: [{
|
||||
width: 40,
|
||||
title: '卡项名称',
|
||||
align: 'left',
|
||||
field: 'sku_name'
|
||||
}, {
|
||||
width: 20,
|
||||
title: '使用次数',
|
||||
align: 'center',
|
||||
field: 'num'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '使用时间',
|
||||
align: 'right',
|
||||
templet: data => {
|
||||
return this.$util.timeFormat(data.create_time);
|
||||
}
|
||||
}, {
|
||||
width: 15,
|
||||
title: '操作',
|
||||
align: 'right',
|
||||
action: true
|
||||
}],
|
||||
option: {},
|
||||
pageSize: 6
|
||||
}
|
||||
};
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
open() {
|
||||
this.$refs.cardListPop.open();
|
||||
},
|
||||
close() {
|
||||
this.$refs.cardListPop.close();
|
||||
},
|
||||
viewDetails(card_id) {
|
||||
this.currCardId = card_id;
|
||||
this.$refs.cardDetailPop.open();
|
||||
this.getCardDetail();
|
||||
|
||||
this.cardInfo.option.member_id = this.globalMemberInfo.member_id;
|
||||
this.cardInfo.option.card_id = this.currCardId;
|
||||
},
|
||||
getCardDetail() {
|
||||
let data = {};
|
||||
data.member_id = this.globalMemberInfo.member_id;
|
||||
data.card_id = this.currCardId;
|
||||
getMemberCardDetail(data).then(res => {
|
||||
this.basicInfo = {};
|
||||
if (res.code >= 0) {
|
||||
this.basicInfo = res.data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pop-box {
|
||||
background: #ffffff;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
|
||||
.pop-header {
|
||||
padding: 0 0.15rem 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #f0f0f0;
|
||||
font-size: 0.14rem;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
border-radius: 0.02rem 0.2rem 0 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.pop-header-close {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 0.18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 1rem);
|
||||
overflow-y: scroll;
|
||||
padding: 0.1rem 0.2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
button {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-list-pop-box {
|
||||
width: 10rem;
|
||||
height: 5.7rem;
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 0.5rem);
|
||||
}
|
||||
|
||||
/deep/ .tpage {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.basic-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.basic {
|
||||
padding: 0.1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.cardDetailPop-box {
|
||||
width: 10rem;
|
||||
height: 5.7rem;
|
||||
|
||||
.tab-head {
|
||||
display: flex;
|
||||
background-color: #f7f8fa;
|
||||
|
||||
text {
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
text-align: center;
|
||||
padding: 0 0.35rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.active {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
overflow-y: inherit;
|
||||
|
||||
.basic-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
|
||||
.basic-item {
|
||||
flex-basis: 33%;
|
||||
height: 0.4rem;
|
||||
line-height: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.other-information {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-direction: column;
|
||||
padding-top: 0.2rem;
|
||||
|
||||
.information-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
background-color: #f7f8fa;
|
||||
|
||||
text {
|
||||
padding: 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex-basis: 35%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 35%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.information-tr {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
|
||||
text {
|
||||
padding: 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex-basis: 35%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 35%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 0.5rem;
|
||||
color: #909399;
|
||||
|
||||
.iconfont {
|
||||
font-size: 0.25rem;
|
||||
margin: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-top: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.view-detail {
|
||||
color: $primary-color;
|
||||
}</style>
|
||||
183
addon/cashier/source/os/components/ns-member-detail-popup/index.js
Executable file
183
addon/cashier/source/os/components/ns-member-detail-popup/index.js
Executable file
@@ -0,0 +1,183 @@
|
||||
import {
|
||||
getMemberInfoById,
|
||||
getMemberLevelList,
|
||||
getCouponTypeList,
|
||||
sendMemberCoupon,
|
||||
applyingMembershipCard
|
||||
} from '@/api/member'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pageSize: 8,
|
||||
sex: [{
|
||||
text: '未知',
|
||||
value: 0
|
||||
}, {
|
||||
text: '男',
|
||||
value: 1
|
||||
}, {
|
||||
text: '女',
|
||||
value: 2
|
||||
}],
|
||||
sendCoupon: {
|
||||
list: [],
|
||||
page: 1
|
||||
},
|
||||
memberLevelList: [],
|
||||
applyMember: {
|
||||
level_id: '',
|
||||
member_level: '',
|
||||
member_level_name: '',
|
||||
member_code: ''
|
||||
}
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getMemberLevel();
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.getMemberInfo(); // 保证数据实时性
|
||||
this.$refs.memberPop.open();
|
||||
},
|
||||
getMemberInfo() {
|
||||
getMemberInfoById(this.globalMemberInfo.member_id).then(res => {
|
||||
if (res.code >= 0) {
|
||||
res.data.birthday = res.data.birthday > 0 ? this.$util.timeFormat(res.data.birthday, 'Y-m-d') : '--';
|
||||
this.$store.commit('app/setGlobalMemberInfo', res.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
getMemberLevel() {
|
||||
this.memberLevelList = [];
|
||||
getMemberLevelList().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
for (let i in res.data) {
|
||||
this.memberLevelList.push({
|
||||
label: res.data[i]['level_name'],
|
||||
value: res.data[i]['level_id'].toString(),
|
||||
disabled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
selectMemberLevel(index, item) {
|
||||
if (index >= 0) {
|
||||
this.applyMember.level_id = item.value;
|
||||
this.applyMember.member_level = item.value;
|
||||
this.applyMember.member_level_name = item.label;
|
||||
} else {
|
||||
this.applyMember.level_id = '';
|
||||
this.applyMember.member_level = item.value;
|
||||
this.applyMember.member_level_name = item.label;
|
||||
}
|
||||
},
|
||||
// 客户操作
|
||||
memberAction(type) {
|
||||
switch (type) {
|
||||
case 'sendCoupon':
|
||||
this.getCouponList();
|
||||
this.$refs.sendCouponPop.open('center');
|
||||
break;
|
||||
case 'applyMember':
|
||||
this.$refs.applyMemberPop.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
popClose(type) {
|
||||
this.$refs[type + 'Pop'].close();
|
||||
},
|
||||
//获取发放优惠券列表
|
||||
getCouponList() {
|
||||
let data = {
|
||||
page: this.sendCoupon.page,
|
||||
page_size: 7
|
||||
};
|
||||
getCouponTypeList(data).then(res => {
|
||||
if (res.code >= 0) {
|
||||
if (this.sendCoupon.page == 1) this.sendCoupon.list = [];
|
||||
if (res.data.list && res.data.list.length) {
|
||||
res.data.list.forEach((item, index) => {
|
||||
if (item.validity_type == 0) item.validity_name = '失效日期:' + this.$util.timeFormat(item.end_time);
|
||||
else if (item.validity_type == 1) item.validity_name = '领取后,' + item.fixed_term + '天有效';
|
||||
else item.validity_name = '长期有效';
|
||||
item.num = 0;
|
||||
});
|
||||
}
|
||||
this.sendCoupon.list = this.sendCoupon.list.concat(res.data.list);
|
||||
if (res.data.page_count >= this.sendCoupon.page) this.sendCoupon.page++;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 发放数量
|
||||
dec: function (item) {
|
||||
if (item.num > 0) {
|
||||
item.num = item.num - 1;
|
||||
}
|
||||
},
|
||||
inc: function (item) {
|
||||
item.num = item.num + 1;
|
||||
},
|
||||
// 发放优惠券
|
||||
sendCouponFn() {
|
||||
if (!this.sendCoupon.list || !this.sendCoupon.list.length) return false;
|
||||
let data = {};
|
||||
data.member_id = this.globalMemberInfo.member_id;
|
||||
data.coupon_data = '';
|
||||
let couponDataArr = [];
|
||||
|
||||
this.sendCoupon.list.forEach((item, index) => {
|
||||
if (item.num > 0) {
|
||||
let obj = {};
|
||||
obj.coupon_type_id = item.coupon_type_id;
|
||||
obj.num = item.num;
|
||||
couponDataArr.push(obj);
|
||||
}
|
||||
});
|
||||
if (couponDataArr.length <= 0) return false;
|
||||
data.coupon_data = JSON.stringify(couponDataArr);
|
||||
sendMemberCoupon(data).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.sendCoupon.page = 1;
|
||||
this.sendCoupon.list = [];
|
||||
this.getMemberInfo();
|
||||
this.$refs.sendCouponPop.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
//打开会员卡项
|
||||
showMemberCard() {
|
||||
this.$refs.memberCardPopup.open();
|
||||
},
|
||||
// 办理会员卡
|
||||
saveApplyMember() {
|
||||
if (!this.applyMember.level_id) {
|
||||
this.$util.showToast({
|
||||
title: '请选择会员卡等级'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
applyingMembershipCard({
|
||||
member_id: this.globalMemberInfo.member_id,
|
||||
level_id: this.applyMember.level_id,
|
||||
member_code: this.applyMember.member_code
|
||||
}).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.getMemberInfo();
|
||||
this.popClose('applyMember');
|
||||
}
|
||||
});
|
||||
},
|
||||
headError(item) {
|
||||
item.headimg = this.defaultImg.head;
|
||||
}
|
||||
}
|
||||
}
|
||||
412
addon/cashier/source/os/components/ns-member-detail-popup/index.scss
Executable file
412
addon/cashier/source/os/components/ns-member-detail-popup/index.scss
Executable file
@@ -0,0 +1,412 @@
|
||||
.member-detail-wrap {
|
||||
width: 100%;
|
||||
border-left: 0;
|
||||
|
||||
.member-head {
|
||||
height: 0.66rem;
|
||||
line-height: 0.66rem;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.member-content {
|
||||
padding: 0.15rem;
|
||||
width: 100%;
|
||||
height: calc(100vh - 0.8rem);
|
||||
box-sizing: border-box;
|
||||
|
||||
.content-block {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.item-img {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
padding-left: 0.15rem;
|
||||
width: calc(100% - 0.7rem);
|
||||
box-sizing: border-box;
|
||||
|
||||
.item-title {
|
||||
width: 100%;
|
||||
font-size: 0.16rem;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.item-label {
|
||||
border: 0.01rem solid $primary-color;
|
||||
color: $primary-color;
|
||||
background-color: #fff;
|
||||
border-radius: 0.02rem;
|
||||
width: fit-content;
|
||||
padding: 0.01rem 0.05rem;
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
|
||||
.item-title-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 50%;
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
}
|
||||
|
||||
.info-list {
|
||||
margin-top: 0.1rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
.info-item {
|
||||
font-size: .14rem;
|
||||
padding-right: .2rem;
|
||||
width: 50%;
|
||||
box-sizing: border-box;
|
||||
height: .25rem;
|
||||
line-height: .25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-block.account {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.2rem;
|
||||
border-radius: 0.03rem;
|
||||
align-items: baseline;
|
||||
padding: .1rem 0;
|
||||
|
||||
.content-data-item {
|
||||
padding: .1rem 0;
|
||||
width: 33%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.data-item-title {
|
||||
}
|
||||
|
||||
.data-item-value {
|
||||
font-size: 0.26rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.content-block.assets {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.content-data-left {
|
||||
background-color: #ffffff;
|
||||
padding: 0.25rem 0;
|
||||
border-radius: 0.03rem;
|
||||
width: calc(50% - 0.075rem);
|
||||
margin-right: 0.15rem;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
height: 1rem;
|
||||
|
||||
.content-data-item {
|
||||
.data-item-title {
|
||||
}
|
||||
|
||||
.data-item-value {
|
||||
font-size: 0.26rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-block.action {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.content-data-item {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
width: calc(100% / 3);
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
padding: 0.15rem 0;
|
||||
border-radius: 0.03rem;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
margin-right: 0.15rem;
|
||||
cursor: pointer;
|
||||
|
||||
.data-item-icon {
|
||||
width: 0.55rem;
|
||||
height: 0.55rem;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.data-item-value {
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pop弹框
|
||||
.pop-box {
|
||||
background: #ffffff;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
|
||||
.pop-header {
|
||||
padding: 0 0.15rem 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #f0f0f0;
|
||||
font-size: 0.14rem;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
border-radius: 0.02rem 0.2rem 0 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.pop-header-text {
|
||||
}
|
||||
|
||||
.pop-header-close {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 0.18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 1rem);
|
||||
overflow-y: scroll;
|
||||
padding: 0.1rem 0.2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
button {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//表单
|
||||
.form-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 0.1rem;
|
||||
display: flex;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
width: 1.2rem;
|
||||
text-align: right;
|
||||
padding-right: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
|
||||
.required {
|
||||
color: red;
|
||||
margin-right: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-inline {
|
||||
width: 2.4rem;
|
||||
line-height: 0.32rem;
|
||||
margin-right: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.form-input {
|
||||
border-width: 0.01rem;
|
||||
border-style: solid;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-radius: 0.02rem;
|
||||
padding-left: 0.1rem;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
font-size: 0.14rem;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.word-aux {
|
||||
color: #999;
|
||||
font-size: 0.12rem;
|
||||
line-height: 1.5;
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.member-info-wrap {
|
||||
width: 5.5rem;
|
||||
height: 5.2rem;
|
||||
}
|
||||
|
||||
.applyMemberPop-box {
|
||||
width: 6rem;
|
||||
height: 3.38rem;
|
||||
|
||||
.pop-content {
|
||||
overflow: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.sendCoupon-box {
|
||||
width: 9rem;
|
||||
height: 5.06rem;
|
||||
|
||||
.sendCoupon-content {
|
||||
padding: 0.1rem 0.2rem;
|
||||
|
||||
.coupon-table-head {
|
||||
display: flex;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
.coupon-table-body {
|
||||
height: 3.2rem;
|
||||
|
||||
.coupon-table-tr {
|
||||
display: flex;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
}
|
||||
|
||||
.table-input {
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
padding: 0 0.1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.item-num {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 0.1rem;
|
||||
|
||||
.num-dec {
|
||||
width: 0.6rem;
|
||||
height: 0.25rem;
|
||||
background: #e6e6e6;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-right: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.num-inc {
|
||||
width: 0.6rem;
|
||||
height: 0.25rem;
|
||||
background: $primary-color;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-left: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-table-td:nth-child(4) {
|
||||
padding: 0 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-table-td,
|
||||
.coupon-table-th {
|
||||
padding: 0 0.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 0.5rem;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 20%;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
justify-content: flex-end;
|
||||
flex-basis: 20%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
margin-top: 0.12rem;
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
color: #909399;
|
||||
|
||||
.iconfont {
|
||||
font-size: 0.25rem;
|
||||
margin: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<view class="member-detail-wrap">
|
||||
|
||||
<uni-popup ref="memberPop">
|
||||
<view class="pop-box member-info-wrap" v-if="globalMemberInfo">
|
||||
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">会员详情</view>
|
||||
<view class="pop-header-close" @click="popClose('member')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="member-content">
|
||||
<view class="content-block">
|
||||
<view class="item-img">
|
||||
<image mode="aspectFill" v-if="globalMemberInfo.headimg" :src="$util.img(globalMemberInfo.headimg)" @error="headError(globalMemberInfo)"/>
|
||||
<image mode="aspectFill" v-else :src="$util.img(defaultImg.head)"/>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-title">
|
||||
<view class="item-title-text">{{ globalMemberInfo.nickname ? globalMemberInfo.nickname : '' }}</view>
|
||||
<view class="item-label" v-if="globalMemberInfo.member_level && globalMemberInfo.member_level_name">{{ globalMemberInfo.member_level_name }}</view>
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">手机:{{ globalMemberInfo.mobile ? globalMemberInfo.mobile : '' }}</view>
|
||||
<view class="info-item" v-if="globalMemberInfo.sex == 0">性别:未知</view>
|
||||
<view class="info-item" v-if="globalMemberInfo.sex == 1">性别:男</view>
|
||||
<view class="info-item" v-if="globalMemberInfo.sex == 2">性别:女</view>
|
||||
<view class="info-item">生日:{{ globalMemberInfo.birthday }}</view>
|
||||
<view class="info-item" v-if="globalMemberInfo.member_time">成为会员:{{ $util.timeFormat(globalMemberInfo.member_time,'Y-m-d') }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-block account">
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">积分</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.point ? parseInt(globalMemberInfo.point) : '0' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">储值余额(元)</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.balance ? globalMemberInfo.balance : '0.00' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">现金余额(元)</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.balance_money ? globalMemberInfo.balance_money : '0.00' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">成长值</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.growth ? globalMemberInfo.growth : '0' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">优惠券(张)</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.coupon_num ? globalMemberInfo.coupon_num : '0' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">卡包</view>
|
||||
<view class="data-item-value">{{ globalMemberInfo.card_num ? globalMemberInfo.card_num : '0' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-block action">
|
||||
<view class="content-data-item" @click="memberAction('sendCoupon')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-coupon.png" />
|
||||
</view>
|
||||
<view class="data-item-value">送优惠券</view>
|
||||
</view>
|
||||
<view class="content-data-item" v-if="isShowMemberCard" @click="showMemberCard">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-balance.png" />
|
||||
</view>
|
||||
<view class="data-item-value">会员卡项</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('applyMember')" v-if="!globalMemberInfo.is_member">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-apply.png" />
|
||||
</view>
|
||||
<view class="data-item-value">办理会员</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 发放优惠券 -->
|
||||
<uni-popup ref="sendCouponPop">
|
||||
<view class="pop-box sendCoupon-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">送优惠券</view>
|
||||
<view class="pop-header-close" @click="popClose('sendCoupon')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="common-scrollbar sendCoupon-content">
|
||||
<view class="coupon-table-head">
|
||||
<view class="coupon-table-th">优惠券名称</view>
|
||||
<view class="coupon-table-th">金额</view>
|
||||
<view class="coupon-table-th">有效期</view>
|
||||
<view class="coupon-table-th">发放数量</view>
|
||||
</view>
|
||||
<scroll-view class="coupon-table-body" @scrolltolower="getCouponList()" scroll-y="true">
|
||||
<view class="coupon-table-tr" v-for="(item, index) in sendCoupon.list" :key="index">
|
||||
<view class="coupon-table-td">{{ item.coupon_name }}</view>
|
||||
<view class="coupon-table-td">{{ item.money }}</view>
|
||||
<view class="coupon-table-td">{{ item.validity_name }}</view>
|
||||
<view class="coupon-table-td">
|
||||
<view class="item-num">
|
||||
<view class="num-dec" v-on:click="dec(item)">-</view>
|
||||
<input class="table-input" type="text" v-model="item.num" />
|
||||
<view class="num-inc" v-on:click="inc(item)">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-if="!sendCoupon.list.length">
|
||||
<view class="iconfont iconwushuju"></view>
|
||||
<view>暂无数据</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="pop-bottom">
|
||||
<button v-if="sendCoupon.list.length" class="primary-btn" @click="sendCouponFn">发放优惠券</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 办理会员 -->
|
||||
<uni-popup ref="applyMemberPop">
|
||||
<view class="pop-box applyMemberPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">办理会员</view>
|
||||
<view class="pop-header-close" @click="popClose('applyMember')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="common-scrollbar pop-content">
|
||||
<view class="form-content">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员等级:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<select-lay :zindex="10" :value="applyMember.level_id" name="names" placeholder="请选择会员等级" :options="memberLevelList" @selectitem="selectMemberLevel"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员卡号:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" type="text" placeholder="请输入会员卡号" v-model="applyMember.member_code" />
|
||||
<view class="word-aux">会员卡号为会员唯一编号,若不设置将会自动生成</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="saveApplyMember">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 会员卡项弹出框 -->
|
||||
<ns-member-card-popup v-if="isShowMemberCard" ref="memberCardPopup"/>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataTable from '@/components/uni-data-table/uni-data-table.vue';
|
||||
import index from './index.js';
|
||||
import UniPopup from "../uni-popup/uni-popup";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
UniPopup,
|
||||
dataTable
|
||||
},
|
||||
props:{
|
||||
// 是否展示会员卡项
|
||||
isShowMemberCard:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
},
|
||||
mixins: [index],
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
<style>
|
||||
.member-info-pop >>> .pop-content, .member-info-pop >>> .uni-scroll-view{
|
||||
overflow: inherit !important;
|
||||
}
|
||||
</style>
|
||||
502
addon/cashier/source/os/components/ns-member-detail/index.js
Executable file
502
addon/cashier/source/os/components/ns-member-detail/index.js
Executable file
@@ -0,0 +1,502 @@
|
||||
import {
|
||||
getMemberInfoById,
|
||||
getMemberLevelList,
|
||||
getCouponTypeList,
|
||||
sendMemberCoupon,
|
||||
editMember,
|
||||
modifyMemberPoint,
|
||||
modifyMemberBalance,
|
||||
modifyMemberGrowth,
|
||||
applyingMembershipCard
|
||||
} from '@/api/member'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
memberId: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageSize: 8,
|
||||
endTime: '',
|
||||
memberInfo: null,
|
||||
sex: [{
|
||||
text: '未知',
|
||||
value: 0
|
||||
}, {
|
||||
text: '男',
|
||||
value: 1
|
||||
}, {
|
||||
text: '女',
|
||||
value: 2
|
||||
}],
|
||||
pointData: {
|
||||
num: 0,
|
||||
desc: ''
|
||||
},
|
||||
growthData: {
|
||||
num: 0,
|
||||
desc: ''
|
||||
},
|
||||
balanceData: {
|
||||
num: 0,
|
||||
desc: ''
|
||||
},
|
||||
option: {},
|
||||
sendCoupon: {
|
||||
list: [],
|
||||
page: 1
|
||||
},
|
||||
memberLevelList: [],
|
||||
applyMember: {
|
||||
level_id: '',
|
||||
member_level_name: '',
|
||||
member_code: ''
|
||||
},
|
||||
couponCols: [{
|
||||
width: 15,
|
||||
title: '优惠券名称',
|
||||
align: 'left',
|
||||
field: 'coupon_name'
|
||||
}, {
|
||||
width: 7,
|
||||
title: '类型',
|
||||
align: 'left',
|
||||
templet: function (data) {
|
||||
if (data.type == 'reward') return '满减';
|
||||
if (data.type == 'discount') return '折扣';
|
||||
}
|
||||
}, {
|
||||
width: 18,
|
||||
title: '优惠金额',
|
||||
align: 'left',
|
||||
templet: function (data) {
|
||||
if (data.type == 'reward') {
|
||||
var html = `满${data.at_least}元减${data.money}`;
|
||||
return `<view title="${html}">${html}</view>`;
|
||||
}
|
||||
if (data.type == 'discount') {
|
||||
var text = '满' + data.at_least + '元打' + data.discount + '折';
|
||||
if (data.discount_limit) text += '(最多抵扣' + data.discount_limit + '元)';
|
||||
return '<view title="' + text + '">' + text + '</view>';
|
||||
}
|
||||
}
|
||||
}, {
|
||||
width: 17,
|
||||
title: '有效期',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
if (data.end_time) return this.$util.timeFormat(data.end_time);
|
||||
else return '长期有效';
|
||||
}
|
||||
}, {
|
||||
width: 10,
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
return: data => {
|
||||
if (data.state == 1) return '未使用';
|
||||
if (data.state == 2) return '已使用';
|
||||
if (data.state == 3) return '已过期';
|
||||
}
|
||||
},{
|
||||
title: '适用场景',
|
||||
field: 'use_channel_name',
|
||||
width: 15,
|
||||
align: 'left',
|
||||
}, {
|
||||
width: 18,
|
||||
title: '领取时间',
|
||||
align: 'right',
|
||||
templet: data => {
|
||||
return this.$util.timeFormat(data.fetch_time);
|
||||
}
|
||||
}],
|
||||
pointCols: [{
|
||||
width: 20,
|
||||
title: '积分',
|
||||
align: 'left',
|
||||
field: 'account_data'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '发生方式',
|
||||
align: 'left',
|
||||
field: 'type_name'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '发生时间',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
var html = this.$util.timeFormat(data.create_time);
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
width: 30,
|
||||
title: '备注',
|
||||
align: 'left',
|
||||
field: 'remark'
|
||||
}],
|
||||
balanceCols: [{
|
||||
width: 10,
|
||||
title: '账户类型',
|
||||
align: 'left',
|
||||
field: 'account_type_name'
|
||||
}, {
|
||||
width: 15,
|
||||
title: '余额',
|
||||
align: 'left',
|
||||
field: 'account_data'
|
||||
}, {
|
||||
width: 20,
|
||||
title: '发生方式',
|
||||
align: 'left',
|
||||
field: 'type_name'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '发生时间',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
var html = this.$util.timeFormat(data.create_time);
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
width: 30,
|
||||
title: '备注',
|
||||
align: 'left',
|
||||
field: 'remark'
|
||||
}],
|
||||
growthCols: [{
|
||||
width: 20,
|
||||
title: '成长值',
|
||||
align: 'left',
|
||||
field: 'account_data'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '发生方式',
|
||||
align: 'left',
|
||||
field: 'type_name'
|
||||
}, {
|
||||
width: 25,
|
||||
title: '发生时间',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
var html = this.$util.timeFormat(data.create_time);
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
width: 30,
|
||||
title: '备注',
|
||||
align: 'left',
|
||||
field: 'remark'
|
||||
}],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getMemberInfo();
|
||||
this.getMemberLevel();
|
||||
let date = new Date();
|
||||
var y = date.getFullYear();
|
||||
var m = date.getMonth() + 1;
|
||||
var d = date.getDate();
|
||||
this.endTime = y + '-' + m + '-' + d;
|
||||
},
|
||||
watch: {
|
||||
memberId: function () {
|
||||
this.getMemberInfo();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkAdmin() {
|
||||
if (this.userInfo && this.userInfo.is_admin == 0) {
|
||||
// 检查当前账号是否有修改手机号的权限
|
||||
var isAgree = false;
|
||||
this.userInfo.user_group_list.forEach((item) => {
|
||||
if (item.store_id == this.globalStoreInfo.store_id) {
|
||||
if (item.menu_array.indexOf('member_edit') != -1) {
|
||||
isAgree = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (isAgree) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
getMemberInfo() {
|
||||
getMemberInfoById(this.memberId).then(res => {
|
||||
if (res.code >= 0) {
|
||||
res.data.birthday = res.data.birthday > 0 ? this.$util.timeFormat(res.data.birthday, 'Y-m-d') : '';
|
||||
this.memberInfo = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
getMemberLevel() {
|
||||
this.memberLevelList = [];
|
||||
getMemberLevelList().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
for (let i in res.data) {
|
||||
this.memberLevelList.push({
|
||||
label: res.data[i]['level_name'],
|
||||
value: res.data[i]['level_id'].toString(),
|
||||
disabled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
selectMemberLevel(index, item) {
|
||||
if (index >= 0) {
|
||||
this.applyMember.level_id = item.value;
|
||||
this.applyMember.member_level_name = item.label;
|
||||
this.memberInfo.member_level = item.value;
|
||||
} else {
|
||||
this.applyMember.level_id = '';
|
||||
this.applyMember.member_level_name = '';
|
||||
this.memberInfo.member_level = '';
|
||||
}
|
||||
},
|
||||
// 客户操作
|
||||
memberAction(type) {
|
||||
switch (type) {
|
||||
case 'memberInfo':
|
||||
this.$refs.memberInfoPop.open('center');
|
||||
break;
|
||||
case 'point':
|
||||
this.$refs.pointPop.open('center');
|
||||
break;
|
||||
case 'balance':
|
||||
this.$store.commit('app/setGlobalMemberInfo', this.memberInfo);
|
||||
this.$util.redirectTo('/pages/recharge/index');
|
||||
break;
|
||||
case 'sendCoupon':
|
||||
this.getCouponList();
|
||||
this.$refs.sendCouponPop.open('center');
|
||||
break;
|
||||
case 'growth':
|
||||
this.$refs.growthPop.open('center');
|
||||
break;
|
||||
case 'couponList':
|
||||
this.option = {
|
||||
member_id: this.memberId
|
||||
};
|
||||
this.$refs.couponListPop.open('center');
|
||||
break;
|
||||
case 'cardList':
|
||||
this.option = {
|
||||
member_id: this.memberId,
|
||||
status:1,
|
||||
};
|
||||
this.$refs.memberCardRecord.open('center');
|
||||
break;
|
||||
case 'pointList':
|
||||
// 积分列表
|
||||
this.option = {
|
||||
member_id: this.memberId,
|
||||
account_type: 'point'
|
||||
};
|
||||
this.$refs.pointListPop.open();
|
||||
break;
|
||||
case 'balanceList':
|
||||
// 余额列表
|
||||
this.option = {
|
||||
member_id: this.memberId,
|
||||
account_type: 'balance'
|
||||
};
|
||||
this.$refs.balanceListPop.open();
|
||||
break;
|
||||
case 'growthList':
|
||||
// 成长值列表
|
||||
this.option = {
|
||||
member_id: this.memberId,
|
||||
account_type: 'growth'
|
||||
};
|
||||
this.$refs.growthListPop.open();
|
||||
break;
|
||||
case 'applyMember':
|
||||
this.$refs.applyMemberPop.open();
|
||||
break;
|
||||
}
|
||||
},
|
||||
popClose(type) {
|
||||
this.$refs[type + 'Pop'].close();
|
||||
},
|
||||
//获取发放优惠券列表
|
||||
getCouponList() {
|
||||
let data = {
|
||||
page: this.sendCoupon.page,
|
||||
page_size: 7
|
||||
};
|
||||
getCouponTypeList(data).then(res => {
|
||||
if (res.code >= 0) {
|
||||
if (this.sendCoupon.page == 1) this.sendCoupon.list = [];
|
||||
if (res.data.list && res.data.list.length) {
|
||||
res.data.list.forEach((item, index) => {
|
||||
if (item.validity_type == 0) item.validity_name = '失效日期:' + this.$util.timeFormat(item.end_time);
|
||||
else if (item.validity_type == 1) item.validity_name = '领取后,' + item.fixed_term + '天有效';
|
||||
else item.validity_name = '长期有效';
|
||||
item.num = 0;
|
||||
});
|
||||
}
|
||||
this.sendCoupon.list = this.sendCoupon.list.concat(res.data.list);
|
||||
if (res.data.page_count >= this.sendCoupon.page) this.sendCoupon.page++;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 发放数量
|
||||
dec: function (item) {
|
||||
if (item.num > 0) {
|
||||
item.num = item.num - 1;
|
||||
}
|
||||
},
|
||||
inc: function (item) {
|
||||
item.num = item.num + 1;
|
||||
},
|
||||
// 发放优惠券
|
||||
sendCouponFn() {
|
||||
if (!this.sendCoupon.list || !this.sendCoupon.list.length) return false;
|
||||
let data = {};
|
||||
data.member_id = this.memberInfo.member_id;
|
||||
data.coupon_data = '';
|
||||
let couponDataArr = [];
|
||||
|
||||
this.sendCoupon.list.forEach((item, index) => {
|
||||
if (item.num > 0) {
|
||||
let obj = {};
|
||||
obj.coupon_type_id = item.coupon_type_id;
|
||||
obj.num = item.num;
|
||||
couponDataArr.push(obj);
|
||||
}
|
||||
});
|
||||
if (couponDataArr.length <= 0) return false;
|
||||
data.coupon_data = JSON.stringify(couponDataArr);
|
||||
sendMemberCoupon(data).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.sendCoupon.page = 1;
|
||||
this.sendCoupon.list = [];
|
||||
this.getMemberInfo();
|
||||
this.$refs.sendCouponPop.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
//修改客户信息
|
||||
saveMemberInfo() {
|
||||
let data = {
|
||||
nickname: this.memberInfo.nickname,
|
||||
sex: this.memberInfo.sex,
|
||||
birthday: this.memberInfo.birthday,
|
||||
member_id: this.memberInfo.member_id,
|
||||
level_id: this.memberInfo.member_level
|
||||
};
|
||||
if (this.checkAdmin()) {
|
||||
data.mobile = this.memberInfo.mobile;
|
||||
}
|
||||
editMember(data).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.getMemberInfo();
|
||||
this.popClose('memberInfo');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 调整积分
|
||||
savePoint() {
|
||||
if (parseInt(this.pointData.num) < 0 && parseInt(this.memberInfo.point) < parseInt(this.pointData.num * -1)) {
|
||||
this.$util.showToast({
|
||||
title: '调整数额与当前积分之和不能小于0'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
modifyMemberPoint({
|
||||
member_id: this.memberInfo.member_id,
|
||||
adjust_num: this.pointData.num,
|
||||
remark: this.pointData.desc
|
||||
}).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.pointData.num = 0;
|
||||
this.pointData.desc = '';
|
||||
this.getMemberInfo();
|
||||
this.popClose('point');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 调整余额
|
||||
saveBalance() {
|
||||
modifyMemberBalance({
|
||||
member_id: this.memberInfo.member_id,
|
||||
adjust_num: this.balanceData.num,
|
||||
remark: this.balanceData.desc
|
||||
}).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.balanceData.num = 0;
|
||||
this.balanceData.desc = '';
|
||||
this.getMemberInfo();
|
||||
this.popClose('balance');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 调整成长值
|
||||
saveGrowth() {
|
||||
if (parseInt(this.growthData.num) < 0 && parseInt(this.memberInfo.growth) < parseInt(this.growthData.num * -1)) {
|
||||
this.$util.showToast({
|
||||
title: '调整数额与当前成长值之和不能小于0'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
modifyMemberGrowth({
|
||||
member_id: this.memberInfo.member_id,
|
||||
adjust_num: this.growthData.num,
|
||||
remark: this.growthData.desc
|
||||
}).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.growthData.num = 0;
|
||||
this.growthData.desc = '';
|
||||
this.getMemberInfo();
|
||||
this.popClose('growth');
|
||||
}
|
||||
});
|
||||
},
|
||||
// 办理会员卡
|
||||
saveApplyMember() {
|
||||
if (!this.applyMember.level_id) {
|
||||
this.$util.showToast({
|
||||
title: '请选择会员卡等级'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
applyingMembershipCard({
|
||||
member_id: this.memberInfo.member_id,
|
||||
level_id: this.applyMember.level_id,
|
||||
member_code: this.applyMember.member_code
|
||||
}).then(res => {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
if (res.code >= 0) {
|
||||
this.$root.page = 1;
|
||||
this.$root.search_text = 1;
|
||||
this.$root.getMemberListFn();
|
||||
this.popClose('applyMember');
|
||||
}
|
||||
});
|
||||
},
|
||||
headError(item) {
|
||||
item.headimg = this.defaultImg.head;
|
||||
}
|
||||
}
|
||||
}
|
||||
453
addon/cashier/source/os/components/ns-member-detail/index.scss
Executable file
453
addon/cashier/source/os/components/ns-member-detail/index.scss
Executable file
@@ -0,0 +1,453 @@
|
||||
.member-detail-wrap {
|
||||
width: 100%;
|
||||
border-left: 0;
|
||||
|
||||
.member-head {
|
||||
height: 0.66rem;
|
||||
line-height: 0.66rem;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.member-content {
|
||||
padding: 0.15rem;
|
||||
width: 100%;
|
||||
height: calc(100vh - 0.8rem);
|
||||
box-sizing: border-box;
|
||||
|
||||
.content-block {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.item-img {
|
||||
width: 0.7rem;
|
||||
height: 0.7rem;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-content {
|
||||
padding-left: 0.15rem;
|
||||
width: calc(100% - 0.7rem);
|
||||
box-sizing: border-box;
|
||||
|
||||
.item-title {
|
||||
width: 100%;
|
||||
font-size: 0.16rem;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
|
||||
.item-label {
|
||||
border: 0.01rem solid $primary-color;
|
||||
color: $primary-color;
|
||||
background-color: #fff;
|
||||
border-radius: 0.02rem;
|
||||
width: fit-content;
|
||||
padding: 0.01rem 0.05rem;
|
||||
margin-left: 0.15rem;
|
||||
}
|
||||
|
||||
.item-title-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 50%;
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
}
|
||||
|
||||
.info-list {
|
||||
margin-top: 0.15rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.info-item {
|
||||
font-size: 0.14rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-block.account {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
background-color: #ffffff;
|
||||
padding: 0.25rem 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 0.2rem;
|
||||
border-radius: 0.03rem;
|
||||
align-items: baseline;
|
||||
|
||||
.content-data-item {
|
||||
.data-item-title {}
|
||||
|
||||
.data-item-value {
|
||||
font-size: 0.26rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.data-item-action {
|
||||
margin-top: 0.1rem;
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
float: left;
|
||||
|
||||
&:nth-child(2n) {
|
||||
margin-left: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-block.assets {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.content-data-left {
|
||||
background-color: #ffffff;
|
||||
padding: 0.25rem 0;
|
||||
border-radius: 0.03rem;
|
||||
width: calc(50% - 0.075rem);
|
||||
margin-right: 0.15rem;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
height: 1rem;
|
||||
|
||||
.content-data-item {
|
||||
.data-item-title {}
|
||||
|
||||
.data-item-value {
|
||||
font-size: 0.26rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.data-item-action {
|
||||
margin-top: 0.15rem;
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content-block.action {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.content-data-item {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
width: calc(100% / 6);
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
padding: 0.15rem 0;
|
||||
border-radius: 0.03rem;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
margin-right: 0.15rem;
|
||||
cursor: pointer;
|
||||
|
||||
.data-item-icon {
|
||||
width: 0.55rem;
|
||||
height: 0.55rem;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.data-item-value {
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pop弹框
|
||||
.pop-box {
|
||||
background: #ffffff;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
|
||||
.pop-header {
|
||||
padding: 0 0.15rem 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #f0f0f0;
|
||||
font-size: 0.14rem;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
border-radius: 0.02rem 0.2rem 0 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.pop-header-close {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 0.18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 1.05rem);
|
||||
overflow-y: auto;
|
||||
padding: 0.1rem 0.2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0.2rem;
|
||||
button {
|
||||
width: 100%;
|
||||
line-height: 0.35rem;
|
||||
height: 0.35rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//表单
|
||||
.form-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 0.1rem;
|
||||
display: flex;
|
||||
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
width: 1.2rem;
|
||||
text-align: right;
|
||||
padding-right: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
|
||||
.required {
|
||||
color: red;
|
||||
margin-right: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-inline {
|
||||
width: 2.5rem;
|
||||
line-height: 0.32rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.form-input {
|
||||
border-width: 0.01rem;
|
||||
border-style: solid;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-radius: 0.02rem;
|
||||
padding-left: 0.1rem;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
font-size: 0.14rem;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
border-width: 0.01rem;
|
||||
border-style: solid;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-radius: 0.02rem;
|
||||
padding-left: 0.1rem;
|
||||
line-height: 0.32rem;
|
||||
font-size: 0.14rem;
|
||||
border-color: #e6e6e6;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.word-aux {
|
||||
color: #999;
|
||||
font-size: 0.12rem;
|
||||
line-height: 1.5;
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.memberInfo-box {
|
||||
width: 5.2rem;
|
||||
height: 4.31rem;
|
||||
}
|
||||
|
||||
.pointPop-box {
|
||||
width: 4.2rem;
|
||||
height: 3.94rem;
|
||||
}
|
||||
|
||||
.balancePop-box {
|
||||
width: 4.2rem;
|
||||
height: 4.2rem;
|
||||
}
|
||||
|
||||
.coupon-list-pop-box {
|
||||
width: 10rem;
|
||||
height: 5.7rem;
|
||||
|
||||
.pop-content {
|
||||
height: calc(100% - 0.5rem);
|
||||
}
|
||||
|
||||
/deep/ .tpage {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.applyMemberPop-box {
|
||||
width: 4.2rem;
|
||||
height: 3.38rem;
|
||||
|
||||
.pop-content {
|
||||
overflow: initial;
|
||||
}
|
||||
}
|
||||
|
||||
.sendCoupon-box {
|
||||
width: 9rem;
|
||||
height: 5.06rem;
|
||||
|
||||
.sendCoupon-content {
|
||||
padding: 0.1rem 0.2rem;
|
||||
|
||||
.coupon-table-head {
|
||||
display: flex;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
.coupon-table-body {
|
||||
height: 3.2rem;
|
||||
|
||||
.coupon-table-tr {
|
||||
display: flex;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
}
|
||||
|
||||
.table-input {
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
padding: 0 0.1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.item-num {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 0.1rem;
|
||||
|
||||
.num-dec {
|
||||
width: 0.6rem;
|
||||
height: 0.25rem;
|
||||
background: #e6e6e6;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-right: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
.num-inc {
|
||||
width: 0.6rem;
|
||||
height: 0.25rem;
|
||||
background: $primary-color;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
border-radius: 30%;
|
||||
text-align: center;
|
||||
line-height: 0.23rem;
|
||||
font-size: 0.25rem;
|
||||
margin-left: 0.1rem;
|
||||
cursor: pointer;
|
||||
transition: 0.3s;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-table-td:nth-child(4) {
|
||||
padding: 0 0.05rem;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-table-td,
|
||||
.coupon-table-th {
|
||||
padding: 0 0.1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 0.5rem;
|
||||
|
||||
&:nth-child(1) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
flex-basis: 20%;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
flex-basis: 30%;
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
justify-content: flex-end;
|
||||
flex-basis: 20%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pop-bottom {
|
||||
margin-top: 0.12rem;
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
color: #909399;
|
||||
|
||||
.iconfont {
|
||||
font-size: 0.25rem;
|
||||
margin: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
500
addon/cashier/source/os/components/ns-member-detail/ns-member-detail.vue
Executable file
500
addon/cashier/source/os/components/ns-member-detail/ns-member-detail.vue
Executable file
@@ -0,0 +1,500 @@
|
||||
<template>
|
||||
<view class="member-detail-wrap">
|
||||
<view class="member-head flex items-center justify-between">
|
||||
<text>会员详情</text>
|
||||
<text class="iconfont iconguanbi1 cursor-pointer" @click="$emit('close')"></text>
|
||||
</view>
|
||||
<view class="member-content">
|
||||
<view class="content-block">
|
||||
<view class="item-img">
|
||||
<image mode="aspectFill" v-if="memberInfo && memberInfo.headimg" :src="$util.img(memberInfo.headimg)" @error="headError(memberInfo)"/>
|
||||
<image mode="aspectFill" v-else :src="$util.img(defaultImg.head)"/>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-title">
|
||||
<view class="item-title-text">{{ memberInfo && memberInfo.nickname ? memberInfo.nickname : '' }}</view>
|
||||
<view class="item-label" v-if="memberInfo && memberInfo.member_level && memberInfo.member_level_name">{{ memberInfo.member_level_name }}</view>
|
||||
</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item">手机:{{ memberInfo && memberInfo.mobile ? memberInfo.mobile : '' }}</view>
|
||||
<view class="info-item" v-if="memberInfo && memberInfo.sex == 0">性别:未知</view>
|
||||
<view class="info-item" v-if="memberInfo && memberInfo.sex == 1">性别:男</view>
|
||||
<view class="info-item" v-if="memberInfo && memberInfo.sex == 2">性别:女</view>
|
||||
<view class="info-item">生日:{{ memberInfo && memberInfo.birthday ? memberInfo.birthday : '' }}</view>
|
||||
<view class="info-item" v-if="memberInfo && memberInfo.member_time">成为会员:{{ $util.timeFormat(memberInfo.member_time) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content-block account">
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">积分</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.point ? parseInt(memberInfo.point) : '0' }}</view>
|
||||
<view class="data-item-action" @click="memberAction('pointList')">查看</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">储值余额(元)</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.balance ? memberInfo.balance : '0.00' }}</view>
|
||||
<view class="data-item-action" @click="memberAction('balanceList')">查看</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">现金余额(元)</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.balance_money ? memberInfo.balance_money : '0.00' }}</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">成长值</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.growth ? memberInfo.growth : '0' }}</view>
|
||||
<view class="data-item-action" @click="memberAction('growthList')">查看</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">优惠券(张)</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.coupon_num ? memberInfo.coupon_num : '0' }}</view>
|
||||
<view class="data-item-action" @click="memberAction('couponList')">查看</view>
|
||||
</view>
|
||||
<view class="content-data-item">
|
||||
<view class="data-item-title">卡包</view>
|
||||
<view class="data-item-value">{{ memberInfo && memberInfo.card_num ? memberInfo.card_num : '0' }}
|
||||
</view>
|
||||
<view class="data-item-action" @click="memberAction('cardList')">查看</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-block action">
|
||||
<view class="content-data-item" @click="memberAction('memberInfo')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-info.png" />
|
||||
</view>
|
||||
<view class="data-item-value">会员信息</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('point')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-point.png" />
|
||||
</view>
|
||||
<view class="data-item-value">积分调整</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('balance')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-balance.png" />
|
||||
</view>
|
||||
<view class="data-item-value">余额充值</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('sendCoupon')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-coupon.png" />
|
||||
</view>
|
||||
<view class="data-item-value">送优惠券</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('growth')">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-growth.png" />
|
||||
</view>
|
||||
<view class="data-item-value">成长值调整</view>
|
||||
</view>
|
||||
<view class="content-data-item" @click="memberAction('applyMember')" v-if="memberInfo && !memberInfo.is_member">
|
||||
<view class="data-item-icon">
|
||||
<image mode="aspectFit" src="@/static/member/icon-member-apply.png" />
|
||||
</view>
|
||||
<view class="data-item-value">办理会员</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 会员详情 -->
|
||||
<uni-popup ref="memberInfoPop">
|
||||
<view class="pop-box memberInfo-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">会员详情</view>
|
||||
<view class="pop-header-close" @click="popClose('memberInfo')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<view class="form-content" v-if="memberInfo">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
昵称:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" placeholder="请输入会员昵称" v-model="memberInfo.nickname" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
手机号:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" placeholder="请输入手机号" v-model="memberInfo.mobile" maxlength="11" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员等级:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<select-lay :zindex="10" :value="memberInfo.member_level" name="names" placeholder="请选择会员等级" :options="memberLevelList" @selectitem="selectMemberLevel"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
性别:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<uni-data-checkbox v-model="memberInfo.sex" :localdata="sex"></uni-data-checkbox>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
生日:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<uni-datetime-picker :end="endTime" v-model="memberInfo.birthday" type="date" :clearIcon="false" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
注册时间:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
{{ memberInfo && memberInfo.reg_time ? $util.timeFormat(memberInfo.reg_time) : '--' }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
最后访问时间:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
{{ memberInfo && memberInfo.last_login_time ? $util.timeFormat(memberInfo.last_login_time) : '--' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="saveMemberInfo">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 积分调整 -->
|
||||
<uni-popup ref="pointPop">
|
||||
<view class="pop-box pointPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">调整积分</view>
|
||||
<view class="pop-header-close" @click="popClose('point')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<view class="form-content">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
当前积分:
|
||||
</view>
|
||||
<view class="form-inline">{{ memberInfo && memberInfo.point ? memberInfo.point : '0' }}</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
调整数额:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" type="number" placeholder="请输入调整数额" v-model="pointData.num" />
|
||||
<view class="word-aux">调整数额与当前积分数相加不能小于0</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
备注:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<textarea class="form-textarea" v-model="pointData.desc"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="savePoint">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 发放优惠券 -->
|
||||
<uni-popup ref="sendCouponPop">
|
||||
<view class="pop-box sendCoupon-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">送优惠券</view>
|
||||
<view class="pop-header-close" @click="popClose('sendCoupon')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="common-scrollbar sendCoupon-content">
|
||||
<view class="coupon-table-head">
|
||||
<view class="coupon-table-th">优惠券名称</view>
|
||||
<view class="coupon-table-th">金额</view>
|
||||
<view class="coupon-table-th">有效期</view>
|
||||
<view class="coupon-table-th">发放数量</view>
|
||||
</view>
|
||||
<scroll-view class="coupon-table-body" @scrolltolower="getCouponList()" scroll-y="true">
|
||||
<view class="coupon-table-tr" v-for="(item, index) in sendCoupon.list" :key="index">
|
||||
<view class="coupon-table-td">{{ item.coupon_name }}</view>
|
||||
<view class="coupon-table-td">{{ item.money }}</view>
|
||||
<view class="coupon-table-td">{{ item.validity_name }}</view>
|
||||
<view class="coupon-table-td">
|
||||
<view class="item-num">
|
||||
<view class="num-dec" v-on:click="dec(item)">-</view>
|
||||
<input class="table-input" type="text" v-model="item.num" />
|
||||
<view class="num-inc" v-on:click="inc(item)">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="empty" v-if="!sendCoupon.list.length">
|
||||
<view class="iconfont iconwushuju"></view>
|
||||
<view>暂无数据</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="pop-bottom">
|
||||
<button v-if="sendCoupon.list.length" class="primary-btn" @click="sendCouponFn">发放优惠券</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 余额调整 -->
|
||||
<uni-popup ref="balancePop">
|
||||
<view class="pop-box pointPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">调整余额</view>
|
||||
<view class="pop-header-close" @click="popClose('balance')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<view class="form-content">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
当前余额:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
{{ memberInfo && memberInfo.balance ? memberInfo.balance : '0.00' }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
调整数额:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" type="number" placeholder="请输入调整数额" v-model="balanceData.num" />
|
||||
<view class="word-aux">调整数额与当前储值余额相加不能小于0</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
备注:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<textarea class="form-textarea" v-model="balanceData.desc"></textarea>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="saveBalance">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 成长值调整 -->
|
||||
<uni-popup ref="growthPop">
|
||||
<view class="pop-box pointPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">调整成长值</view>
|
||||
<view class="pop-header-close" @click="popClose('growth')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<view class="form-content">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
当前成长值:
|
||||
</view>
|
||||
<view class="form-inline">{{ memberInfo && memberInfo.growth ? memberInfo.growth : '0' }}</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
调整数额:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" type="number" placeholder="请输入调整数额" v-model="growthData.num" />
|
||||
<view class="word-aux">调整数额与当前成长值相加不能小于0</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
备注:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<textarea class="form-textarea" v-model="growthData.desc"></textarea>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="saveGrowth">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 办理会员 -->
|
||||
<uni-popup ref="applyMemberPop">
|
||||
<view class="pop-box applyMemberPop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">办理会员</view>
|
||||
<view class="pop-header-close" @click="popClose('applyMember')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="common-scrollbar pop-content">
|
||||
<view class="form-content">
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员等级:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<select-lay :zindex="10" :value="applyMember.level_id" name="names" placeholder="请选择会员等级" :options="memberLevelList" @selectitem="selectMemberLevel"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员卡号:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input class="form-input" type="text" placeholder="请输入会员卡号" v-model="applyMember.member_code" />
|
||||
<view class="word-aux">会员卡号为会员唯一编号,若不设置将会自动生成</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pop-bottom">
|
||||
<button class="primary-btn" @click="saveApplyMember">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 优惠券列表 -->
|
||||
<uni-popup ref="couponListPop">
|
||||
<view class="pop-box coupon-list-pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">优惠券</view>
|
||||
<view class="pop-header-close" @click="popClose('couponList')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<dataTable url="/cashier/storeapi/member/coupon" :cols="couponCols" ref="table" :option="option" :pagesize="pageSize"></dataTable>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 积分列表 -->
|
||||
<uni-popup ref="pointListPop">
|
||||
<view class="pop-box coupon-list-pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">积分</view>
|
||||
<view class="pop-header-close" @click="popClose('pointList')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<dataTable url="/cashier/storeapi/member/memberaccountlist" :cols="pointCols" ref="table" :option="option" :pagesize="pageSize"></dataTable>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 余额列表 -->
|
||||
<uni-popup ref="balanceListPop">
|
||||
<view class="pop-box coupon-list-pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">余额</view>
|
||||
<view class="pop-header-close" @click="popClose('balanceList')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<dataTable url="/cashier/storeapi/member/memberaccountlist" :cols="balanceCols" ref="table" :option="option" :pagesize="pageSize"></dataTable>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 成长值列表 -->
|
||||
<uni-popup ref="growthListPop">
|
||||
<view class="pop-box coupon-list-pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">成长值</view>
|
||||
<view class="pop-header-close" @click="popClose('growthList')">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y="true" class="common-scrollbar pop-content">
|
||||
<dataTable url="/cashier/storeapi/member/memberaccountlist" :cols="growthCols" ref="table" :option="option" :pagesize="pageSize"></dataTable>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 卡项 -->
|
||||
<ns-member-card-record ref="memberCardRecord" :option="option"/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataTable from '@/components/uni-data-table/uni-data-table.vue';
|
||||
import nsMemberCardRecord from '@/components/ns-member-card-record/ns-member-card-record.vue';
|
||||
import index from './index.js';
|
||||
export default {
|
||||
components: {
|
||||
dataTable,
|
||||
nsMemberCardRecord
|
||||
},
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
106
addon/cashier/source/os/components/ns-order-log/ns-order-log.vue
Executable file
106
addon/cashier/source/os/components/ns-order-log/ns-order-log.vue
Executable file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<view class="journal">
|
||||
<view class="item" v-for="(item, index) in list" :key="index">
|
||||
<view class="time">
|
||||
<view>{{ $util.timeFormat(item.action_time).split(' ')[0] }}</view>
|
||||
<view>{{ $util.timeFormat(item.action_time).split(' ')[1] }}</view>
|
||||
</view>
|
||||
<view class="unit">
|
||||
<view class="top">
|
||||
<view class="core"></view>
|
||||
<view class="unit-separate"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="message">{{ item.action }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mounted() {},
|
||||
methods: {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.journal {
|
||||
padding-left: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
height: 0.7rem;
|
||||
display: flex;
|
||||
|
||||
.time {
|
||||
margin-right: 0.1rem;
|
||||
min-width: 1rem;
|
||||
|
||||
view:nth-child(1) {
|
||||
font-size: 0.16rem;
|
||||
margin-bottom: 0.1rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
view:nth-child(2) {
|
||||
font-size: 0.14rem;
|
||||
color: #999999;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unit {
|
||||
width: 0.18rem;
|
||||
height: 100%;
|
||||
margin-right: 0.1rem;
|
||||
|
||||
.top {
|
||||
width: 0.18rem;
|
||||
height: 0.18rem;
|
||||
border-radius: 50%;
|
||||
background: $primary-color;
|
||||
position: relative;
|
||||
|
||||
.core {
|
||||
background: #ffffff;
|
||||
width: 0.08rem;
|
||||
height: 0.08rem;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.unit-separate {
|
||||
position: absolute;
|
||||
width: 0.01rem;
|
||||
height: 0.7rem;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: $primary-color;
|
||||
z-index: 555;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1023
addon/cashier/source/os/components/ns-payment/index.js
Executable file
1023
addon/cashier/source/os/components/ns-payment/index.js
Executable file
File diff suppressed because it is too large
Load Diff
786
addon/cashier/source/os/components/ns-payment/index.scss
Executable file
786
addon/cashier/source/os/components/ns-payment/index.scss
Executable file
@@ -0,0 +1,786 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
& > view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-wrap {
|
||||
.header {
|
||||
height: 0.66rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
padding: 0.15rem 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.info-wrap {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
margin-right: 0.15rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
background-color: #f7f8fa;
|
||||
padding-bottom: 0.15rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
/deep/ .uni-scroll-view-content {
|
||||
margin: 0 0.15rem;
|
||||
width: calc(100% - 0.3rem);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.payment-money {
|
||||
text-align: right;
|
||||
font-size: 0.2rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
line-height: 0.6rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
line-height: 0.6rem;
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.uni-flex {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.type-item {
|
||||
padding: 0.2rem 0.1rem;
|
||||
background: #fff;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.16rem;
|
||||
margin: 0 0.1rem 0.1rem 0;
|
||||
width: calc((100% - 0.86rem) / 3);
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
border-radius: 0.02rem;
|
||||
|
||||
&.account {
|
||||
width: calc((100% - 0.86rem) / 2);
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:nth-child(3n + 3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
color: $primary-color;
|
||||
font-size: 0.3rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #fe2278;
|
||||
margin-left: 0.05rem;
|
||||
}
|
||||
|
||||
.iconxuanzhong {
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $primary-color;
|
||||
|
||||
.iconxuanzhong {
|
||||
display: block;
|
||||
right: -0.11rem;
|
||||
bottom: -0.01rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: #f5f5f5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.pay-type {
|
||||
.type-item {
|
||||
padding: 0.15rem 0.1rem;
|
||||
}
|
||||
|
||||
.pay-icon {
|
||||
color: #fff;
|
||||
background: #f0f0f0;
|
||||
width: 0.3rem;
|
||||
height: 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.16rem;
|
||||
border-radius: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.button-wrap {
|
||||
padding-top: 0.15rem;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
.scancode {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 0 0 0 0.1rem;
|
||||
min-width: 1rem;
|
||||
}
|
||||
|
||||
.print-ticket {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bill-wrap {
|
||||
width: 3rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
font-size: 0.2rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
line-height: 0.6rem;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 0;
|
||||
margin: 0 0.15rem;
|
||||
display: block;
|
||||
height: auto;
|
||||
|
||||
.block-title {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
height: 0.35rem;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
text {
|
||||
padding: 0 0.2rem;
|
||||
background: #fff;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
z-index: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
border-top: 0.01rem dashed #e6e6e6;
|
||||
}
|
||||
}
|
||||
|
||||
.bill-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
line-height: 1;
|
||||
align-items: center;
|
||||
margin-top: 0.2rem;
|
||||
|
||||
.text {
|
||||
color: #fe2278;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark-info {
|
||||
padding: 0.1rem;
|
||||
background-color: var(--primary-color-light-9);
|
||||
color: $primary-color;
|
||||
margin-top: 0.1rem;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pay-result {
|
||||
.body {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
text-align: center;
|
||||
|
||||
&.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
.iconfont {
|
||||
font-size: 1rem;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.msg {
|
||||
margin-top: 0.1rem;
|
||||
font-size: 0.16rem;
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 0.66rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 0.01rem solid #e6e6e6;
|
||||
justify-content: center;
|
||||
|
||||
button {
|
||||
margin: 0 0 0 0.15rem;
|
||||
width: auto;
|
||||
min-width: 1.6rem;
|
||||
height: 0.45rem;
|
||||
line-height: 0.45rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.money-wrap {
|
||||
background: #fff;
|
||||
border-radius: 0.05rem;
|
||||
|
||||
.head {
|
||||
height: 0.6rem;
|
||||
line-height: 0.6rem;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
|
||||
text {
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.iconguanbi1 {
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.22rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
display: flex;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
height: 0.6rem;
|
||||
align-items: center;
|
||||
margin: 0 0.2rem;
|
||||
padding: 0 0.15rem;
|
||||
|
||||
.unit {
|
||||
font-size: 0.25rem;
|
||||
}
|
||||
|
||||
.money {
|
||||
margin-left: 0.05rem;
|
||||
font-size: 0.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.keyboard-wrap {
|
||||
width: 4rem;
|
||||
padding: 0 0.2rem 0.3rem 0.2rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.coupon-wrap {
|
||||
background: #fff;
|
||||
width: 6rem;
|
||||
border-radius: 0.05rem;
|
||||
|
||||
.head {
|
||||
height: 0.6rem;
|
||||
line-height: 0.6rem;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
|
||||
text {
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.iconguanbi1 {
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.22rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
padding: 0.1rem 0.15rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.item {
|
||||
margin: 0 0.1rem 0.1rem 0;
|
||||
padding: 0.1rem 0;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
width: calc((100% - 0.14rem) / 2);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.iconxuanzhong {
|
||||
position: absolute;
|
||||
display: none;
|
||||
right: -0.01rem;
|
||||
bottom: -0.01rem;
|
||||
font-size: 0.3rem;
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-color: $primary-color;
|
||||
|
||||
.iconxuanzhong {
|
||||
display: block;
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(2n + 2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.money {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 0.6rem;
|
||||
min-width: 1rem;
|
||||
font-size: 0.2rem;
|
||||
line-height: 1;
|
||||
|
||||
.unit {
|
||||
font-size: 0.16rem;
|
||||
margin-top: 0.05rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 0 0.1rem;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.time,
|
||||
.limit {
|
||||
font-size: 0.12rem;
|
||||
color: #999;
|
||||
line-height: 1;
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.safe-verify-popup {
|
||||
width: 4.4rem;
|
||||
height: 3.1rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
|
||||
.header {
|
||||
height: 0.6rem;
|
||||
line-height: 0.6rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.type-wrap {
|
||||
display: flex;
|
||||
|
||||
.item {
|
||||
margin-left: 0.15rem;
|
||||
font-size: 0.16rem;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
font-size: 0.18rem;
|
||||
color: $primary-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.iconguanbi1 {
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
top: 0;
|
||||
font-size: 0.22rem;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 0.3rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.member-code-hint{
|
||||
margin-top: .3rem;
|
||||
font-size: .16rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.mobile {
|
||||
font-size: 0.25rem;
|
||||
font-weight: bold;
|
||||
margin-top: 0.05rem;
|
||||
}
|
||||
|
||||
.sms-code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0.15rem;
|
||||
border-bottom: 0.01rem solid #eee;
|
||||
padding: 0.15rem 0;
|
||||
|
||||
view {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
margin: 0 0.1rem 0 0;
|
||||
padding: 0;
|
||||
border-bottom: none;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
text {
|
||||
position: absolute;
|
||||
right: 0.1rem;
|
||||
font-size: 0.2rem;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.send-tip {
|
||||
color: $primary-color;
|
||||
font-size: 0.13rem;
|
||||
cursor: pointer;
|
||||
|
||||
&.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
margin-top: 0.3rem;
|
||||
line-height: 0.4rem;
|
||||
}
|
||||
|
||||
.scancode-wrap {
|
||||
text-align: center;
|
||||
|
||||
.input-wrap {
|
||||
display: flex;
|
||||
|
||||
view {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
|
||||
input {
|
||||
width: 0;
|
||||
flex: 1;
|
||||
height: 0.5rem;
|
||||
border: 0.01rem solid #cccccc;
|
||||
text-align: center;
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.focus {
|
||||
border-color: $primary-color;
|
||||
box-shadow: 0 0 0.02rem 0.02rem var(--primary-color-light-7);
|
||||
}
|
||||
}
|
||||
|
||||
text {
|
||||
position: absolute;
|
||||
right: 0.1rem;
|
||||
font-size: 0.2rem;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
margin: 0 0 0 0.1rem;
|
||||
line-height: 0.5rem;
|
||||
width: 1rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
image {
|
||||
width: 3rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.third-popup {
|
||||
width: 4rem;
|
||||
height: 5rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.head {
|
||||
height: 0.8rem;
|
||||
line-height: 0.8rem;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
text {
|
||||
font-size: 0.25rem;
|
||||
}
|
||||
|
||||
.iconguanbi1 {
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.22rem;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.money {
|
||||
text-align: center;
|
||||
font-size: 0.18rem;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.scan-code-type {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin-top: 0.2rem;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.type-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
line-height: 0.5rem;
|
||||
font-size: 0.16rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 0.03rem solid #f5f5f5;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
border-bottom: 0.03rem solid $primary-color;
|
||||
}
|
||||
|
||||
&:last-child::after {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 20%;
|
||||
width: 0.01rem;
|
||||
height: 60%;
|
||||
background: #ddd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-wrap {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.qrcode-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.empty {
|
||||
padding: 1rem 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qrcode-item {
|
||||
height: 1.3rem;
|
||||
width: 1.3rem;
|
||||
padding: 0.1rem;
|
||||
box-shadow: 0 0.02rem 0.1rem 0 rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.qrcode {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 0.25rem;
|
||||
position: absolute !important;
|
||||
z-index: 5;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scancode-wrap {
|
||||
view {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
input {
|
||||
width: 3.3rem;
|
||||
height: 0.5rem;
|
||||
border: 0.01rem solid #cccccc;
|
||||
text-align: center;
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
|
||||
&.focus {
|
||||
border-color: $primary-color;
|
||||
box-shadow: 0 0 0.02rem 0.02rem var(--primary-color-light-7);
|
||||
}
|
||||
}
|
||||
|
||||
text {
|
||||
position: absolute;
|
||||
right: 0.1rem;
|
||||
font-size: 0.2rem;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
image {
|
||||
width: 3.3rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark-wrap {
|
||||
width: 6rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.04rem;
|
||||
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0.15rem;
|
||||
height: 0.45rem;
|
||||
line-height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconfont {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 0.15rem 0.15rem 0.1rem;
|
||||
|
||||
textarea {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
width: 100%;
|
||||
padding: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.placeholder-class {
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
height: 0.5rem;
|
||||
padding-bottom: 0.05rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
button {
|
||||
width: 95%;
|
||||
}
|
||||
}
|
||||
}
|
||||
366
addon/cashier/source/os/components/ns-payment/ns-payment.vue
Executable file
366
addon/cashier/source/os/components/ns-payment/ns-payment.vue
Executable file
@@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<view class="container" v-if="payInfo">
|
||||
<view class="uni-flex uni-column payment-wrap" v-show="payStatus == 'pay'">
|
||||
<view class="header">结算</view>
|
||||
<view class="body">
|
||||
<view class="info-wrap">
|
||||
<scroll-view scroll-y="true" class="info">
|
||||
<view class="payment-money">费用总额:¥{{ payInfo.original_money | moneyFormat }}</view>
|
||||
<block v-if="promotionShow">
|
||||
<view class="title">营销优惠</view>
|
||||
<view class="uni-flex">
|
||||
<view class="type-item" :class="{ disabled: payInfo.offset.coupon_array.member_coupon_list.length == 0, active: discount.coupon_id }" @click="selectCoupon" v-if="payInfo.offset.coupon_array">
|
||||
<view class="iconfont iconyouhuiquan"></view>
|
||||
<view class="name" v-show="!discount.coupon_id">
|
||||
优惠券
|
||||
<text class="text" v-if="payInfo.offset.coupon_array.member_coupon_list.length">
|
||||
({{ payInfo.offset.coupon_array.member_coupon_list.length }}张可用)
|
||||
</text>
|
||||
</view>
|
||||
<view class="name" v-show="discount.coupon_id">
|
||||
优惠券抵扣
|
||||
<text class="text">{{ payInfo.coupon_money }}元</text>
|
||||
</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
<view class="type-item" :class="{ active: discount.reduction }" @click="reduction" v-if="payInfo.collectmoney_config.reduction == 1">
|
||||
<view class="iconfont iconjianmianjine"></view>
|
||||
<view class="name" v-if="discount.reduction" @click.stop="openMoneyPopup({ title: '减免金额', money: $util.moneyFormat(discount.reduction), type: 'reduction' })">
|
||||
减免
|
||||
<text class="text">{{ discount.reduction }}元</text>
|
||||
</view>
|
||||
<view v-else class="name">减免金额</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<block v-if="payInfo.offset.point_array || payInfo.offset.balance">
|
||||
<view class="title">账户余额</view>
|
||||
<view class="uni-flex">
|
||||
<view class="type-item account" :class="{ active: discount.is_use_balance, disabled: balance == 0 }" @click="useBalance" v-if="payInfo.offset.balance">
|
||||
<view class="iconfont iconyue"></view>
|
||||
<view class="name" v-if="discount.is_use_balance">
|
||||
余额支付
|
||||
<text class="text">{{ payInfo.total_balance | moneyFormat }}元</text>
|
||||
</view>
|
||||
<view class="name" v-else>
|
||||
账户余额
|
||||
<text class="text" v-if="balance > 0">{{ balance | moneyFormat }}元</text>
|
||||
</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
<view class="type-item account" :class="{ active: discount.is_use_point, disabled: payInfo.offset.point_array.point == 0 }" @click="usePoint" v-if="payInfo.offset.point_array">
|
||||
<view class="iconfont iconjifen1"></view>
|
||||
<view class="name" v-if="discount.is_use_point">
|
||||
积分抵扣
|
||||
<text class="text">{{ payInfo.point_money | moneyFormat }}元({{ parseInt(payInfo.offset.point_array.point) }}积分)</text>
|
||||
</view>
|
||||
<view class="name" v-else>
|
||||
账户积分
|
||||
<text class="text" v-if="globalMemberInfo.point">{{ globalMemberInfo.point }}积分</text>
|
||||
</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view class="title">支付方式</view>
|
||||
<view class="uni-flex pay-type">
|
||||
<block v-for="(item, key,index) in payType" :key="key">
|
||||
<view class="type-item" @click="switchPayType(item.type)" :class="{ active: item.type == type }">
|
||||
<view class="pay-icon iconfont" :style="{ background: item.background }" :class="item.icon"></view>
|
||||
<view class="name">{{ item.name }} [{{ item.hotKey }}]</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="type-item" @click="switchMemberCode()" :class="{ active: discount.is_use_balance}">
|
||||
<view class="pay-icon iconfont iconhuiyuanma" :style="{ background: '#F7861E' }"></view>
|
||||
<view class="name">
|
||||
<text>会员码 [M]</text>
|
||||
<template v-if="discount.is_use_balance">
|
||||
<text style="margin-left: 0.05rem;">(</text>
|
||||
<text style="margin-left: 0.05rem;">使用余额</text>
|
||||
<text class="text">{{ payInfo.total_balance | moneyFormat }}元</text>
|
||||
<text style="margin-left: 0.05rem;">)</text>
|
||||
</template>
|
||||
</view>
|
||||
<!-- <view class="iconfont iconxuanzhong"></view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="remark-info" v-if="payInfo.remark">备注:{{ payInfo.remark }}</view>
|
||||
</scroll-view>
|
||||
<view class="button-wrap">
|
||||
<view class="print-ticket">
|
||||
<checkbox-group @change="autoPrintTicket = !autoPrintTicket">
|
||||
<label>
|
||||
<checkbox :checked="autoPrintTicket" style="transform:scale(0.7)" />
|
||||
<text>打印小票</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
<button class="default-btn" @click="openRemark">备注</button>
|
||||
<button class="default-btn cancel-btn" plain @click="cancelPayment">取消 [Esc]</button>
|
||||
<button class="primary-btn" @click="confirm()" v-if="type != 'third' || payInfo.pay_money == 0">收款 [Enter]</button>
|
||||
<button class="primary-btn" @click="thirdConfirm()" v-else>收款 [Enter]</button>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="bill-wrap">
|
||||
<view class="title">支付明细</view>
|
||||
<view class="body">
|
||||
<view class="bill-info">
|
||||
<view>费用总额</view>
|
||||
<view>¥{{ payInfo.original_money | moneyFormat }}</view>
|
||||
</view>
|
||||
<view class="block-title"><text>营销优惠</text></view>
|
||||
<view class="bill-info">
|
||||
<view>减免金额</view>
|
||||
<view class="text">
|
||||
-¥{{ payInfo.offset.reduction ? $util.moneyFormat(payInfo.offset.reduction) : '0.00' }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="bill-info" v-if="payInfo.offset.coupon_array">
|
||||
<view>优惠券</view>
|
||||
<view class="text">-¥{{ $util.moneyFormat(payInfo.coupon_money) }}</view>
|
||||
</view>
|
||||
<view class="bill-info" v-if="payInfo.offset.hongbao_array">
|
||||
<view>红包</view>
|
||||
<view class="text">-¥{{ $util.moneyFormat(payInfo.hongbao_money) }}</view>
|
||||
</view>
|
||||
<view class="bill-info" v-if="payInfo.offset.point_array">
|
||||
<view>积分抵扣</view>
|
||||
<view class="text">-¥{{ $util.moneyFormat(payInfo.point_money) }}</view>
|
||||
</view>
|
||||
<block v-if="payInfo.offset.balance">
|
||||
<view class="block-title"><text>余额抵扣</text></view>
|
||||
<view class="bill-info">
|
||||
<view>余额支付</view>
|
||||
<view>-¥{{ $util.moneyFormat(payInfo.total_balance) }}</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="block-title"><text>支付方式</text></view>
|
||||
<view class="bill-info">
|
||||
<view>{{ payType[type].name }}</view>
|
||||
<view v-show="type == 'cash'">
|
||||
¥{{ payInfo.cash > 0 ? $util.moneyFormat(payInfo.cash) : $util.moneyFormat(payInfo.pay_money) }}
|
||||
</view>
|
||||
<view v-show="type != 'cash'">¥{{ payInfo.pay_money | moneyFormat }}</view>
|
||||
</view>
|
||||
<view class="block-title"></view>
|
||||
<view class="bill-info">
|
||||
<view>需支付</view>
|
||||
<view>¥{{ payInfo.pay_money | moneyFormat }}</view>
|
||||
</view>
|
||||
<view class="bill-info">
|
||||
<view>实付</view>
|
||||
<view v-show="type == 'cash'">
|
||||
¥{{ payInfo.cash > 0 ? $util.moneyFormat(payInfo.cash) : $util.moneyFormat(payInfo.pay_money) }}
|
||||
</view>
|
||||
<view v-show="type != 'cash'">¥{{ payInfo.pay_money | moneyFormat }}</view>
|
||||
</view>
|
||||
<view class="bill-info" v-if="payInfo.cash_change > 0">
|
||||
<view>找零</view>
|
||||
<view>¥{{ payInfo.cash_change | moneyFormat }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付结果 -->
|
||||
<view class="uni-flex uni-column pay-result" v-show="payStatus == 'success'">
|
||||
<view class="body status">
|
||||
<view class="iconfont iconchenggong"></view>
|
||||
<view class="msg">收款成功</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<button class="primary-btn" @click="paySuccess">继续收款 [Enter]({{ autoComplete.time }}s)</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-popup ref="moneyPopup" type="center">
|
||||
<view class="money-wrap">
|
||||
<view class="head">
|
||||
<text>{{ moneyPopup.title }}</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.moneyPopup.close()"></text>
|
||||
</view>
|
||||
<view class="content-wrap">
|
||||
<view class="unit">¥</view>
|
||||
<view class="money">{{ moneyPopup.money }}</view>
|
||||
</view>
|
||||
<view class="keyboard-wrap">
|
||||
<view class="num-wrap">
|
||||
<view class="key-item" @click="keydown('1')">1</view>
|
||||
<view class="key-item" @click="keydown('2')">2</view>
|
||||
<view class="key-item" @click="keydown('3')">3</view>
|
||||
<view class="key-item" @click="keydown('4')">4</view>
|
||||
<view class="key-item" @click="keydown('5')">5</view>
|
||||
<view class="key-item" @click="keydown('6')">6</view>
|
||||
<view class="key-item" @click="keydown('7')">7</view>
|
||||
<view class="key-item" @click="keydown('8')">8</view>
|
||||
<view class="key-item" @click="keydown('9')">9</view>
|
||||
<view class="key-item" @click="keydown('00')">00</view>
|
||||
<view class="key-item" @click="keydown('0')">0</view>
|
||||
<view class="key-item" @click="keydown('.')">.</view>
|
||||
</view>
|
||||
<view class="action-wrap">
|
||||
<view class="delete" @click="deleteCode">删除</view>
|
||||
<view class="delete" @click="moneyPopup.money = ''">清空</view>
|
||||
<view class="confirm" @click="moneyPopupConfirm()">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<uni-popup ref="couponPopup" type="center" v-if="payInfo.offset.coupon_array && payInfo.offset.coupon_array.member_coupon_list.length">
|
||||
<view class="coupon-wrap">
|
||||
<view class="head">
|
||||
<text>选择优惠券</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.couponPopup.close()"></text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="body">
|
||||
<view class="list">
|
||||
<view class="item" :class="{ active: discount.coupon_id && discount.coupon_id == item.coupon_id }" v-for="(item, index) in payInfo.offset.coupon_array.member_coupon_list" :key="index" @click="selectCouponItem(item)">
|
||||
<view class="money" v-show="item.type == 'discount'">
|
||||
{{ item.discount }}
|
||||
<text class="unit">折</text>
|
||||
</view>
|
||||
<view class="money" v-show="item.type != 'discount'">
|
||||
<text class="unit">¥</text>
|
||||
{{ item.money }}
|
||||
</view>
|
||||
<view class="info">
|
||||
<view class="title">{{ item.coupon_name }}</view>
|
||||
<view class="limit">
|
||||
{{ item.at_least == 0 ? '无门槛券' : '满' + item.at_least + '可用' }}
|
||||
{{ item.type == 'discount' && item.discount_limit > 0 ? ',最多优惠' + item.discount_limit : '' }}
|
||||
</view>
|
||||
<view class="time" v-if="item.end_time">{{ $util.timeFormat(item.end_time, 'y-m-d') }}前可用
|
||||
</view>
|
||||
<view class="time" v-else>长期有效</view>
|
||||
</view>
|
||||
<view class="iconfont iconxuanzhong"></view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 扫码枪支付弹窗 -->
|
||||
<uni-popup ref="thirdPopup" type="center" @change="popupChange">
|
||||
<view class="third-popup">
|
||||
<view class="head">
|
||||
<text>请选择扫码方式</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.thirdPopup.close();thirdPopupOpen = false;"></text>
|
||||
</view>
|
||||
<view class="money">扫码收款¥{{ payInfo.pay_money | moneyFormat }}</view>
|
||||
<view class="scan-code-type" v-if="type == 'third'">
|
||||
<view class="type-item" :class="{ active: scanCodeType == 'scancode' }" @click="scanCodeType = 'scancode'">扫码枪</view>
|
||||
<view class="type-item" :class="{ active: scanCodeType == 'qrcode' }" @click="scanCodeType = 'qrcode'">二维码</view>
|
||||
</view>
|
||||
<view class="content-wrap">
|
||||
<view class="qrcode-wrap" v-show="scanCodeType == 'qrcode'">
|
||||
<block v-if="payQrcode.length">
|
||||
<view class="qrcode-item" v-for="(item, index) in payQrcode" :key="index">
|
||||
<image :src="item.qrcode.replace(/[\r\n]/g, '')" mode="widthFix" class="qrcode" v-if="item.qrcode.indexOf('data:image') != -1" />
|
||||
<image :src="$util.img(item.qrcode)" mode="widthFix" class="qrcode" v-else />
|
||||
<image :src="$util.img(item.logo)" mode="widthFix" class="logo" />
|
||||
</view>
|
||||
</block>
|
||||
<view class="empty" v-else>没有可用的收款二维码</view>
|
||||
</view>
|
||||
<view class="scancode-wrap" v-show="scanCodeType == 'scancode'">
|
||||
<block v-if="scancodeList.length">
|
||||
<view>
|
||||
<input type="number" v-model="authCode" :class="{ focus: scanCodeFocus }"
|
||||
:focus="scanCodeFocus" placeholder="请点击输入框聚焦扫码或输入付款码" @confirm="scanCode"
|
||||
@focus="scanCodeFocus = true" @blur="scanCodeInputBlur()" />
|
||||
<text class="iconfont icondelete" v-show="authCode.length > 0" @click="clearAuthCode"></text>
|
||||
</view>
|
||||
<image src="@/static/cashier/scan_code_tip.png" mode="widthFix" />
|
||||
</block>
|
||||
<view class="empty" v-else>没有可用的支付方式</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<!-- 使用账号余额,验证会员码/手机号 -->
|
||||
<uni-popup ref="safeVerifyPopup" type="center">
|
||||
<view class="safe-verify-popup">
|
||||
<view class="header">
|
||||
<view class="type-wrap" v-if="active == 'memberCodePopup'">
|
||||
<view class="item">会员码</view>
|
||||
</view>
|
||||
<view class="type-wrap" v-else-if="active == 'safeVerifyPopup' && payInfo.collectmoney_config.sms_verify == 1">
|
||||
<view class="item" :class="{ active: safeVerifyType == 'payment_code' }" @click="changeSafeVerifyType('payment_code')">会员码</view>
|
||||
<view class="item" :class="{ active: safeVerifyType == 'sms_code' }" @click="changeSafeVerifyType('sms_code')">短信验证码</view>
|
||||
</view>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.safeVerifyPopup.close()"></text>
|
||||
</view>
|
||||
<view class="content" v-show="safeVerifyType == 'payment_code'">
|
||||
<view class="scancode-wrap">
|
||||
<view class="input-wrap">
|
||||
<view>
|
||||
<input type="number" v-model="paymentCode" :class="{ focus: scanCodeFocus }"
|
||||
:focus="scanCodeFocus" placeholder="请点击输入框聚焦扫码或输入会员码" @confirm="verifyPaymentCode"
|
||||
@focus="scanCodeFocus = true" @blur="scanCodeInputBlur()"
|
||||
placeholder-class="placeholder" />
|
||||
<text class="iconfont icondelete" v-show="paymentCode.length > 0" @click="clearPaymentCode"></text>
|
||||
</view>
|
||||
<button class="primary-btn" @click="verifyPaymentCode">确认</button>
|
||||
</view>
|
||||
<image src="@/static/cashier/scan_code_tip.png" mode="widthFix" />
|
||||
<!-- <view class="member-code-hint">打开手机端 --》个人中心 --》 会员码</view> -->
|
||||
</view>
|
||||
</view>
|
||||
<view class="content" v-show="safeVerifyType == 'sms_code' && active == 'safeVerifyPopup'">
|
||||
<block v-if="payInfo.member_account">
|
||||
<view class="tip">将发送验证码到该手机</view>
|
||||
<view class="mobile">
|
||||
{{ payInfo.member_account.mobile.replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2') }}
|
||||
</view>
|
||||
<view class="sms-code">
|
||||
<view>
|
||||
<input type="number" v-model="smsCode" class="sms-code" placeholder="请输入验证码"
|
||||
:focus="scanCodeFocus" placeholder-class="placeholder" @focus="scanCodeFocus = true"
|
||||
@blur="scanCodeFocus = false" />
|
||||
<text class="iconfont icondelete" v-show="smsCode.length > 0" @click="clearSmsCode"></text>
|
||||
</view>
|
||||
<text class="send-tip" @click="sendMobileCode" :class="{ disabled: dynacodeData.isSend }">{{ dynacodeData.codeText }}</text>
|
||||
</view>
|
||||
<button class="primary-btn" @click="verifySmsCode">确认</button>
|
||||
</block>
|
||||
<view v-else>该会员尚未绑定手机号,无法使用该验证方式</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<uni-popup ref="remarkPopup" type="center">
|
||||
<view class="remark-wrap">
|
||||
<view class="header">
|
||||
<text class="title">备注</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
|
||||
</view>
|
||||
<view class="body">
|
||||
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" @keydown.enter="remarkConfirm" />
|
||||
</view>
|
||||
<view class="footer">
|
||||
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from './index.js';
|
||||
export default {
|
||||
name: 'nsPayment',
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
146
addon/cashier/source/os/components/ns-pend-order-popup/index.js
Executable file
146
addon/cashier/source/os/components/ns-pend-order-popup/index.js
Executable file
@@ -0,0 +1,146 @@
|
||||
import { editPendOrderRemark, deletePendOrder, getPendOrderList } from '@/api/pendorder.js';
|
||||
import { getMemberInfoById } from '@/api/member.js'
|
||||
import {mapGetters} from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'nsPendOrder',
|
||||
data() {
|
||||
return {
|
||||
orderData: {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
},
|
||||
remark: '',
|
||||
index: -1,
|
||||
orderId: 0,
|
||||
isRepeat: false,
|
||||
height: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['pendOrderNum'])
|
||||
},
|
||||
created() {
|
||||
this.getOrder();
|
||||
},
|
||||
mounted() {
|
||||
this.setHeight();
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.$refs.pendOrderPop.open();
|
||||
},
|
||||
getOrder(page = null) {
|
||||
if (page === 0) this.orderData.page = page;
|
||||
this.orderId = 0;
|
||||
|
||||
if (this.orderData.page + 1 > this.orderData.total) return;
|
||||
|
||||
this.orderData.page++;
|
||||
|
||||
getPendOrderList({ page: this.orderData.page }).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.orderData.page == 1) this.orderData.list = [];
|
||||
this.$store.commit('billing/setPendOrderNum', res.data.count);
|
||||
if (res.data.list.length) {
|
||||
this.orderData.total = res.data.page_count;
|
||||
this.orderData.list = this.orderData.list.concat(res.data.list);
|
||||
} else {
|
||||
this.orderData.total = 1;
|
||||
}
|
||||
this.setHeight();
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteOrder(order_id) {
|
||||
if (this.isRepeat) return;
|
||||
this.isRepeat = true;
|
||||
deletePendOrder(order_id).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.isRepeat = false;
|
||||
this.getOrder(0);
|
||||
}
|
||||
});
|
||||
},
|
||||
remarkConfirm() {
|
||||
let data = this.orderData.list[this.index];
|
||||
editPendOrderRemark({
|
||||
order_id: data.order_id,
|
||||
remark: this.remark
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.orderData.list[this.index].remark = this.remark;
|
||||
this.$refs.remarkPopup.close();
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: '操作失败'
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
remarkSetting(data, index) {
|
||||
this.index = index;
|
||||
this.remark = data.remark;
|
||||
this.$refs.remarkPopup.open();
|
||||
},
|
||||
async takeOrder(data) {
|
||||
this.orderId = data.order_id;
|
||||
//获取挂单数据的会员信息
|
||||
if (data.member_id) {
|
||||
let res = await getMemberInfoById(data.member_id);
|
||||
if (res.code == 0 && res.data) {
|
||||
this.$store.commit('app/setGlobalMemberInfo', res.data);
|
||||
} else {
|
||||
this.$store.commit('app/setGlobalMemberInfo', null);
|
||||
}
|
||||
}
|
||||
//取出挂单数据设置到展示列表
|
||||
let goodsData = {};
|
||||
data.order_goods.forEach(item => {
|
||||
if (item.goods_class == 'money') item.money = item.price;
|
||||
//item.is_adjust = true;
|
||||
var key = 'sku_' + item.sku_id;
|
||||
if (item.goods_class == 4 || item.goods_class == 6) {
|
||||
var index = 0;
|
||||
Object.keys(goodsData).forEach(k => {
|
||||
if (k.indexOf(key) != -1) {
|
||||
index++;
|
||||
}
|
||||
});
|
||||
key += '_' + index;
|
||||
}
|
||||
goodsData[key] = item;
|
||||
});
|
||||
this.$store.commit('billing/setPendOrderId', data.order_id);
|
||||
this.$store.commit('billing/setPendOrderNum', this.pendOrderNum - 1);
|
||||
this.$store.commit('billing/setGoodsData', goodsData);
|
||||
this.$store.commit('billing/setOrderData', {
|
||||
goods_list: [],
|
||||
remark: data.remark
|
||||
});
|
||||
|
||||
this.$store.commit('billing/setActive', 'SelectGoodsAfter');
|
||||
this.$refs.pendOrderPop.close();
|
||||
},
|
||||
switchStoreAfter() {
|
||||
this.orderData = {
|
||||
page: 0,
|
||||
total: 1,
|
||||
list: []
|
||||
};
|
||||
this.getOrder();
|
||||
},
|
||||
setHeight() {
|
||||
this.$nextTick(() => {
|
||||
const query = uni.createSelectorQuery()
|
||||
// #ifndef MP-ALIPAY
|
||||
.in(this)
|
||||
// #endif
|
||||
query.selectViewport().scrollOffset(data => {
|
||||
this.height = (data.scrollHeight - 51 - 67 - 15) / 100 + 'rem';
|
||||
}).exec();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
269
addon/cashier/source/os/components/ns-pend-order-popup/index.scss
Executable file
269
addon/cashier/source/os/components/ns-pend-order-popup/index.scss
Executable file
@@ -0,0 +1,269 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.pend-order-scroll-view-wrap {
|
||||
height: calc(100% - 0.67rem) !important;
|
||||
box-sizing: border-box;
|
||||
padding-top: 0.15rem;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 0.66rem;
|
||||
line-height: 0.66rem;
|
||||
text-align: left;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
color: #303133;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.table-list {
|
||||
.table-item {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
padding: 0.15rem;
|
||||
position: relative;
|
||||
margin-bottom: 0.2rem;
|
||||
|
||||
.table-header-info {
|
||||
text {
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.color {
|
||||
font-size: 0.18rem;
|
||||
color: #fe2278;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header-time {
|
||||
color: #909399;
|
||||
font-size: 0.14rem;
|
||||
margin-top: 0.1rem;
|
||||
|
||||
.line {
|
||||
margin: 0 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.table-header-btn {
|
||||
position: absolute;
|
||||
right: 0.3rem;
|
||||
top: 0.3rem;
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table-content {
|
||||
margin-top: 0.1rem;
|
||||
|
||||
.table-content-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
padding: 0.1rem 0;
|
||||
|
||||
.content-item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
.content-item-info {
|
||||
padding-right: 0.15rem;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
view {
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.content-item-name {
|
||||
margin-bottom: 0.05rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
white-space: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-item-img {
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
margin-right: 0.1rem;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.content-item-number {
|
||||
font-size: 0.16rem;
|
||||
}
|
||||
|
||||
.content-item-price {
|
||||
font-size: 0.14rem;
|
||||
width: 40%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remark-info {
|
||||
padding: 0.1rem;
|
||||
background-color: var(--primary-color-light-9);
|
||||
color: $primary-color;
|
||||
margin-top: 0.1rem;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
.table-bottom {
|
||||
margin-top: 0.2rem;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
|
||||
button {
|
||||
width: 1rem;
|
||||
margin: 0;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-scroll-view {
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
background-color: rgba($color: #000000, $alpha: 0);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 0.06rem;
|
||||
box-shadow: inset 0 0 0.06rem rgba(45, 43, 43, 0.45);
|
||||
background-color: #ddd;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover::-webkit-scrollbar-thumb {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.remark-wrap {
|
||||
width: 6rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.04rem;
|
||||
box-shadow: 0 0.01rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
.header,
|
||||
.footer {
|
||||
height: 0.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
line-height: 1;
|
||||
position: absolute;
|
||||
right: 0.15rem;
|
||||
font-size: 0.2rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 0.15rem;
|
||||
|
||||
textarea {
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
width: 100%;
|
||||
padding: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.placeholder-class {
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
border-top: 0.01rem solid #e6e6e6;
|
||||
border-bottom: unset;
|
||||
|
||||
button {
|
||||
width: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding-top: 1.2rem;
|
||||
|
||||
image {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
// pop弹框
|
||||
.pop-box {
|
||||
background: #ffffff;
|
||||
width: 8rem;
|
||||
height: 7rem;
|
||||
|
||||
.pop-header {
|
||||
padding: 0 0.15rem 0 0.2rem;
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
border-bottom: 0.01rem solid #f0f0f0;
|
||||
font-size: 0.14rem;
|
||||
color: #333;
|
||||
overflow: hidden;
|
||||
border-radius: 0.02rem 0.2rem 0 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.pop-header-text {}
|
||||
|
||||
.pop-header-close {
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
font-size: 0.18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<view class="container pend-order">
|
||||
|
||||
<uni-popup ref="pendOrderPop">
|
||||
<view class="pop-box">
|
||||
<view class="pop-header">
|
||||
<view class="pop-header-text">挂/取单</view>
|
||||
<view class="pop-header-close" @click="$refs.pendOrderPop.close()">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" @scrolltolower="getOrder" class="pend-order-scroll-view-wrap" :style="{height : height}">
|
||||
<view class="table-list" v-if="orderData.list.length">
|
||||
<block v-for="(item, index) in orderData.list" :key="index">
|
||||
<view class="table-item" v-show="item.order_id != orderId">
|
||||
<view class="table-header">
|
||||
<view class="table-header-info">
|
||||
<text>订单总价:</text>
|
||||
<text class="color">¥{{ item.order_money | moneyFormat }}</text>
|
||||
</view>
|
||||
<view class="table-header-time">
|
||||
<text>挂单时间:{{ item.create_time | timeFormat }}</text>
|
||||
<block v-if="item.member_id">
|
||||
<text class="line">|</text>
|
||||
<text>会员:{{ item.nickname }}</text>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="table-content">
|
||||
<view class="table-content-item" v-for="(goods, gindex) in item.order_goods" :key="gindex">
|
||||
<view class="content-item-left">
|
||||
<view class="content-item-img">
|
||||
<image v-if="goods.goods_class == 'money'" src="@/static/goods/goods.png"/>
|
||||
<image v-else-if="goods.goods_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png"/>
|
||||
<image v-else :src="$util.img(goods.goods_image, { size: 'small' })" @error="goods.goods_image = '@/static/goods/goods.png'"/>
|
||||
</view>
|
||||
<view class="content-item-info">
|
||||
<view class="content-item-name" v-if="goods.goods_class == 'money'">无码商品</view>
|
||||
<view class="content-item-name" v-else>
|
||||
<text>{{ goods.goods_name }}</text>
|
||||
<text>{{ goods.spec_name }}</text>
|
||||
</view>
|
||||
<view>¥{{ goods.price | moneyFormat }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="content-item-number">x {{ goods.num }}</view>
|
||||
<view class="content-item-price">¥{{ (goods.num * goods.price) | moneyFormat }}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="remark-info" v-if="item.remark">备注:{{ item.remark }}</view>
|
||||
<view class="table-bottom">
|
||||
<button class="default-btn btn-left" @click="deleteOrder(item.order_id)">删除</button>
|
||||
<button class="default-btn btn-left" @click="remarkSetting(item, index)">备注</button>
|
||||
<button class="primary-btn btn-right" @click="takeOrder(item)">取单</button>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
<view class="empty" v-if="!orderData.list.length || (orderData.list.length == 1 && orderId)">
|
||||
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
|
||||
<view class="tips">暂无挂单记录</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
</view>
|
||||
</uni-popup>
|
||||
<uni-popup ref="remarkPopup" type="center">
|
||||
<view class="remark-wrap">
|
||||
<view class="header">
|
||||
<text class="title">备注</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.remarkPopup.close()"></text>
|
||||
</view>
|
||||
<view class="body">
|
||||
<textarea v-model="remark" placeholder="填写备注信息" placeholder-class="placeholder-class" />
|
||||
</view>
|
||||
<view class="footer">
|
||||
<button type="default" class="primary-btn" @click="remarkConfirm">确认</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from './index.js';
|
||||
|
||||
export default {
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
127
addon/cashier/source/os/components/ns-promotion-popup/index.js
Executable file
127
addon/cashier/source/os/components/ns-promotion-popup/index.js
Executable file
@@ -0,0 +1,127 @@
|
||||
import {getAddonIsExist,getPromotionQrcode} from '@/api/promotion.js';
|
||||
export default {
|
||||
name: 'nsPromotionPopup',
|
||||
props: {
|
||||
pageName: {
|
||||
type: String,
|
||||
default: 'COUPON_DETAIL'
|
||||
},
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
qrParams:{
|
||||
page_name:'',
|
||||
option:'',
|
||||
app_type:'h5'
|
||||
},
|
||||
APPType:'h5',
|
||||
appTypeArray: [{
|
||||
text: 'H5',
|
||||
value: 'h5'
|
||||
}],
|
||||
qrData:{}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.qrParams.page_name = this.pageName
|
||||
this.getAddonIsExistFn()
|
||||
},
|
||||
methods:{
|
||||
getAddonIsExistFn(){
|
||||
getAddonIsExist().then(res=>{
|
||||
if(res.data.weapp){
|
||||
this.appTypeArray.push({text:'微信小程序',value:'weapp'})
|
||||
}
|
||||
if(res.data.aliapp){
|
||||
this.appTypeArray.push({text:'支付宝小程序',value:'aliapp'})
|
||||
}
|
||||
})
|
||||
},
|
||||
getPromotionQrcodeFn(){
|
||||
getPromotionQrcode(this.qrParams).then(res=>{
|
||||
this.qrData = Object.assign(this.qrData,res.data)
|
||||
this.$forceUpdate();
|
||||
})
|
||||
},
|
||||
open(option){
|
||||
this.qrParams.option = JSON.stringify(option)
|
||||
this.$refs.promotionPop.open()
|
||||
this.qrData={}
|
||||
this.appTypeArray.forEach((el)=>{
|
||||
this.qrParams.app_type = el.value
|
||||
this.getPromotionQrcodeFn()
|
||||
})
|
||||
|
||||
},
|
||||
//复制链接
|
||||
copyTextToClipboard(text) {
|
||||
uni.setClipboardData({
|
||||
data: text,
|
||||
success: function () {
|
||||
// 可以添加用户友好的提示,例如使用uni.showToast提示复制成功
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
},
|
||||
fail: function () {
|
||||
console.log('复制失败');
|
||||
// 可以添加错误处理或用户友好的提示
|
||||
}
|
||||
});
|
||||
},
|
||||
//下载二维码
|
||||
download(url){
|
||||
var oA = document.createElement("a");
|
||||
oA.innerHTML = '123'
|
||||
oA.download = ''; // 设置下载的文件名,默认是'下载'
|
||||
oA.target = "_blank"
|
||||
oA.href = url; //临时路径再保存到本地
|
||||
document.body.appendChild(oA);
|
||||
oA.click();
|
||||
oA.remove(); // 下载之后把创建的元素删除
|
||||
|
||||
}
|
||||
// download(url){
|
||||
// //下载文档
|
||||
// uni.downloadFile({
|
||||
// url: url,//下载地址接口返回
|
||||
// success: (data) => {
|
||||
// if (data.statusCode === 200) {
|
||||
// //文件保存到本地
|
||||
// uni.saveFile({
|
||||
// tempFilePath: data.tempFilePath, //临时路径
|
||||
// success: function(res) {
|
||||
// uni.showToast({
|
||||
// icon: 'none',
|
||||
// mask: true,
|
||||
// title: '文件已保存:' + res.savedFilePath, //保存路径
|
||||
// duration: 3000,
|
||||
// });
|
||||
// setTimeout(() => {
|
||||
// //打开文档查看
|
||||
// uni.openDocument({
|
||||
// filePath: res.savedFilePath,
|
||||
// success: function(res) {
|
||||
// // console.log('打开文档成功');
|
||||
// }
|
||||
// });
|
||||
// }, 3000)
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// fail: (err) => {
|
||||
// console.log(err);
|
||||
// uni.showToast({
|
||||
// icon: 'none',
|
||||
// mask: true,
|
||||
// title: '失败请重新下载',
|
||||
// });
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
}
|
||||
}
|
||||
76
addon/cashier/source/os/components/ns-promotion-popup/index.scss
Executable file
76
addon/cashier/source/os/components/ns-promotion-popup/index.scss
Executable file
@@ -0,0 +1,76 @@
|
||||
.promotion-pop{
|
||||
width: 7rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.06rem;
|
||||
.header{
|
||||
padding: 0.15rem 0.2rem;
|
||||
font-size: 0.14rem;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
|
||||
}
|
||||
.body{
|
||||
width: 100%;
|
||||
padding: 0.2rem 0.3rem;
|
||||
box-sizing: border-box;
|
||||
.alter{
|
||||
height: 0.48rem;
|
||||
line-height: 0.48rem;
|
||||
font-size: 0.14rem;
|
||||
padding: 0 0.2rem;
|
||||
color: #666;
|
||||
background-color: var(--primary-color-light-9);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.content{
|
||||
.qrCode{
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background-color: #f8f8f8;
|
||||
color: #333;
|
||||
font-size: 0.14rem;
|
||||
image{
|
||||
width:1.6rem;
|
||||
height:1.6rem;
|
||||
}
|
||||
}
|
||||
.right{
|
||||
margin-left: 0.2rem;
|
||||
.form-item{
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
.link {
|
||||
|
||||
.form-inline{
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
}
|
||||
input{
|
||||
width: 2rem;
|
||||
height: 0.3rem;
|
||||
border: 0.01rem solid #e6e6e6;
|
||||
padding: 0 0.12rem;
|
||||
font-size: 0.14rem;
|
||||
border-radius: 0.02rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.btn{
|
||||
background-color: var(--primary-color);
|
||||
color: #fff;
|
||||
margin-left: .1rem;
|
||||
font-size: 0.14rem;
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
&::after{
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
.download{
|
||||
color: var(--primary-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
60
addon/cashier/source/os/components/ns-promotion-popup/ns-promotion-popup.vue
Executable file
60
addon/cashier/source/os/components/ns-promotion-popup/ns-promotion-popup.vue
Executable file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<unipopup ref="promotionPop" type="center">
|
||||
<view class="promotion-pop">
|
||||
<view class="header flex justify-between">
|
||||
<view class="title">推广</view>
|
||||
<view class="pop-header-close" @click="$refs.promotionPop.close()">
|
||||
<text class="iconguanbi1 iconfont"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="body">
|
||||
<view class="alter">活动可分享至多个渠道推广,增加曝光率,提升分享打开率。</view>
|
||||
<view class="flex content">
|
||||
<view class="qrCode flex items-center justify-center">
|
||||
<image v-if="qrData[APPType]&&qrData[APPType].path" :src="$util.img(qrData[APPType].path)"/>
|
||||
<text v-else>小程序配置错误</text>
|
||||
</view>
|
||||
<view class="flex-1 right">
|
||||
<view class="form-box">
|
||||
<view class="form-content">
|
||||
<view class="form-item flex">
|
||||
<view class="form-label">充值方式:</view>
|
||||
<view class="form-inline">
|
||||
<uni-data-checkbox v-model="APPType" :localdata="appTypeArray" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item link" v-if="APPType == 'h5'&&qrData[APPType]&&qrData[APPType].url">
|
||||
<view class="form-label">
|
||||
推广链接:
|
||||
</view>
|
||||
<view class="form-inline flex items-center">
|
||||
<input type="text" disabled v-model="qrData[APPType].url" @keydown.enter="search('enter')" />
|
||||
<button type="default" class="btn" @click="copyTextToClipboard(qrData[APPType].url)">复制</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item" v-if="qrData[APPType]&&qrData[APPType].path">
|
||||
<text class="download" @click="download($util.img(qrData[APPType].path))">下载二维码</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</unipopup>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import unipopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import index from './index.js';
|
||||
export default {
|
||||
components: {
|
||||
unipopup,
|
||||
},
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
185
addon/cashier/source/os/components/ns-scale-goods/command.js
Executable file
185
addon/cashier/source/os/components/ns-scale-goods/command.js
Executable file
File diff suppressed because one or more lines are too long
384
addon/cashier/source/os/components/ns-scale-goods/ns-scale-goods.vue
Executable file
384
addon/cashier/source/os/components/ns-scale-goods/ns-scale-goods.vue
Executable file
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-popup ref="memberInquirePopup" type="center" @change="popupChange" :mask-click="false">
|
||||
<view class="popup-inquire-wrap">
|
||||
<view class="popup-header">
|
||||
<text class="title">称重商品同步到电子秤</text>
|
||||
<text class="iconfont iconguanbi1" @click="$refs.memberInquirePopup.close()"></text>
|
||||
</view>
|
||||
|
||||
<view class="popup-content">
|
||||
<view v-show="step == 1">
|
||||
<view class="content-title">选择商品</view>
|
||||
<uniDataTable url="/weighgoods/storeapi/goods/skuall" :cols="cols" :classType="true" @checkBox="checkBox" ref="goodsListTable" />
|
||||
</view>
|
||||
<view v-show="step == 2">
|
||||
<view class="content-title">选择需同步的电子秤</view>
|
||||
<uniDataTable url="/scale/storeapi/scale/page" :pagesize="0" :cols="scaleCols" :classType="true" ref="scaleListTable" @tableData="onloadScale" />
|
||||
</view>
|
||||
<view v-show="step == 3">
|
||||
<view class="content-title">同步商品到电子秤</view>
|
||||
<uniDataTable :cols="syncTaskCols" :classType="true" ref="syncTaskTable" :data="syncTask" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-footer" v-show="step == 1">
|
||||
<button type="default" class="default-btn" @click="next">下一步</button>
|
||||
</view>
|
||||
<view class="popup-footer" v-show="step == 2">
|
||||
<button type="default" class="default-btn" @click="step = 1">上一步</button>
|
||||
<button type="primary" class="primary-btn" @click="syncGoods">同步</button>
|
||||
</view>
|
||||
<view class="popup-footer" v-show="step == 3">
|
||||
<button type="default" class="primary-btn" :loading="synching" v-if="synching">同步中</button>
|
||||
<button type="default" class="primary-btn" :loading="synching" @click="$refs.memberInquirePopup.close()" v-else>完成</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
|
||||
import { getScaleList } from '@/api/scale.js';
|
||||
import {
|
||||
createCommand
|
||||
} from './command.js'
|
||||
|
||||
var self;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
uniDataTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
step: 1,
|
||||
cols: [{
|
||||
width: 6,
|
||||
align: 'center',
|
||||
checkbox: true
|
||||
},
|
||||
{
|
||||
field: 'account_data',
|
||||
width: 50,
|
||||
title: '商品信息',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
let img = this.$util.img(data.sku_image);
|
||||
let html = `
|
||||
<view class="goods-content">
|
||||
<image class="goods-img" src="${img}" mode="aspectFit"/>
|
||||
<text class="goods-name multi-hidden">${data.sku_name}</text>
|
||||
</view>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
title: '价格',
|
||||
align: 'center',
|
||||
templet: function(data) {
|
||||
return '¥' + data.price;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'plu',
|
||||
width: 10,
|
||||
title: 'PLU码',
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
title: '计价方式',
|
||||
align: 'center',
|
||||
templet: function(data) {
|
||||
if (data.pricing_type == 'num') {
|
||||
return '计数';
|
||||
} else {
|
||||
return '计重';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
width: 10,
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
templet: function(data) {
|
||||
var str = '';
|
||||
if (data.store_status == 1) {
|
||||
str = '销售中';
|
||||
} else if (data.store_status == 0) {
|
||||
str = '仓库中';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
],
|
||||
scaleCols: [{
|
||||
width: 6,
|
||||
align: 'center',
|
||||
checkbox: true,
|
||||
disabled: (data) => {
|
||||
return !data.connect_status
|
||||
}
|
||||
},
|
||||
{
|
||||
width: 24,
|
||||
title: '设备名称',
|
||||
align: 'left',
|
||||
field: 'name',
|
||||
},
|
||||
{
|
||||
width: 20,
|
||||
title: '设备品牌',
|
||||
align: 'center',
|
||||
field: 'brand_name',
|
||||
},
|
||||
{
|
||||
width: 20,
|
||||
title: '设备型号',
|
||||
align: 'center',
|
||||
field: 'model_name',
|
||||
},
|
||||
{
|
||||
width: 20,
|
||||
title: '状态',
|
||||
align: 'center',
|
||||
templet: (data) => {
|
||||
return data.connect_status ? '已连接' : '未连接'
|
||||
}
|
||||
}
|
||||
],
|
||||
syncTaskCols: [{
|
||||
width: 70,
|
||||
title: '设备名称',
|
||||
align: 'left',
|
||||
templet: (data) => {
|
||||
return data.name
|
||||
}
|
||||
},
|
||||
{
|
||||
width: 30,
|
||||
title: '同步状态',
|
||||
align: 'left',
|
||||
templet: (data) => {
|
||||
var str = '';
|
||||
switch (data.syncStatus) {
|
||||
case '1':
|
||||
str = `<view>同步成功</view>`;
|
||||
break;
|
||||
case '0':
|
||||
str = `<view>同步失败</view><view style="color: red;display:block;white-space: normal;">失败原因:${data.msg}</view>`;
|
||||
break;
|
||||
default:
|
||||
str = `<view>同步中</view>`;
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
],
|
||||
syncTask: {},
|
||||
synching: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getScaleListFn();
|
||||
self = this;
|
||||
},
|
||||
methods: {
|
||||
popupChange(e) {
|
||||
if (!e.show) {
|
||||
this.syncTask = {};
|
||||
this.synching = false;
|
||||
this.step = 1
|
||||
}
|
||||
},
|
||||
open() {
|
||||
this.$refs.memberInquirePopup.open();
|
||||
},
|
||||
selectScale(e) {
|
||||
this.scale = this.scaleList[e].name;
|
||||
this.scaleId = this.scaleList[e].scale_id
|
||||
},
|
||||
checkBox(e) {
|
||||
this.goodsList = e;
|
||||
},
|
||||
getScaleListFn() {
|
||||
if (!this.addon.includes('scale')) {
|
||||
return;
|
||||
}
|
||||
getScaleList({
|
||||
page: 1,
|
||||
page_size: 100
|
||||
}).then(res=>{
|
||||
if (res.data.list.length > 0) this.scaleList = res.data.list;
|
||||
});
|
||||
},
|
||||
next() {
|
||||
const selected = this.$refs.goodsListTable.selected;
|
||||
if (!selected.length) {
|
||||
this.$util.showToast({
|
||||
'title': '请选择要同步的商品'
|
||||
});
|
||||
return
|
||||
}
|
||||
this.step += 1;
|
||||
},
|
||||
onloadScale(list) {
|
||||
if (typeof window.POS_DATA_CALLBACK == 'function') delete window.POS_DATA_CALLBACK;
|
||||
|
||||
/**
|
||||
* 商品同步数据回调
|
||||
* @param {Object} text
|
||||
*/
|
||||
window.POS_DATA_CALLBACK = function(text) {
|
||||
let data = text.split(':');
|
||||
let index = parseInt(data[0]);
|
||||
|
||||
switch (data[1]) {
|
||||
case 'SyncGoodsPlu':
|
||||
self.$set(self.syncTask[index], 'syncStatus', data[2]);
|
||||
self.$set(self.syncTask[index], 'msg', data[4]);
|
||||
|
||||
if (index == self.syncTask.length - 1) {
|
||||
self.synching = false
|
||||
}
|
||||
break;
|
||||
case 'PingWeigher':
|
||||
self.$set(self.$refs.scaleListTable.list[index], 'connect_status', parseInt(data[3]));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let weigher = list.map(item => {
|
||||
item.config = JSON.parse(item.config);
|
||||
return item;
|
||||
});
|
||||
|
||||
try {
|
||||
this.$pos.send('PingWeigher', JSON.stringify({
|
||||
weigher
|
||||
}));
|
||||
} catch (e) {}
|
||||
},
|
||||
async syncGoods() {
|
||||
const selected = this.$refs.scaleListTable.selected;
|
||||
if (!selected.length) {
|
||||
this.$util.showToast({
|
||||
'title': '请选择要同步的设备'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (this.synching) return;
|
||||
this.synching = true;
|
||||
|
||||
this.syncTask = this.$refs.scaleListTable.selected
|
||||
this.step += 1;
|
||||
|
||||
setTimeout(() => {
|
||||
this.createSyncData()
|
||||
}, 100)
|
||||
},
|
||||
createSyncData() {
|
||||
let task = {};
|
||||
task.weigher = this.$refs.scaleListTable.selected.map(scale => {
|
||||
scale.config = typeof scale.config == 'string' ? JSON.parse(scale.config) : scale.config;
|
||||
scale.goodsList = this.$refs.goodsListTable.selected.map(sku => {
|
||||
return {
|
||||
sku_no: sku.sku_no,
|
||||
plu: sku.plu,
|
||||
price: sku.price,
|
||||
sku_name: sku.sku_name,
|
||||
pricing_type: sku.pricing_type,
|
||||
command: ''
|
||||
}
|
||||
});
|
||||
return scale;
|
||||
});
|
||||
|
||||
this.syncTask = task.weigher;
|
||||
|
||||
try {
|
||||
console.log(JSON.stringify(task));
|
||||
this.$pos.send('SyncGoodsPlu', JSON.stringify(task));
|
||||
} catch (e) {
|
||||
this.synching = false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-inquire-wrap {
|
||||
overflow: hidden;
|
||||
width: 9.55rem;
|
||||
height: 5.37rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.05rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0.15rem;
|
||||
height: 0.45rem;
|
||||
line-height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconfont {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
flex: 1;
|
||||
height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 0.1rem;
|
||||
|
||||
/deep/ .content {}
|
||||
|
||||
.content-title {
|
||||
margin-bottom: .1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
padding: 0.1rem;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
|
||||
button {
|
||||
width: 1rem;
|
||||
margin: 0 0 0 .15rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/deep/.goods-content {
|
||||
display: flex;
|
||||
|
||||
.goods-img {
|
||||
margin-right: 0.1rem;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.goods-name {
|
||||
white-space: pre-wrap;
|
||||
align-self: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.uni-select-lay-select {
|
||||
width: 2rem !important;
|
||||
height: 0.42rem !important;
|
||||
}
|
||||
</style>
|
||||
242
addon/cashier/source/os/components/ns-select-member/index.js
Executable file
242
addon/cashier/source/os/components/ns-select-member/index.js
Executable file
@@ -0,0 +1,242 @@
|
||||
import {getMemberList,getMemberInfoById, getMemberLevelList, addMember, searchMemberByMobile} from '@/api/member.js';
|
||||
import {mapGetters} from 'vuex';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchText: '',
|
||||
page: 1,
|
||||
memberList: [],
|
||||
memberId: '',
|
||||
memberData: {
|
||||
sex: 0,
|
||||
mobile: '',
|
||||
nickname: '',
|
||||
birthday: '',
|
||||
member_level: '',
|
||||
member_level_name: ''
|
||||
},
|
||||
memberLevelList: [], // 会员等级
|
||||
sex: [{
|
||||
text: '未知',
|
||||
value: 0
|
||||
}, {
|
||||
text: '男',
|
||||
value: 1
|
||||
}, {
|
||||
text: '女',
|
||||
value: 2
|
||||
}],
|
||||
memberType: 'login',
|
||||
flag: false,
|
||||
inputFocus: false,
|
||||
isPhone: false,
|
||||
searchFinish: false // 搜索是否完成
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getMemberLevel();
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['memberSearchWayConfig'])
|
||||
},
|
||||
watch: {
|
||||
memberSearchWayConfig: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if(newVal) {
|
||||
if(newVal.way == 'list'){
|
||||
this.getMemberListFn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
searchMemberInputBlur(){
|
||||
this.inputFocus = false;
|
||||
//强制聚焦处理
|
||||
if(this.memberType = 'login'){
|
||||
this.$nextTick(() => {
|
||||
this.inputFocus = true;
|
||||
});
|
||||
}
|
||||
},
|
||||
open(callback) {
|
||||
this.memberId = this.globalMemberInfo ? this.globalMemberInfo.member_id + '' : '';
|
||||
this.$refs.memberPopup.open('', callback);
|
||||
this.inputFocus = true;
|
||||
this.searchFinish = false;
|
||||
},
|
||||
// 查询会员列表
|
||||
searchMemberByMobileFn() {
|
||||
setTimeout(() => {
|
||||
if (!this.searchText) return false;
|
||||
searchMemberByMobile({
|
||||
mobile: this.searchText
|
||||
}).then((res) => {
|
||||
if (res.code >= 0) {
|
||||
this.$store.commit('app/setGlobalMemberInfo', res.data);
|
||||
this.initData();
|
||||
this.$refs.memberPopup.close();
|
||||
} else {
|
||||
if (res.data > 1) {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
return false;
|
||||
}
|
||||
var regex = /^1[3-9]\d{9}$/;
|
||||
if (res.data == 0 && regex.test(this.searchText)) {
|
||||
this.isPhone = true;
|
||||
this.$refs.emptyPopup.open();
|
||||
return false;
|
||||
}
|
||||
if (res.data == 0) {
|
||||
this.isPhone = false;
|
||||
this.$refs.emptyPopup.open();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 200)
|
||||
},
|
||||
getMemberInfo(memberId, callback) {
|
||||
this.memberId = memberId;
|
||||
getMemberInfoById(memberId).then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.$store.commit('app/setGlobalMemberInfo', res.data);
|
||||
if (callback) callback();
|
||||
this.initData();
|
||||
this.$refs.memberPopup.close();
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: '未获取到会员信息'
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
/******************************** 录入会员 ********************************/
|
||||
getMemberLevel() {
|
||||
this.memberLevelList = [];
|
||||
getMemberLevelList().then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
for (let i in res.data) {
|
||||
this.memberLevelList.push({
|
||||
label: res.data[i]['level_name'],
|
||||
value: res.data[i]['level_id'].toString(),
|
||||
disabled: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 选择会员等级
|
||||
selectMemberLevel(index, item) {
|
||||
if (index >= 0) {
|
||||
this.memberData.member_level = item.value;
|
||||
this.memberData.member_level_name = item.label;
|
||||
} else {
|
||||
this.memberData.member_level = '';
|
||||
this.memberData.member_level_name = '';
|
||||
}
|
||||
this.$forceUpdate();
|
||||
},
|
||||
// 选择时间
|
||||
changeTime(e) {
|
||||
this.memberData.birthday = e;
|
||||
},
|
||||
verify() {
|
||||
if (!this.memberData.mobile) {
|
||||
this.$util.showToast({
|
||||
title: '请输入会员手机号'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!this.$util.verifyMobile(this.memberData.mobile)) {
|
||||
this.$util.showToast({
|
||||
title: '请输入正确的手机号码'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// 确定录入
|
||||
addMemberFn() {
|
||||
if (this.verify()) {
|
||||
if (this.flag) return;
|
||||
this.flag = true;
|
||||
addMember(this.memberData).then(res => {
|
||||
if (res.code == 0 && res.data) {
|
||||
this.memberType = 'login';
|
||||
this.getMemberInfo(res.data)
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
this.flag = false;
|
||||
})
|
||||
}
|
||||
},
|
||||
closedFn() {
|
||||
this.memberType = "login";
|
||||
this.$refs.memberPopup.close();
|
||||
},
|
||||
memberEmptyRegister() {
|
||||
this.memberType = "register";
|
||||
this.memberData.mobile = this.searchText;
|
||||
this.$refs.emptyPopup.close();
|
||||
},
|
||||
initData() {
|
||||
this.searchText = '';
|
||||
this.memberData.sex = 0;
|
||||
this.memberData.mobile = '';
|
||||
this.memberData.nickname = '';
|
||||
this.memberData.birthday = '';
|
||||
this.memberData.member_level = '';
|
||||
this.memberData.member_level_name = '';
|
||||
},
|
||||
stayTuned() {
|
||||
this.$util.showToast({
|
||||
title: '敬请期待'
|
||||
});
|
||||
},
|
||||
getMemberListFn(isSearch){
|
||||
getMemberList({
|
||||
page: this.page,
|
||||
page_size: 12,
|
||||
search_text: this.searchText
|
||||
}).then((res)=>{
|
||||
if (res.code >= 0) {
|
||||
if (this.page == 1) this.memberList = [];
|
||||
this.memberList = this.memberList.concat(res.data.list);
|
||||
this.memberList.forEach((item) => {
|
||||
if (item.mobile) {
|
||||
if (this.userInfo && this.userInfo.is_admin == 0) {
|
||||
// 非管理员,不能查看会员手机号
|
||||
item.mobile = item.mobile.substring(0, 4 - 1) + '****' + item.mobile.substring(6 + 1);
|
||||
}
|
||||
} else {
|
||||
item.mobile = '--';
|
||||
}
|
||||
});
|
||||
|
||||
if (isSearch) {
|
||||
// 默认选中第一个搜索结果
|
||||
this.memberId = 0;
|
||||
if (this.memberList.length) {
|
||||
this.memberId = this.memberList[0].member_id;
|
||||
}
|
||||
}
|
||||
this.searchFinish = true;
|
||||
if (res.data.page_count >= this.page) this.page++;
|
||||
}
|
||||
})
|
||||
},
|
||||
searchMemberByList(){
|
||||
this.page = 1;
|
||||
this.getMemberListFn(Boolean(this.searchText));
|
||||
}
|
||||
}
|
||||
};
|
||||
333
addon/cashier/source/os/components/ns-select-member/index.scss
Executable file
333
addon/cashier/source/os/components/ns-select-member/index.scss
Executable file
@@ -0,0 +1,333 @@
|
||||
.member-inquire-wrap {
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 0.05rem;
|
||||
|
||||
.member-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0.15rem;
|
||||
height: 0.45rem;
|
||||
line-height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconfont {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
&.exact{
|
||||
width: 4rem;
|
||||
|
||||
.member-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.3rem 0.3rem;
|
||||
|
||||
.member-img{
|
||||
width: 0.75rem;
|
||||
height: 0.75rem;
|
||||
}
|
||||
.member-input{
|
||||
margin-top: .25rem;
|
||||
width: 100%;
|
||||
height: .4rem;
|
||||
line-height: .4rem;
|
||||
// border-radius: 0.02rem;
|
||||
padding: 0 0.1rem;
|
||||
border: 0.01rem solid $primary-color;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
button{
|
||||
// border-radius: 0.05rem;
|
||||
height: .4rem;
|
||||
line-height: .4rem;
|
||||
margin-top: 0.15rem;
|
||||
width: 100%;
|
||||
}
|
||||
.function-list{
|
||||
margin-top: .25rem;
|
||||
padding-top: .15rem;
|
||||
border-top: 0.01rem dashed #ccc;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.item-wrap{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
.item-icon{
|
||||
font-size: .25rem;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.list{
|
||||
width: 9.55rem;
|
||||
height: 5.37rem;
|
||||
|
||||
.member-content {
|
||||
padding: 0.1rem;
|
||||
|
||||
.search-warp {
|
||||
margin-left: 0.1rem;
|
||||
|
||||
.search-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.05rem;
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
padding-left: 0.1rem;
|
||||
width: 2.5rem;
|
||||
height: 0.4rem;
|
||||
line-height: 0.4rem;
|
||||
border: 0.01rem solid #dcdee2;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 2rem;
|
||||
height: 0.42rem;
|
||||
line-height: 0.42rem;
|
||||
color: #fff;
|
||||
font-size: $uni-font-size-base;
|
||||
margin: 0;
|
||||
|
||||
&:last-of-type {
|
||||
margin-left: 0.15rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-scroll-view-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: baseline;
|
||||
height: 430px;
|
||||
}
|
||||
|
||||
.member-list {
|
||||
.member-item {
|
||||
display: flex;
|
||||
padding: 0.13rem 0.15rem;
|
||||
margin: 0.1rem;
|
||||
width: 2.9rem;
|
||||
height: 1rem;
|
||||
background-color: #f5f5f5;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.05rem;
|
||||
&.active {
|
||||
background-color: $primary-color;
|
||||
.name,
|
||||
.phone,
|
||||
.other>view {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-child(3n + 3) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 0.45rem;
|
||||
height: 0.45rem;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex: 1;
|
||||
width: calc( 100% - 0.55rem );
|
||||
.name{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
text:nth-child(1) {
|
||||
font-size: $uni-font-size-lg;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.phone {
|
||||
font-size: $uni-font-size-sm;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.other {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: $uni-font-size-sm;
|
||||
|
||||
view {
|
||||
font-size: $uni-font-size-sm;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 录入会员
|
||||
.member-entering-wrap {
|
||||
width: 3.8rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.05rem;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 0.15rem;
|
||||
height: 0.45rem;
|
||||
line-height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconfont {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.form-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.2rem;
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 0.1rem;
|
||||
display: flex;
|
||||
|
||||
.form-label {
|
||||
width: 0.9rem;
|
||||
text-align: right;
|
||||
padding-right: 0.1rem;
|
||||
box-sizing: border-box;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
|
||||
.required {
|
||||
color: red;
|
||||
margin-right: 0.03rem;
|
||||
}
|
||||
}
|
||||
|
||||
.form-inline {
|
||||
width: 2.5rem;
|
||||
line-height: 0.32rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.form-input {
|
||||
border-width: 0.01rem;
|
||||
border-style: solid;
|
||||
background-color: #fff;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
border-radius: 0.02rem;
|
||||
padding-left: 0.1rem;
|
||||
height: 0.32rem;
|
||||
line-height: 0.32rem;
|
||||
font-size: 0.14rem;
|
||||
border-color: #e6e6e6;
|
||||
}
|
||||
|
||||
button {
|
||||
width: calc(50% - 0.05rem);
|
||||
display: inline-block;
|
||||
margin-right: 0.1rem;
|
||||
|
||||
&:nth-child(2) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.btn-wrap {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 0.1rem 0;
|
||||
.primary-btn {
|
||||
height: 0.4rem;
|
||||
line-height: 0.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
text-align: center;
|
||||
padding-top: 0.8rem;
|
||||
width: 100%;
|
||||
|
||||
image {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #999;
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.member-empty{
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 0.02rem;
|
||||
width: 3rem;
|
||||
.head{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: .2rem;
|
||||
height: .42rem;
|
||||
background-color: #f8f8f8;
|
||||
border-bottom: .01rem solid #eee;
|
||||
}
|
||||
.content{
|
||||
padding: .06rem .2rem 0;
|
||||
height: .6rem;
|
||||
line-height: .6rem;
|
||||
}
|
||||
.btn-wrap{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-right: .2rem;
|
||||
padding-bottom: .2rem;
|
||||
button{
|
||||
margin: 0;
|
||||
margin-left: .1rem;
|
||||
border-radius: .02rem;
|
||||
}
|
||||
.close-btn{
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
addon/cashier/source/os/components/ns-select-member/ns-select-member.vue
Executable file
154
addon/cashier/source/os/components/ns-select-member/ns-select-member.vue
Executable file
@@ -0,0 +1,154 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-popup ref="memberPopup" type="center" @maskClick="closedFn">
|
||||
<view class="member-inquire-wrap" :class="{ 'exact' : memberSearchWayConfig.way == 'exact','list' : memberSearchWayConfig.way == 'list' }" v-if="memberType == 'login'">
|
||||
<view class="member-header">
|
||||
<text class="title">{{ memberSearchWayConfig.way == 'exact' ? '会员查询' : '会员列表' }}</text>
|
||||
<text class="iconfont iconguanbi1" @click="closedFn"></text>
|
||||
</view>
|
||||
|
||||
<view class="member-content" v-if="memberSearchWayConfig.way == 'exact'">
|
||||
<image class="member-img" mode="aspectFill" src="@/static/member/head.png" />
|
||||
<input type="number" class="member-input" focus placeholder="请输入手机号或手机号后四位" placeholder-style="font-size:0.14rem" v-model="searchText" @confirm="searchMemberByMobileFn()" :focus="inputFocus" @focus="inputFocus = true" @blur="searchMemberInputBlur" />
|
||||
<button class="switch primary-btn" @click="searchMemberByMobileFn()">查询</button>
|
||||
<view class="function-list">
|
||||
<view class="item-wrap" @click="stayTuned">
|
||||
<text class="item-icon iconfont iconmenpos"></text>
|
||||
<text>刷卡登录</text>
|
||||
</view>
|
||||
<view class="item-wrap" @click="stayTuned">
|
||||
<!-- <image class="item-img" mode="aspectFill" src="@/static/member/head.png" /> -->
|
||||
<text class="item-icon iconfont iconsaomiaoerweima"></text>
|
||||
<text>扫码登录</text>
|
||||
</view>
|
||||
<view class="item-wrap" @click="stayTuned">
|
||||
<text class="item-icon iconfont iconhuaxiangfenxi"></text>
|
||||
<text>人脸登录</text>
|
||||
</view>
|
||||
<view class="item-wrap" @click="memberType = 'register'">
|
||||
<text class="item-icon iconfont iconhuiyuanzhucedengluguanli"></text>
|
||||
<text>会员注册</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="member-content" v-if="memberSearchWayConfig.way == 'list'">
|
||||
<view class="search-warp">
|
||||
<view class="search-input">
|
||||
<input focus placeholder="可查询会员账号、手机号、昵称" placeholder-style="font-size:0.14rem" v-model="searchText" @confirm="searchMemberByList()" :focus="inputFocus" @focus="inputFocus = true" @blur="searchMemberInputBlur" />
|
||||
<button class="switch primary-btn" @click="searchMemberByList()">查询 [Enter]</button>
|
||||
<button class="default-btn" plain="true" @click="memberType = 'register'">添加会员</button>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view @scrolltolower="getMemberListFn()" scroll-y="true" class="member-list">
|
||||
<view :class="['member-item', { active: item.member_id == memberId }]" v-for="(item, index) in memberList" :key="index" @click="getMemberInfo(item.member_id)">
|
||||
<image class="item-img" mode="aspectFill" v-if="item.headimg" :src="$util.img(item.headimg)" @error="item.headimg = defaultImg.head"/>
|
||||
<image class="item-img" mode="aspectFill" v-else :src="$util.img(defaultImg.head)"/>
|
||||
<view class="item-content">
|
||||
<view class="name">
|
||||
<text :title="item.nickname">{{ item.nickname }}</text>
|
||||
</view>
|
||||
<view class="phone">手机号:{{ item.mobile }}</view>
|
||||
<view class="other">
|
||||
<view>余额:{{ parseFloat(parseFloat(item.balance) + parseFloat(item.balance_money)).toFixed(2) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-show="memberList.length == 0" class="empty">
|
||||
<image :src="$util.img('public/uniapp/cashier/member-empty.png')" mode="widthFix"/>
|
||||
<view class="tips">暂无会员</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<view class="member-entering-wrap" v-if="memberType == 'register'">
|
||||
<view class="header">
|
||||
<text class="iconfont iconqianhou1" @click="memberType = 'login'"></text>
|
||||
<text class="title">录入会员</text>
|
||||
<text class="iconfont iconguanbi1" @click="closedFn"></text>
|
||||
</view>
|
||||
<view class="form-content">
|
||||
<view>
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
手机号:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input type="number" class="form-input" v-model="memberData.mobile" placeholder="请输入会员手机号" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员名称:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<input type="text" class="form-input" v-model="memberData.nickname" placeholder="请输入会员昵称" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
性别:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<uni-data-checkbox v-model="memberData.sex" :localdata="sex"/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
生日:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<uni-datetime-picker v-model="memberData.birthday" type="date" :clearIcon="false" @change="changeTime" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item" v-if="memberLevelList.length">
|
||||
<view class="form-label">
|
||||
<text class="required"></text>
|
||||
会员等级:
|
||||
</view>
|
||||
<view class="form-inline">
|
||||
<select-lay :zindex="10" :value="memberData.member_level" name="names" placeholder="请选择会员等级" :options="memberLevelList" @selectitem="selectMemberLevel"/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn-wrap">
|
||||
<button type="primary" class="primary-btn" @click="addMemberFn">确定录入</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
<uni-popup ref="emptyPopup" type="center">
|
||||
<view class="member-empty">
|
||||
<view class="head">提示</view>
|
||||
<view class="content">未找到顾客{{searchText}}</view>
|
||||
<view class="btn-wrap">
|
||||
<button class="close-btn" @click="$refs.emptyPopup.close()">关闭</button>
|
||||
<button class="primary-btn" v-if="isPhone" @click="memberEmptyRegister()">注册</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import index from './index.js';
|
||||
export default {
|
||||
mixins: [index]
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
146
addon/cashier/source/os/components/ns-update/ns-update.vue
Executable file
146
addon/cashier/source/os/components/ns-update/ns-update.vue
Executable file
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<view>
|
||||
<uni-popup ref="updatePopup" type="center" :maskClick="false" v-if="versionInfo">
|
||||
<view class="update-wrap">
|
||||
<view class="head"><image src="@/static/cashier/update_header.png" /></view>
|
||||
<view class="body">
|
||||
<view class="version-no">版本号:{{ versionInfo.version }}</view>
|
||||
<view class="title">更新内容</view>
|
||||
<view class="desc common-scrollbar">{{ versionInfo.update_desc }}</view>
|
||||
<button type="default" class="primary-btn" @click="update">立即更新</button>
|
||||
<view class="giveup-update" @click="giveupUpdate" v-if="!versionInfo.is_force_upgrade">以后再说</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* app版本更新
|
||||
*/
|
||||
import {checkUpdate} from '@/api/config.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
versionInfo: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
// wifi模式下才检测升级
|
||||
if (plus.networkinfo.getCurrentType() == plus.networkinfo.CONNECTION_WIFI) {
|
||||
this.checkUpdateFn();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 检测是否有新版本
|
||||
*/
|
||||
checkUpdateFn() {
|
||||
checkUpdate({
|
||||
app_key: this.$config.app.app_key,
|
||||
version: this.$config.app.version_no,
|
||||
platform: uni.getSystemInfoSync().platform
|
||||
}).then(res=>{
|
||||
if (res.code == 0 && res.data) {
|
||||
this.versionInfo = res.data;
|
||||
if (!uni.getStorageSync('version_' + this.versionInfo.version_no)) {
|
||||
this.$refs.updatePopup.open();
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 确认更新
|
||||
*/
|
||||
update() {
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
if (systemInfo.platform == 'android') {
|
||||
uni.showLoading({});
|
||||
uni.downloadFile({
|
||||
url: this.$util.img(this.versionInfo.package_path),
|
||||
success: data => {
|
||||
uni.hideLoading();
|
||||
if (data.statusCode === 200) {
|
||||
plus.runtime.install(
|
||||
data.tempFilePath,
|
||||
{
|
||||
force: false
|
||||
},
|
||||
function() {
|
||||
plus.runtime.restart();
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
fail: res => {
|
||||
this.$util.showToast({ title: '安装包下载失败' });
|
||||
uni.hideLoading();
|
||||
}
|
||||
});
|
||||
} else if (systemInfo.platform == 'ios') {
|
||||
plus.runtime.launchApplication({ action: this.versionInfo.package_path }, e => {
|
||||
this.$util.showToast({ title: e.message });
|
||||
this.$refs.updatePopup.close();
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 放弃本次更新
|
||||
*/
|
||||
giveupUpdate() {
|
||||
uni.setStorageSync('version_' + this.versionInfo.version_no, 1);
|
||||
this.$refs.updatePopup.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.update-wrap {
|
||||
width: 3rem;
|
||||
|
||||
.head {
|
||||
height: 0.98rem;
|
||||
|
||||
image {
|
||||
width: 3rem;
|
||||
height: 0.98rem;
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 0.2rem 0.3rem;
|
||||
background: #fff;
|
||||
|
||||
.version-no {
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
max-height: 1rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 0.16rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
margin-top: 0.15rem;
|
||||
}
|
||||
|
||||
.giveup-update {
|
||||
margin-top: 0.15rem;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/deep/ .uni-popup {
|
||||
z-index: 1010;
|
||||
}
|
||||
</style>
|
||||
220
addon/cashier/source/os/components/pick-regions/pick-regions.vue
Executable file
220
addon/cashier/source/os/components/pick-regions/pick-regions.vue
Executable file
@@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<view class="pick-regions">
|
||||
<picker mode="multiSelector" :value="multiIndex" :range="multiArray" @change="handleValueChange" @columnchange="handleColumnChange">
|
||||
<slot></slot>
|
||||
</picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getAreaList} from '@/api/address.js'
|
||||
export default {
|
||||
props: {
|
||||
defaultRegions: {
|
||||
type: Array
|
||||
},
|
||||
selectArr: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pickerValueArray: [],
|
||||
cityArr: [],
|
||||
districtArr: [],
|
||||
multiIndex: [0, 0, 0],
|
||||
isInitMultiArray: false,
|
||||
// 是否加载完默认地区
|
||||
isLoadDefaultAreas: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
defaultRegions: {
|
||||
handler(arr, oldArr = []) {
|
||||
// 避免传的是字面量的时候重复触发
|
||||
if (arr.length != this.selectArr || arr.join('') === oldArr.join('')) return;
|
||||
|
||||
this.handleDefaultRegions();
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
multiArray() {
|
||||
if (!this.isLoadDefaultAreas) return;
|
||||
var arr = this.pickedArr.map(arr => arr.map(item => item.label));
|
||||
return arr;
|
||||
},
|
||||
pickedArr() {
|
||||
// 进行初始化
|
||||
if (this.isInitMultiArray) {
|
||||
if (this.selectArr == '2') {
|
||||
return [this.pickerValueArray[0], this.pickerValueArray[1]];
|
||||
} else {
|
||||
return [this.pickerValueArray[0], this.pickerValueArray[1], this.pickerValueArray[2]];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectArr == '2') {
|
||||
return [this.pickerValueArray[0], this.cityArr];
|
||||
} else {
|
||||
return [this.pickerValueArray[0], this.cityArr, this.districtArr];
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDefaultAreas(0, { level: 0 });
|
||||
},
|
||||
methods: {
|
||||
async handleColumnChange(e) {
|
||||
this.isInitMultiArray = false;
|
||||
let col = e.detail.column;
|
||||
let row = e.detail.value;
|
||||
this.multiIndex[col] = row;
|
||||
switch (col) {
|
||||
case 0:
|
||||
//选择省,加载市、区县
|
||||
this.cityArr = await this.getAreasAsync(this.pickerValueArray[0][this.multiIndex[col]].value);
|
||||
this.districtArr = await this.getAreasAsync(this.cityArr[0].value);
|
||||
break;
|
||||
case 1:
|
||||
//选择市,加载区县
|
||||
this.districtArr = await this.getAreasAsync(this.cityArr[this.multiIndex[col]].value);
|
||||
break;
|
||||
case 2:
|
||||
if (!this.cityArr.length) this.cityArr = await this.getAreasAsync(this.pickerValueArray[0][0].value)
|
||||
if (!this.districtArr.length) this.districtArr = await this.getAreasAsync(this.cityArr[0].value);
|
||||
break;
|
||||
}
|
||||
},
|
||||
handleValueChange(e) {
|
||||
// 结构赋值
|
||||
let [index0, index1, index2] = e.detail.value;
|
||||
let [arr0, arr1, arr2] = this.pickedArr;
|
||||
let address = '';
|
||||
if (this.selectArr == '2') {
|
||||
address = [arr0[index0], arr1[index1]];
|
||||
} else {
|
||||
address = [arr0[index0], arr1[index1], arr2[index2]];
|
||||
}
|
||||
this.$emit('getRegions', address);
|
||||
},
|
||||
handleDefaultRegions() {
|
||||
var time = setInterval(() => {
|
||||
if (!this.isLoadDefaultAreas) return;
|
||||
this.isInitMultiArray = false;
|
||||
for (let i = 0; i < this.defaultRegions.length; i++) {
|
||||
for (let j = 0; j < this.pickerValueArray[i].length; j++) {
|
||||
// 匹配省
|
||||
if ( (this.defaultRegions[i] == this.pickerValueArray[i][j].value || this.defaultRegions[i] == this.pickerValueArray[i][j].label) && this.pickerValueArray[i][j].level == 1) {
|
||||
// 设置选中省
|
||||
this.$set(this.multiIndex, i, j);
|
||||
|
||||
// 查询市
|
||||
this.getAreas(this.pickerValueArray[i][j].value, data => {
|
||||
this.cityArr = data;
|
||||
|
||||
for (let k = 0; k < this.cityArr.length; k++) {
|
||||
if (this.defaultRegions[1] == this.cityArr[k].value || this.defaultRegions[1] == this.cityArr[k].label) {
|
||||
// 设置选中市
|
||||
this.$set(this.multiIndex, 1, k);
|
||||
|
||||
// 查询区县
|
||||
this.getAreas(this.cityArr[k].value, data => {
|
||||
this.districtArr = data;
|
||||
|
||||
// 设置选中区县
|
||||
for (let u = 0; u < this.districtArr.length; u++) {
|
||||
if (this.defaultRegions[2] == this.districtArr[u].value || this.defaultRegions[2] == this.districtArr[u].label) {
|
||||
this.$set(this.multiIndex, 2, u);
|
||||
this.handleValueChange({
|
||||
detail: {
|
||||
value: [j, k, u]
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.isLoadDefaultAreas) clearInterval(time);
|
||||
}, 100);
|
||||
},
|
||||
getDefaultAreas(pid, obj) {
|
||||
getAreaList({ pid: pid }).then(res=>{
|
||||
if (res.code == 0) {
|
||||
var data = [];
|
||||
var selected = undefined;
|
||||
res.data.forEach((item, index) => {
|
||||
if (obj != undefined) {
|
||||
if (obj.level == 0 && obj.province_id != undefined) {
|
||||
selected = obj.province_id;
|
||||
} else if (obj.level == 1 && obj.city_id != undefined) {
|
||||
selected = obj.city_id;
|
||||
} else if (obj.level == 2 && obj.district_id != undefined) {
|
||||
selected = obj.district_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected == undefined && index == 0) {
|
||||
selected = item.id;
|
||||
}
|
||||
data.push({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
level: item.level
|
||||
});
|
||||
});
|
||||
|
||||
this.pickerValueArray[obj.level] = data;
|
||||
if (obj.level + 1 < 3) {
|
||||
obj.level++;
|
||||
this.getDefaultAreas(selected, obj);
|
||||
} else {
|
||||
this.isInitMultiArray = true;
|
||||
this.isLoadDefaultAreas = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 同步获取地区
|
||||
async getAreasAsync(pid) {
|
||||
let res = await getAreaList({ pid: pid });
|
||||
if (res.code == 0) {
|
||||
var data = [];
|
||||
res.data.forEach((item, index) => {
|
||||
data.push({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
level: item.level
|
||||
});
|
||||
});
|
||||
return data;
|
||||
}
|
||||
},
|
||||
// 异步获取地区
|
||||
getAreas(pid, callback) {
|
||||
getAreaList({ pid: pid }).then(res=>{
|
||||
if (res.code == 0) {
|
||||
var data = [];
|
||||
res.data.forEach((item, index) => {
|
||||
data.push({
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
level: item.level
|
||||
});
|
||||
});
|
||||
if (callback) callback(data);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
201
addon/cashier/source/os/components/qiun-data-charts/license.md
Executable file
201
addon/cashier/source/os/components/qiun-data-charts/license.md
Executable file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
1598
addon/cashier/source/os/components/qiun-data-charts/qiun-data-charts.vue
Executable file
1598
addon/cashier/source/os/components/qiun-data-charts/qiun-data-charts.vue
Executable file
File diff suppressed because it is too large
Load Diff
44
addon/cashier/source/os/components/qiun-error/qiun-error.vue
Executable file
44
addon/cashier/source/os/components/qiun-error/qiun-error.vue
Executable file
File diff suppressed because one or more lines are too long
166
addon/cashier/source/os/components/qiun-loading/loading1.vue
Executable file
166
addon/cashier/source/os/components/qiun-loading/loading1.vue
Executable file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<view class="container loading1">
|
||||
<view class="shape shape1"></view>
|
||||
<view class="shape shape2"></view>
|
||||
<view class="shape shape3"></view>
|
||||
<view class="shape shape4"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading1',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped="true">
|
||||
.container {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container.loading1 {
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.container .shape {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.container .shape.shape1 {
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.container .shape.shape2 {
|
||||
right: 0;
|
||||
background-color: #91CB74;
|
||||
}
|
||||
|
||||
.container .shape.shape3 {
|
||||
bottom: 0;
|
||||
background-color: #FAC858;
|
||||
}
|
||||
|
||||
.container .shape.shape4 {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: #EE6666;
|
||||
}
|
||||
|
||||
.loading1 .shape1 {
|
||||
-webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
|
||||
animation: animation1shape1 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation1shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(16px, 16px);
|
||||
transform: translate(16px, 16px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation1shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(16px, 16px);
|
||||
transform: translate(16px, 16px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading1 .shape2 {
|
||||
-webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
|
||||
animation: animation1shape2 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation1shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-16px, 16px);
|
||||
transform: translate(-16px, 16px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation1shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-16px, 16px);
|
||||
transform: translate(-16px, 16px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading1 .shape3 {
|
||||
-webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
|
||||
animation: animation1shape3 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation1shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(16px, -16px);
|
||||
transform: translate(16px, -16px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation1shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(16px, -16px);
|
||||
transform: translate(16px, -16px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading1 .shape4 {
|
||||
-webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
|
||||
animation: animation1shape4 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation1shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-16px, -16px);
|
||||
transform: translate(-16px, -16px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation1shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-16px, -16px);
|
||||
transform: translate(-16px, -16px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
176
addon/cashier/source/os/components/qiun-loading/loading2.vue
Executable file
176
addon/cashier/source/os/components/qiun-loading/loading2.vue
Executable file
@@ -0,0 +1,176 @@
|
||||
<template>
|
||||
<view class="container loading2">
|
||||
<view class="shape shape1"></view>
|
||||
<view class="shape shape2"></view>
|
||||
<view class="shape shape3"></view>
|
||||
<view class="shape shape4"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading2',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped="true">
|
||||
.container {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container.loading2 {
|
||||
-webkit-transform: rotate(10deg);
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
|
||||
.container.loading2 .shape {
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.container.loading2 {
|
||||
-webkit-animation: rotation 1s infinite;
|
||||
animation: rotation 1s infinite;
|
||||
}
|
||||
|
||||
.container .shape {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.container .shape.shape1 {
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.container .shape.shape2 {
|
||||
right: 0;
|
||||
background-color: #91CB74;
|
||||
}
|
||||
|
||||
.container .shape.shape3 {
|
||||
bottom: 0;
|
||||
background-color: #FAC858;
|
||||
}
|
||||
|
||||
.container .shape.shape4 {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: #EE6666;
|
||||
}
|
||||
|
||||
|
||||
.loading2 .shape1 {
|
||||
-webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
|
||||
animation: animation2shape1 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation2shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(20px, 20px);
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation2shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(20px, 20px);
|
||||
transform: translate(20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading2 .shape2 {
|
||||
-webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
|
||||
animation: animation2shape2 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation2shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-20px, 20px);
|
||||
transform: translate(-20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation2shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-20px, 20px);
|
||||
transform: translate(-20px, 20px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading2 .shape3 {
|
||||
-webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
|
||||
animation: animation2shape3 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation2shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(20px, -20px);
|
||||
transform: translate(20px, -20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation2shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(20px, -20px);
|
||||
transform: translate(20px, -20px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading2 .shape4 {
|
||||
-webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
|
||||
animation: animation2shape4 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation2shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-20px, -20px);
|
||||
transform: translate(-20px, -20px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation2shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-20px, -20px);
|
||||
transform: translate(-20px, -20px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
182
addon/cashier/source/os/components/qiun-loading/loading3.vue
Executable file
182
addon/cashier/source/os/components/qiun-loading/loading3.vue
Executable file
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<view class="container loading3">
|
||||
<view class="shape shape1"></view>
|
||||
<view class="shape shape2"></view>
|
||||
<view class="shape shape3"></view>
|
||||
<view class="shape shape4"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading3',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped="true">
|
||||
.container {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container.loading3 {
|
||||
-webkit-animation: rotation 1s infinite;
|
||||
animation: rotation 1s infinite;
|
||||
}
|
||||
|
||||
.container.loading3 .shape1 {
|
||||
border-top-left-radius: 10px;
|
||||
}
|
||||
|
||||
.container.loading3 .shape2 {
|
||||
border-top-right-radius: 10px;
|
||||
}
|
||||
|
||||
.container.loading3 .shape3 {
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
.container.loading3 .shape4 {
|
||||
border-bottom-right-radius: 10px;
|
||||
}
|
||||
|
||||
.container .shape {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.container .shape.shape1 {
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.container .shape.shape2 {
|
||||
right: 0;
|
||||
background-color: #91CB74;
|
||||
}
|
||||
|
||||
.container .shape.shape3 {
|
||||
bottom: 0;
|
||||
background-color: #FAC858;
|
||||
}
|
||||
|
||||
.container .shape.shape4 {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: #EE6666;
|
||||
}
|
||||
|
||||
.loading3 .shape1 {
|
||||
-webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
|
||||
animation: animation3shape1 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation3shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(5px, 5px);
|
||||
transform: translate(5px, 5px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation3shape1 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(5px, 5px);
|
||||
transform: translate(5px, 5px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading3 .shape2 {
|
||||
-webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
|
||||
animation: animation3shape2 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation3shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-5px, 5px);
|
||||
transform: translate(-5px, 5px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation3shape2 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-5px, 5px);
|
||||
transform: translate(-5px, 5px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading3 .shape3 {
|
||||
-webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
|
||||
animation: animation3shape3 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation3shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(5px, -5px);
|
||||
transform: translate(5px, -5px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation3shape3 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(5px, -5px);
|
||||
transform: translate(5px, -5px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading3 .shape4 {
|
||||
-webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
|
||||
animation: animation3shape4 0.5s ease 0s infinite alternate;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation3shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-5px, -5px);
|
||||
transform: translate(-5px, -5px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation3shape4 {
|
||||
from {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
to {
|
||||
-webkit-transform: translate(-5px, -5px);
|
||||
transform: translate(-5px, -5px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
227
addon/cashier/source/os/components/qiun-loading/loading4.vue
Executable file
227
addon/cashier/source/os/components/qiun-loading/loading4.vue
Executable file
@@ -0,0 +1,227 @@
|
||||
<template>
|
||||
<view class="container loading5">
|
||||
<view class="shape shape1"></view>
|
||||
<view class="shape shape2"></view>
|
||||
<view class="shape shape3"></view>
|
||||
<view class="shape shape4"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading5',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped="true">
|
||||
.container {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container.loading5 .shape {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.container .shape {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.container .shape.shape1 {
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.container .shape.shape2 {
|
||||
right: 0;
|
||||
background-color: #91CB74;
|
||||
}
|
||||
|
||||
.container .shape.shape3 {
|
||||
bottom: 0;
|
||||
background-color: #FAC858;
|
||||
}
|
||||
|
||||
.container .shape.shape4 {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: #EE6666;
|
||||
}
|
||||
|
||||
.loading5 .shape1 {
|
||||
animation: animation5shape1 2s ease 0s infinite reverse;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation5shape1 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, 15px);
|
||||
transform: translate(0, 15px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(15px, 15px);
|
||||
transform: translate(15px, 15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(15px, 0);
|
||||
transform: translate(15px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation5shape1 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, 15px);
|
||||
transform: translate(0, 15px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(15px, 15px);
|
||||
transform: translate(15px, 15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(15px, 0);
|
||||
transform: translate(15px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading5 .shape2 {
|
||||
animation: animation5shape2 2s ease 0s infinite reverse;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation5shape2 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(-15px, 0);
|
||||
transform: translate(-15px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-15px, 15px);
|
||||
transform: translate(-15px, 15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, 15px);
|
||||
transform: translate(0, 15px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation5shape2 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(-15px, 0);
|
||||
transform: translate(-15px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-15px, 15px);
|
||||
transform: translate(-15px, 15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, 15px);
|
||||
transform: translate(0, 15px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading5 .shape3 {
|
||||
animation: animation5shape3 2s ease 0s infinite reverse;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation5shape3 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(15px, 0);
|
||||
transform: translate(15px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(15px, -15px);
|
||||
transform: translate(15px, -15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, -15px);
|
||||
transform: translate(0, -15px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation5shape3 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(15px, 0);
|
||||
transform: translate(15px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(15px, -15px);
|
||||
transform: translate(15px, -15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, -15px);
|
||||
transform: translate(0, -15px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading5 .shape4 {
|
||||
animation: animation5shape4 2s ease 0s infinite reverse;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation5shape4 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, -15px);
|
||||
transform: translate(0, -15px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-15px, -15px);
|
||||
transform: translate(-15px, -15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(-15px, 0);
|
||||
transform: translate(-15px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation5shape4 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, -15px);
|
||||
transform: translate(0, -15px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-15px, -15px);
|
||||
transform: translate(-15px, -15px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(-15px, 0);
|
||||
transform: translate(-15px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
235
addon/cashier/source/os/components/qiun-loading/loading5.vue
Executable file
235
addon/cashier/source/os/components/qiun-loading/loading5.vue
Executable file
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<view class="container loading6">
|
||||
<view class="shape shape1"></view>
|
||||
<view class="shape shape2"></view>
|
||||
<view class="shape shape3"></view>
|
||||
<view class="shape shape4"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'loading6',
|
||||
data() {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped="true">
|
||||
.container {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container.loading6 {
|
||||
-webkit-animation: rotation 1s infinite;
|
||||
animation: rotation 1s infinite;
|
||||
}
|
||||
|
||||
.container.loading6 .shape {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.container .shape {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.container .shape.shape1 {
|
||||
left: 0;
|
||||
background-color: #1890FF;
|
||||
}
|
||||
|
||||
.container .shape.shape2 {
|
||||
right: 0;
|
||||
background-color: #91CB74;
|
||||
}
|
||||
|
||||
.container .shape.shape3 {
|
||||
bottom: 0;
|
||||
background-color: #FAC858;
|
||||
}
|
||||
|
||||
.container .shape.shape4 {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background-color: #EE6666;
|
||||
}
|
||||
|
||||
.loading6 .shape1 {
|
||||
-webkit-animation: animation6shape1 2s linear 0s infinite normal;
|
||||
animation: animation6shape1 2s linear 0s infinite normal;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation6shape1 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, 18px);
|
||||
transform: translate(0, 18px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(18px, 18px);
|
||||
transform: translate(18px, 18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(18px, 0);
|
||||
transform: translate(18px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation6shape1 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, 18px);
|
||||
transform: translate(0, 18px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(18px, 18px);
|
||||
transform: translate(18px, 18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(18px, 0);
|
||||
transform: translate(18px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.loading6 .shape2 {
|
||||
-webkit-animation: animation6shape2 2s linear 0s infinite normal;
|
||||
animation: animation6shape2 2s linear 0s infinite normal;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation6shape2 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(-18px, 0);
|
||||
transform: translate(-18px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-18px, 18px);
|
||||
transform: translate(-18px, 18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, 18px);
|
||||
transform: translate(0, 18px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation6shape2 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(-18px, 0);
|
||||
transform: translate(-18px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-18px, 18px);
|
||||
transform: translate(-18px, 18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, 18px);
|
||||
transform: translate(0, 18px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading6 .shape3 {
|
||||
-webkit-animation: animation6shape3 2s linear 0s infinite normal;
|
||||
animation: animation6shape3 2s linear 0s infinite normal;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation6shape3 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(18px, 0);
|
||||
transform: translate(18px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(18px, -18px);
|
||||
transform: translate(18px, -18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, -18px);
|
||||
transform: translate(0, -18px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation6shape3 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(18px, 0);
|
||||
transform: translate(18px, 0);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(18px, -18px);
|
||||
transform: translate(18px, -18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(0, -18px);
|
||||
transform: translate(0, -18px);
|
||||
}
|
||||
}
|
||||
|
||||
.loading6 .shape4 {
|
||||
-webkit-animation: animation6shape4 2s linear 0s infinite normal;
|
||||
animation: animation6shape4 2s linear 0s infinite normal;
|
||||
}
|
||||
|
||||
@-webkit-keyframes animation6shape4 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, -18px);
|
||||
transform: translate(0, -18px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-18px, -18px);
|
||||
transform: translate(-18px, -18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(-18px, 0);
|
||||
transform: translate(-18px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animation6shape4 {
|
||||
0% {
|
||||
-webkit-transform: translate(0, 0);
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
25% {
|
||||
-webkit-transform: translate(0, -18px);
|
||||
transform: translate(0, -18px);
|
||||
}
|
||||
50% {
|
||||
-webkit-transform: translate(-18px, -18px);
|
||||
transform: translate(-18px, -18px);
|
||||
}
|
||||
75% {
|
||||
-webkit-transform: translate(-18px, 0);
|
||||
transform: translate(-18px, 0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
34
addon/cashier/source/os/components/qiun-loading/qiun-loading.vue
Executable file
34
addon/cashier/source/os/components/qiun-loading/qiun-loading.vue
Executable file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<view>
|
||||
<Loading1 v-if="loadingType==1" />
|
||||
<Loading2 v-if="loadingType==2" />
|
||||
<Loading3 v-if="loadingType==3" />
|
||||
<Loading4 v-if="loadingType==4" />
|
||||
<Loading5 v-if="loadingType==5" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Loading1 from "./loading1.vue";
|
||||
import Loading2 from "./loading2.vue";
|
||||
import Loading3 from "./loading3.vue";
|
||||
import Loading4 from "./loading4.vue";
|
||||
import Loading5 from "./loading5.vue";
|
||||
|
||||
export default {
|
||||
components: {Loading1, Loading2, Loading3, Loading4, Loading5},
|
||||
name: 'qiun-loading',
|
||||
props: {
|
||||
loadingType: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
455
addon/cashier/source/os/components/select-lay/select-lay.vue
Executable file
455
addon/cashier/source/os/components/select-lay/select-lay.vue
Executable file
@@ -0,0 +1,455 @@
|
||||
<template>
|
||||
<view class="uni-select-lay" :style="{ 'z-index': zindex }">
|
||||
<input type="text" :name="name" v-model="value" class="uni-select-input" readonly />
|
||||
<view class="uni-select-lay-select" :class="{ active: active }">
|
||||
<!-- 禁用mask -->
|
||||
<view class="uni-disabled" v-if="disabled"></view>
|
||||
<!-- 禁用mask -->
|
||||
<!-- 清空 -->
|
||||
<view class="uni-select-lay-input-close" v-if="changevalue != '' && this.active"><text @click.stop="removevalue"></text></view>
|
||||
<!-- 清空 -->
|
||||
<input
|
||||
type="text"
|
||||
readonly
|
||||
disabled="true"
|
||||
class="uni-select-lay-input"
|
||||
:class="{ active: changevalue != '' && changevalue != placeholder }"
|
||||
v-model="changevalue"
|
||||
:placeholder="placeholder"
|
||||
@focus="unifocus"
|
||||
@input="intchange"
|
||||
@blur="uniblur"
|
||||
@click.stop="select"
|
||||
/>
|
||||
<view class="uni-select-lay-icon" :class="{ disabled: disabled }" @click.stop="select"><text></text></view>
|
||||
</view>
|
||||
<view class="uni-date-mask" v-show="active" @click.stop="select"></view>
|
||||
<scroll-view class="uni-select-lay-options" :scroll-y="true" v-show="active" @scroll="selectmove" @touchstart="movetouch">
|
||||
<template v-if="!changes">
|
||||
<view class="uni-select-lay-item" v-if="showplaceholder" :class="{ active: value == '' }" @click.stop="selectitem(-1, null)">{{ placeholder }}</view>
|
||||
<view class="uni-select-lay-item" :class="{ active: value == item[svalue], disabled: item.disabled }" v-for="(item, index) in options" :key="index" @click.stop="selectitem(index, item)">
|
||||
{{ item[slabel] }}
|
||||
</view>
|
||||
</template>
|
||||
<!-- 搜索 -->
|
||||
<template v-else>
|
||||
<template v-if="vlist.length > 0">
|
||||
<view class="uni-select-lay-item" :class="{ active: value == item[svalue] }" v-for="(item, index) in vlist" :key="index" @click.stop="selectitem(index, item)">
|
||||
{{ item[slabel] }}
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view class="nosearch">{{ changesValue }}</view>
|
||||
</template>
|
||||
</template>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'select-lay',
|
||||
props: {
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
zindex: {
|
||||
type: Number,
|
||||
default: 999
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
value: {
|
||||
type: [String,Number],
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
showplaceholder: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
slabel: {
|
||||
type: String,
|
||||
default: 'label'
|
||||
},
|
||||
svalue: {
|
||||
type: String,
|
||||
default: 'value'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
active: false, //组件是否激活,
|
||||
isfocus: false, //是否有焦点
|
||||
isremove: false, //是否是因为点击清空才导致的失去焦点
|
||||
ismove: false, //是否是因为移动才失去焦点
|
||||
changevalue: '', //搜索框同步
|
||||
oldvalue: '', //数据回滚
|
||||
changes: false, //正在搜索
|
||||
changesValue: '',
|
||||
vlist: [], //搜索框查询的列表
|
||||
settimer: null //value改变定时器
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.itemcheck();
|
||||
},
|
||||
watch: {
|
||||
//value改变
|
||||
value() {
|
||||
this.itemcheck();
|
||||
},
|
||||
//初始化数组
|
||||
options() {
|
||||
// 此处判断是否有初始value,存在则判断显示文字
|
||||
this.itemcheck();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//判断数组跟当前active值
|
||||
itemcheck() {
|
||||
// 此处判断是否有初始value,存在则判断显示文字
|
||||
if (this.value != '') {
|
||||
// 展示plachhoder
|
||||
//判断数组
|
||||
if (this.options.length > 0) {
|
||||
this.options.forEach(item => {
|
||||
if (this.value == item[this.svalue]) {
|
||||
this.oldvalue = this.changevalue = item[this.slabel];
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.oldvalue = this.changevalue = '';
|
||||
}
|
||||
},
|
||||
//点击组件
|
||||
select() {
|
||||
if (this.disabled) return;
|
||||
this.active = !this.active;
|
||||
if (this.active) {
|
||||
this.changes = false;
|
||||
} else {
|
||||
this.changevalue = this.oldvalue;
|
||||
}
|
||||
},
|
||||
// 获得焦点
|
||||
unifocus() {
|
||||
if (this.disabled) return;
|
||||
this.active = true;
|
||||
this.changes = false;
|
||||
this.isfocus = true;
|
||||
},
|
||||
// 失去焦点
|
||||
uniblur() {
|
||||
this.isfocus = false;
|
||||
// bug 点击组件列会先触发失去焦点,此时组件列事件不执行
|
||||
setTimeout(() => {
|
||||
if (this.isremove || this.ismove) {
|
||||
this.isremove = false;
|
||||
this.ismove = false;
|
||||
} else {
|
||||
this.changevalue = this.oldvalue;
|
||||
this.isremove = false;
|
||||
this.active = false;
|
||||
}
|
||||
}, 153);
|
||||
},
|
||||
movetouch() {
|
||||
setTimeout(() => {
|
||||
if (this.isfocus) {
|
||||
this.ismove = false;
|
||||
return;
|
||||
}
|
||||
if (!this.ismove) this.ismove = true;
|
||||
}, 100);
|
||||
// this.changes = false;
|
||||
},
|
||||
selectmove() {
|
||||
setTimeout(() => {
|
||||
if (this.isfocus) {
|
||||
this.ismove = false;
|
||||
return;
|
||||
}
|
||||
if (!this.ismove) this.ismove = true;
|
||||
}, 100);
|
||||
|
||||
// this.changes = false;
|
||||
},
|
||||
//移除数据
|
||||
removevalue() {
|
||||
this.isremove = true;
|
||||
this.changes = false;
|
||||
this.changevalue = '';
|
||||
},
|
||||
//value 改变
|
||||
intchange() {
|
||||
if (this.changevalue == '') {
|
||||
this.changes = false;
|
||||
return;
|
||||
}
|
||||
if (this.oldvalue == this.changevalue) {
|
||||
return;
|
||||
}
|
||||
this.vlist = [];
|
||||
this.changes = true;
|
||||
this.changesValue = '正在搜索...';
|
||||
if (this.settimer) {
|
||||
clearTimeout(this.settimer);
|
||||
}
|
||||
this.settimer = setTimeout(() => {
|
||||
this.vlist = this.options.filter(item => {
|
||||
return item[this.slabel].includes(this.changevalue);
|
||||
});
|
||||
if (this.vlist.length === 0) {
|
||||
this.changesValue = '暂无匹配内容!';
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
|
||||
//点击组件列
|
||||
selectitem(index, item) {
|
||||
if (item && item.disabled) {
|
||||
return false;
|
||||
}
|
||||
this.changevalue = this.oldvalue;
|
||||
this.active = false;
|
||||
this.$emit('selectitem', index, item);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uni-select-lay {
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
box-sizing: border-box;
|
||||
.uni-select-input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
z-index: -111;
|
||||
}
|
||||
|
||||
// select部分
|
||||
.uni-select-lay-select {
|
||||
user-select: none;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
height: 0.32rem;
|
||||
padding: 0 0.3rem 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.02rem;
|
||||
border: 0.01rem solid rgb(229, 229, 229);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 0.14rem;
|
||||
color: #999;
|
||||
|
||||
.uni-disabled {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 19;
|
||||
cursor: no-drop;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
// input 框的清除按钮
|
||||
.uni-select-lay-input-close {
|
||||
position: absolute;
|
||||
right: 0.35rem;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 0.15rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 3;
|
||||
cursor: pointer;
|
||||
|
||||
text {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
width: 0.13rem;
|
||||
height: 0.13rem;
|
||||
border-radius: 50%;
|
||||
border: 0.01rem solid #bbb;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 20%;
|
||||
top: 50%;
|
||||
height: 0.01rem;
|
||||
width: 60%;
|
||||
transform: rotate(45deg);
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
&::after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uni-select-lay-input {
|
||||
font-size: 0.14rem;
|
||||
color: #999;
|
||||
display: block;
|
||||
width: 98%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 0.3rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.active {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.uni-select-lay-icon {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 0.01rem;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
text {
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 0.07rem 0.07rem 0;
|
||||
border-style: solid;
|
||||
border-color: #bbb transparent transparent;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: no-drop;
|
||||
|
||||
text {
|
||||
width: 0.2rem;
|
||||
height: 0.2rem;
|
||||
border: 0.02rem solid #ff0000;
|
||||
border-radius: 50%;
|
||||
transition: 0.3s;
|
||||
position: relative;
|
||||
z-index: 999;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 0.02rem;
|
||||
margin-top: -0.01rem;
|
||||
background-color: #ff0000;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.active .uni-select-lay-icon {
|
||||
text {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// options部分
|
||||
.uni-select-lay-options {
|
||||
user-select: none;
|
||||
position: absolute;
|
||||
top: calc(100% + 0.05rem);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
// height: 500rpx;
|
||||
max-height: 2.5rem;
|
||||
// overflow-y: auto;
|
||||
border-radius: 0.02rem;
|
||||
border: 1px solid rgb(229, 229, 229);
|
||||
background: #fff;
|
||||
padding: 0.05rem 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 9;
|
||||
|
||||
.uni-select-lay-item {
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
line-height: 2.5;
|
||||
transition: 0.3s;
|
||||
font-size: 0.14rem;
|
||||
|
||||
&.active {
|
||||
background: $primary-color;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: $primary-color;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.nosearch {
|
||||
font-size: 0.16rem;
|
||||
line-height: 3;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
}
|
||||
.uni-date-mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 8;
|
||||
}
|
||||
</style>
|
||||
480
addon/cashier/source/os/components/stock-goods-dialog/stock-goods-dialog.vue
Executable file
480
addon/cashier/source/os/components/stock-goods-dialog/stock-goods-dialog.vue
Executable file
@@ -0,0 +1,480 @@
|
||||
<template>
|
||||
<unipopup ref="dialogRef" type="center" :maskClick="false">
|
||||
<view class="stock-dialog-wrap">
|
||||
<view class="stock-dialog-head">
|
||||
<text>商品选择</text>
|
||||
<text class="iconfont iconguanbi1" @click="$emit('change', false)"></text>
|
||||
</view>
|
||||
<view class="stock-dialog-body">
|
||||
<view class="tree">
|
||||
<scroll-view scroll-y="true" class="list-wrap">
|
||||
<view class="item" :class="{ 'active': option.category_id === '' }" @click="itemClick({ category_id: '', child_num: 0 })">
|
||||
<view class="icon"></view>
|
||||
<view>全部分类</view>
|
||||
</view>
|
||||
<view v-for="(item, key) in goodsCategoryList" :key="key">
|
||||
<view class="item" :class="{ 'active': option.category_id === item.category_id }" @click="itemClick(item)">
|
||||
<view class="icon" :class="{ 'active': activeList.indexOf(item.category_id) != -1 }">
|
||||
<text v-if="item.child_num" class="iconfont iconsanjiao_xia"></text>
|
||||
</view>
|
||||
<view>{{ item.title }}</view>
|
||||
</view>
|
||||
<template v-if="item.child_num">
|
||||
<view v-show="activeList.indexOf(item.category_id) != -1" v-for="(item2, key2) in item.children" :key="key2" class="level">
|
||||
<view class="item" :class="{ 'active': option.category_id === item2.category_id }" @click="itemClick(item2)">
|
||||
<view class="icon" :class="{ 'active': activeList.indexOf(item2.category_id) != -1 }">
|
||||
<text v-if="item2.child_num" class="iconfont iconsanjiao_xia"></text>
|
||||
</view>
|
||||
<view>{{ item2.title }}</view>
|
||||
</view>
|
||||
<template>
|
||||
<view v-show="activeList.indexOf(item2.category_id) != -1" v-for="(item3, key3) in item2.children" :key="key3" class="level">
|
||||
<view class="item item2" @click="itemClick(item3)">
|
||||
<view class="icon"></view>
|
||||
<view>{{ item3.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<view class="stock-dialog-table">
|
||||
<view class="search common-form">
|
||||
<view class="common-form-item">
|
||||
<view class="form-inline">
|
||||
<view class="form-input-inline">
|
||||
<input type="text" v-model="option.search_text" @confirm="getStoreGoods" placeholder="请输入产品名称/规格/编码" class="form-input" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-inline common-btn-wrap">
|
||||
<button type="default" class="screen-btn" @click="getStoreGoods">筛选</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<uniDataTable :url="url" :option="option" :cols="cols" :pagesize="8" ref="goodsListTable" @checkBox="checkBox" @tableData="tableDataChange"></uniDataTable>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="btn">
|
||||
<button type="primary" class="default-btn submit" @click="submit('close')">选中</button>
|
||||
<button type="primary" class="default-btn" @click="$emit('change', false)">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</unipopup>
|
||||
</template>
|
||||
<script>
|
||||
import unipopup from '@/components/uni-popup/uni-popup.vue';
|
||||
import uniDataTable from '@/components/uni-data-table/uni-data-table.vue';
|
||||
import {getManageGoodsCategory} from '@/api/goods.js';
|
||||
|
||||
export default {
|
||||
name: 'stockDialog',
|
||||
components: {
|
||||
unipopup,
|
||||
uniDataTable
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
params: {
|
||||
type: Object,
|
||||
default: ()=>{
|
||||
return {}
|
||||
}
|
||||
},
|
||||
apiType: {
|
||||
type: String,
|
||||
default: 'sku' //选择是sku 还是 spu
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
goodsCategoryList: {},
|
||||
activeList: [],//下拉激活
|
||||
option: {
|
||||
category_id: '',
|
||||
search_text: '',
|
||||
is_weigh: 0,
|
||||
page_size: 8,
|
||||
},
|
||||
cols: [{
|
||||
width: 6,
|
||||
align: 'center',
|
||||
checkbox: true
|
||||
}, {
|
||||
field: 'account_data',
|
||||
width: 50,
|
||||
title: '商品信息',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
let img = this.$util.img(data.sku_image);
|
||||
let html = `
|
||||
<view class="goods-content">
|
||||
<image class="goods-img" src="${img}" mode="aspectFit"/>
|
||||
<text class="goods-name multi-hidden" title="${data.sku_name}">${data.sku_name}</text>
|
||||
</view>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
field: 'real_stock',
|
||||
width: 22,
|
||||
title: '库存',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
return (data.real_stock || 0);
|
||||
}
|
||||
}, {
|
||||
width: 22,
|
||||
title: '单位',
|
||||
templet: data => {
|
||||
return (data.unit || '件');
|
||||
}
|
||||
}],
|
||||
checkList: {},
|
||||
url: '/stock/storeapi/manage/getStoreGoods'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler: function (val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
this.option = Object.assign(this.option, this.params);
|
||||
if (this.params.temp_store_id && this.params.temp_store_id == '') {
|
||||
delete this.option.temp_store_id
|
||||
}
|
||||
this.$refs.dialogRef.open()
|
||||
})
|
||||
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.option = Object(this.option, {
|
||||
category_id: '',
|
||||
search_text: '',
|
||||
is_weigh: 0,
|
||||
page: 1,
|
||||
page_size: 8,
|
||||
});
|
||||
this.checkList = {};
|
||||
this.$refs.dialogRef.close()
|
||||
})
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
apiType: {
|
||||
handler: function (val) {
|
||||
if(val == 'sku'){
|
||||
this.cols = [{
|
||||
width: 6,
|
||||
align: 'center',
|
||||
checkbox: true
|
||||
}, {
|
||||
field: 'account_data',
|
||||
width: 50,
|
||||
title: '商品信息',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
let img = this.$util.img(data.sku_image);
|
||||
let html = `
|
||||
<view class="goods-content">
|
||||
<image class="goods-img" src="${img}" mode="aspectFit"/>
|
||||
<text class="goods-name multi-hidden" title="${data.sku_name}">${data.sku_name}</text>
|
||||
</view>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
field: 'real_stock',
|
||||
width: 22,
|
||||
title: '库存',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
return (data.real_stock || 0);
|
||||
}
|
||||
}, {
|
||||
width: 22,
|
||||
title: '单位',
|
||||
templet: data => {
|
||||
return (data.unit || '件');
|
||||
}
|
||||
}];
|
||||
this.url = '/stock/storeapi/manage/getStoreGoods';
|
||||
}else if(val == 'spu'){
|
||||
this.cols = [{
|
||||
width: 6,
|
||||
align: 'center',
|
||||
checkbox: true
|
||||
}, {
|
||||
field: 'account_data',
|
||||
width: 50,
|
||||
title: '商品信息',
|
||||
align: 'left',
|
||||
templet: data => {
|
||||
let img = this.$util.img(data.goods_image);
|
||||
let html = `
|
||||
<view class="goods-content">
|
||||
<image class="goods-img" src="${img}" mode="aspectFit"/>
|
||||
<text class="goods-name multi-hidden" title="${data.goods_name}">${data.goods_name}</text>
|
||||
</view>
|
||||
`;
|
||||
return html;
|
||||
}
|
||||
}, {
|
||||
field: 'goods_stock',
|
||||
width: 22,
|
||||
title: '库存',
|
||||
align: 'center',
|
||||
templet: data => {
|
||||
return (data.goods_stock || 0);
|
||||
}
|
||||
}, {
|
||||
width: 22,
|
||||
title: '商品类型',
|
||||
templet: data => {
|
||||
return (data.goods_class_name || '--');
|
||||
}
|
||||
}];
|
||||
this.url = '/cashier/storeapi/goods/getGoodsListBySelect';
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getGoodsCategory()
|
||||
},
|
||||
methods: {
|
||||
getGoodsCategory() {
|
||||
getManageGoodsCategory().then(res=>{
|
||||
uni.hideLoading();
|
||||
if (res.data && Object.keys(res.data)) {
|
||||
this.goodsCategoryList = res.data
|
||||
} else {
|
||||
this.$util.showToast({
|
||||
title: res.message
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
itemClick(item) {//tree点击
|
||||
this.option.category_id = item.category_id;
|
||||
var index = this.activeList.indexOf(item.category_id);
|
||||
if (item.child_num && index === -1) {
|
||||
this.activeList.push(item.category_id);
|
||||
} else if (item.child_num && index != -1) {
|
||||
this.activeList.splice(index, 1);
|
||||
}
|
||||
this.$forceUpdate();
|
||||
this.getStoreGoods();
|
||||
},
|
||||
getStoreGoods() {//表格查询
|
||||
this.$refs.goodsListTable.load({
|
||||
page: 1
|
||||
});
|
||||
},
|
||||
checkBox(list, listIndex) {
|
||||
this.checkList[this.$refs.goodsListTable.page] = {};
|
||||
this.checkList[this.$refs.goodsListTable.page].data = list;
|
||||
this.checkList[this.$refs.goodsListTable.page].index = listIndex;
|
||||
},
|
||||
tableDataChange(){
|
||||
if(this.checkList[this.$refs.goodsListTable.page])
|
||||
this.$refs.goodsListTable.defaultSelectData(this.checkList[this.$refs.goodsListTable.page].data, this.checkList[this.$refs.goodsListTable.page].index);
|
||||
},
|
||||
submit(val) {
|
||||
if (!Object.values(this.checkList).length) {
|
||||
this.$util.showToast({
|
||||
title: '请选择商品'
|
||||
});
|
||||
return false
|
||||
}
|
||||
let data = [];
|
||||
Object.values(this.checkList).forEach((item,index)=>{
|
||||
data = data.concat(item.data)
|
||||
});
|
||||
this.$emit('selectGoods', data);
|
||||
if(val !='submit'){
|
||||
this.$emit('change', false);
|
||||
}else{
|
||||
this.$refs.goodsListTable.clearCheck();
|
||||
}
|
||||
this.checkList = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.stock-dialog-wrap {
|
||||
background-color: #fff;
|
||||
border-radius: 0.05rem;
|
||||
width: 9rem;
|
||||
|
||||
.stock-dialog-head {
|
||||
padding: 0 0.15rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 0.15rem;
|
||||
height: 0.45rem;
|
||||
border-bottom: 0.01rem solid #e8eaec;
|
||||
|
||||
.iconguanbi1 {
|
||||
font-size: $uni-font-size-lg;
|
||||
}
|
||||
}
|
||||
|
||||
.stock-dialog-body {
|
||||
width: 100%;
|
||||
height: 7.3rem;
|
||||
padding: 0.1rem 0.2rem 0 0.2rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
||||
.tree {
|
||||
width: 1.8rem;
|
||||
height: 7.1rem;
|
||||
overflow-y: auto;
|
||||
border-right: 0.01rem solid #e8eaec;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
flex-grow: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
.list-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
>view {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
view.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
line-height: 0.3rem;
|
||||
min-height: 0.3rem;
|
||||
font-weight: 500;
|
||||
|
||||
&.active {
|
||||
|
||||
.icon,
|
||||
view {
|
||||
color: $primary-color !important;
|
||||
}
|
||||
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 0.2rem;
|
||||
height: 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: rotate(-90deg);
|
||||
transition: all ease 0.5s;
|
||||
|
||||
&.active {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.level {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.item {
|
||||
padding-left: 0.2rem;
|
||||
}
|
||||
|
||||
.item2 {
|
||||
padding-left: 0.4rem;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.stock-dialog-table {
|
||||
width: 6.6rem;
|
||||
margin-left: 0.2rem;
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-top: 0.01rem solid #e8eaec;
|
||||
padding: 0.1rem 0.2rem 0.1rem 0.2rem;
|
||||
height: 0.38rem;
|
||||
|
||||
.default-btn,
|
||||
.primary-btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.default-btn {
|
||||
|
||||
border: 0.01rem solid #e8eaec !important;
|
||||
}
|
||||
.submit{
|
||||
margin-right: 0.15rem;
|
||||
}
|
||||
.default-btn::after {
|
||||
display: none;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.common-form .common-btn-wrap {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.common-form .common-btn-wrap .screen-btn {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.common-form .common-form-item {
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
/deep/ .goods-content {
|
||||
display: flex;
|
||||
|
||||
.goods-img {
|
||||
margin-right: 0.1rem;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
flex-basis: auto;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
420
addon/cashier/source/os/components/u-charts/config-echarts.js
Executable file
420
addon/cashier/source/os/components/u-charts/config-echarts.js
Executable file
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
* uCharts®
|
||||
* 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)、Vue、Taro等支持canvas的框架平台
|
||||
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
|
||||
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
* 复制使用请保留本段注释,感谢支持开源!
|
||||
*
|
||||
* uCharts®官方网站
|
||||
* https://www.uCharts.cn
|
||||
*
|
||||
* 开源地址:
|
||||
* https://gitee.com/uCharts/uCharts
|
||||
*
|
||||
* uni-app插件市场地址:
|
||||
* http://ext.dcloud.net.cn/plugin?id=271
|
||||
*
|
||||
*/
|
||||
|
||||
// 通用配置项
|
||||
|
||||
// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
|
||||
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
|
||||
|
||||
module.exports = {
|
||||
//demotype为自定义图表类型
|
||||
"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
|
||||
//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
|
||||
"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
|
||||
//instance为实例变量承载属性,option为eopts承载属性,不要删除
|
||||
"instance": {},
|
||||
"option": {},
|
||||
//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
|
||||
"formatter":{
|
||||
"tooltipDemo1":function(res){
|
||||
let result = ''
|
||||
for (let i in res) {
|
||||
if (i == 0) {
|
||||
result += res[i].axisValueLabel + '年销售额'
|
||||
}
|
||||
let value = '--'
|
||||
if (res[i].data !== null) {
|
||||
value = res[i].data
|
||||
}
|
||||
// #ifdef H5
|
||||
result += '\n' + res[i].seriesName + ':' + value + ' 万元'
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
result += '<br/>' + res[i].marker + res[i].seriesName + ':' + value + ' 万元'
|
||||
// #endif
|
||||
}
|
||||
return result;
|
||||
},
|
||||
legendFormat:function(name){
|
||||
return "自定义图例+"+name;
|
||||
},
|
||||
yAxisFormatDemo:function (value, index) {
|
||||
return value + '元';
|
||||
},
|
||||
seriesFormatDemo:function(res){
|
||||
return res.name + '年' + res.value + '元';
|
||||
}
|
||||
},
|
||||
//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在eopts参数,会将demotype与eopts中option合并后渲染图表。
|
||||
"demotype":{
|
||||
"color": color,
|
||||
//在这里填写echarts的option即可
|
||||
|
||||
},
|
||||
//下面是自定义配置,请添加项目所需的通用配置
|
||||
"column": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'axis'
|
||||
},
|
||||
"grid": {
|
||||
"top": 30,
|
||||
"bottom": 50,
|
||||
"right": 15,
|
||||
"left": 40
|
||||
},
|
||||
"legend": {
|
||||
"bottom": 'left',
|
||||
},
|
||||
"toolbox": {
|
||||
"show": false,
|
||||
},
|
||||
"xAxis": {
|
||||
"type": 'category',
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
"boundaryGap": true,
|
||||
"data": []
|
||||
},
|
||||
"yAxis": {
|
||||
"type": 'value',
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
},
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'bar',
|
||||
"data": [],
|
||||
"barwidth": 20,
|
||||
"label": {
|
||||
"show": true,
|
||||
"color": "#666666",
|
||||
"position": 'top',
|
||||
},
|
||||
},
|
||||
},
|
||||
"line": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'axis'
|
||||
},
|
||||
"grid": {
|
||||
"top": 30,
|
||||
"bottom": 50,
|
||||
"right": 15,
|
||||
"left": 40
|
||||
},
|
||||
"legend": {
|
||||
"bottom": 'left',
|
||||
},
|
||||
"toolbox": {
|
||||
"show": false,
|
||||
},
|
||||
"xAxis": {
|
||||
"type": 'category',
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
"boundaryGap": true,
|
||||
"data": []
|
||||
},
|
||||
"yAxis": {
|
||||
"type": 'value',
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
},
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'line',
|
||||
"data": [],
|
||||
"barwidth": 20,
|
||||
"label": {
|
||||
"show": true,
|
||||
"color": "#666666",
|
||||
"position": 'top',
|
||||
},
|
||||
},
|
||||
},
|
||||
"area": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'axis'
|
||||
},
|
||||
"grid": {
|
||||
"top": 30,
|
||||
"bottom": 50,
|
||||
"right": 15,
|
||||
"left": 40
|
||||
},
|
||||
"legend": {
|
||||
"bottom": 'left',
|
||||
},
|
||||
"toolbox": {
|
||||
"show": false,
|
||||
},
|
||||
"xAxis": {
|
||||
"type": 'category',
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
"boundaryGap": true,
|
||||
"data": []
|
||||
},
|
||||
"yAxis": {
|
||||
"type": 'value',
|
||||
"axisTick": {
|
||||
"show": false,
|
||||
},
|
||||
"axisLabel": {
|
||||
"color": '#666666'
|
||||
},
|
||||
"axisLine": {
|
||||
"lineStyle": {
|
||||
"color": '#CCCCCC'
|
||||
}
|
||||
},
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'line',
|
||||
"data": [],
|
||||
"areaStyle": {},
|
||||
"label": {
|
||||
"show": true,
|
||||
"color": "#666666",
|
||||
"position": 'top',
|
||||
},
|
||||
},
|
||||
},
|
||||
"pie": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'item'
|
||||
},
|
||||
"grid": {
|
||||
"top": 40,
|
||||
"bottom": 30,
|
||||
"right": 15,
|
||||
"left": 15
|
||||
},
|
||||
"legend": {
|
||||
"bottom": 'left',
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'pie',
|
||||
"data": [],
|
||||
"radius": '50%',
|
||||
"label": {
|
||||
"show": true,
|
||||
"color": "#666666",
|
||||
"position": 'top',
|
||||
},
|
||||
},
|
||||
},
|
||||
"ring": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'item'
|
||||
},
|
||||
"grid": {
|
||||
"top": 40,
|
||||
"bottom": 30,
|
||||
"right": 15,
|
||||
"left": 15
|
||||
},
|
||||
"legend": {
|
||||
"bottom": 'left',
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'pie',
|
||||
"data": [],
|
||||
"radius": ['40%', '70%'],
|
||||
"avoidLabelOverlap": false,
|
||||
"label": {
|
||||
"show": true,
|
||||
"color": "#666666",
|
||||
"position": 'top',
|
||||
},
|
||||
"labelLine": {
|
||||
"show": true
|
||||
},
|
||||
},
|
||||
},
|
||||
"rose": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'item'
|
||||
},
|
||||
"legend": {
|
||||
"top": 'bottom'
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'pie',
|
||||
"data": [],
|
||||
"radius": "55%",
|
||||
"center": ['50%', '50%'],
|
||||
"rosetype": 'area',
|
||||
},
|
||||
},
|
||||
"funnel": {
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": 'item',
|
||||
"formatter": "{b} : {c}%"
|
||||
},
|
||||
"legend": {
|
||||
"top": 'bottom'
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'funnel',
|
||||
"left": '10%',
|
||||
"top": 60,
|
||||
"bottom": 60,
|
||||
"width": '80%',
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"minSize": '0%',
|
||||
"maxSize": '100%',
|
||||
"sort": 'descending',
|
||||
"gap": 2,
|
||||
"label": {
|
||||
"show": true,
|
||||
"position": 'inside'
|
||||
},
|
||||
"labelLine": {
|
||||
"length": 10,
|
||||
"lineStyle": {
|
||||
"width": 1,
|
||||
"type": 'solid'
|
||||
}
|
||||
},
|
||||
"itemStyle": {
|
||||
"bordercolor": '#fff',
|
||||
"borderwidth": 1
|
||||
},
|
||||
"emphasis": {
|
||||
"label": {
|
||||
"fontSize": 20
|
||||
}
|
||||
},
|
||||
"data": [],
|
||||
},
|
||||
},
|
||||
"gauge": {
|
||||
"color": color,
|
||||
"tooltip": {
|
||||
"formatter": '{a} <br/>{b} : {c}%'
|
||||
},
|
||||
"seriesTemplate": {
|
||||
"name": '业务指标',
|
||||
"type": 'gauge',
|
||||
"detail": {"formatter": '{value}%'},
|
||||
"data": [{"value": 50, "name": '完成率'}]
|
||||
},
|
||||
},
|
||||
"candle": {
|
||||
"xAxis": {
|
||||
"data": []
|
||||
},
|
||||
"yAxis": {},
|
||||
"color": color,
|
||||
"title": {
|
||||
"text": ''
|
||||
},
|
||||
"dataZoom": [{
|
||||
"type": 'inside',
|
||||
"xAxisIndex": [0, 1],
|
||||
"start": 10,
|
||||
"end": 100
|
||||
},
|
||||
{
|
||||
"show": true,
|
||||
"xAxisIndex": [0, 1],
|
||||
"type": 'slider',
|
||||
"bottom": 10,
|
||||
"start": 10,
|
||||
"end": 100
|
||||
}
|
||||
],
|
||||
"seriesTemplate": {
|
||||
"name": '',
|
||||
"type": 'k',
|
||||
"data": [],
|
||||
},
|
||||
}
|
||||
}
|
||||
433
addon/cashier/source/os/components/u-charts/config-ucharts.js
Executable file
433
addon/cashier/source/os/components/u-charts/config-ucharts.js
Executable file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
* uCharts®
|
||||
* 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)、Vue、Taro等支持canvas的框架平台
|
||||
* Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
|
||||
* Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
* 复制使用请保留本段注释,感谢支持开源!
|
||||
*
|
||||
* uCharts®官方网站
|
||||
* https://www.uCharts.cn
|
||||
*
|
||||
* 开源地址:
|
||||
* https://gitee.com/uCharts/uCharts
|
||||
*
|
||||
* uni-app插件市场地址:
|
||||
* http://ext.dcloud.net.cn/plugin?id=271
|
||||
*
|
||||
*/
|
||||
|
||||
// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
|
||||
const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
|
||||
|
||||
module.exports = {
|
||||
//demotype为自定义图表类型
|
||||
"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","area","radar","gauge","candle","mix","demotype"],
|
||||
"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","区域图","雷达图","仪表盘","K线图","混合图","自定义类型"],
|
||||
//增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
|
||||
"categories":["line","column","area","radar","gauge","candle","mix","demotype"],
|
||||
//instance为实例变量承载属性,option为eopts承载属性,不要删除
|
||||
"instance":{},
|
||||
"option":{},
|
||||
//下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
|
||||
"formatter":{
|
||||
"yAxisDemo1":function(val){return val+'元'},
|
||||
"yAxisDemo2":function(val){return val.toFixed(2)},
|
||||
"seriesDemo1":function(val){
|
||||
return val+'元'
|
||||
},
|
||||
"tooltipDemo1":function(item, category, index, opts){
|
||||
if(index==0){
|
||||
return '随便用'+item.data+'年'
|
||||
}else{
|
||||
return '其他我没改'+item.data+'天'
|
||||
}
|
||||
},
|
||||
"pieDemo":function(val, index, series){
|
||||
if(index !== undefined){
|
||||
return series[index].name+':'+series[index].data+'元'
|
||||
}
|
||||
},
|
||||
},
|
||||
//这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
|
||||
"demotype":{
|
||||
//我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
|
||||
"type": "line",
|
||||
"color": color,
|
||||
"padding": [15,10,0,15],
|
||||
"xAxis": {
|
||||
"disableGrid": true,
|
||||
},
|
||||
"yAxis": {
|
||||
"gridType": "dash",
|
||||
"dashLength": 2,
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"line": {
|
||||
"type": "curve",
|
||||
"width": 2
|
||||
},
|
||||
}
|
||||
},
|
||||
//下面是自定义配置,请添加项目所需的通用配置
|
||||
"pie":{
|
||||
"type": "pie",
|
||||
"color": color,
|
||||
"padding": [5,5,5,5],
|
||||
"extra": {
|
||||
"pie": {
|
||||
"activeOpacity": 0.5,
|
||||
"activeRadius": 10,
|
||||
"offsetAngle": 0,
|
||||
"labelWidth": 15,
|
||||
"border": true,
|
||||
"borderWidth": 3,
|
||||
"borderColor": "#FFFFFF"
|
||||
},
|
||||
}
|
||||
},
|
||||
"ring":{
|
||||
"type": "ring",
|
||||
"color": color,
|
||||
"padding": [5,5,5,5],
|
||||
"rotate": false,
|
||||
"dataLabel": true,
|
||||
"legend": {
|
||||
"show": true,
|
||||
"position": "right",
|
||||
"lineHeight": 25,
|
||||
},
|
||||
"title": {
|
||||
"name": "收益率",
|
||||
"fontSize": 15,
|
||||
"color": "#666666"
|
||||
},
|
||||
"subtitle": {
|
||||
"name": "70%",
|
||||
"fontSize": 25,
|
||||
"color": "#7cb5ec"
|
||||
},
|
||||
"extra": {
|
||||
"ring": {
|
||||
"ringWidth":30,
|
||||
"activeOpacity": 0.5,
|
||||
"activeRadius": 10,
|
||||
"offsetAngle": 0,
|
||||
"labelWidth": 15,
|
||||
"border": true,
|
||||
"borderWidth": 3,
|
||||
"borderColor": "#FFFFFF"
|
||||
},
|
||||
},
|
||||
},
|
||||
"rose":{
|
||||
"type": "rose",
|
||||
"color": color,
|
||||
"padding": [5,5,5,5],
|
||||
"legend": {
|
||||
"show": true,
|
||||
"position": "left",
|
||||
"lineHeight": 25,
|
||||
},
|
||||
"extra": {
|
||||
"rose": {
|
||||
"type": "area",
|
||||
"minRadius": 50,
|
||||
"activeOpacity": 0.5,
|
||||
"activeRadius": 10,
|
||||
"offsetAngle": 0,
|
||||
"labelWidth": 15,
|
||||
"border": false,
|
||||
"borderWidth": 2,
|
||||
"borderColor": "#FFFFFF"
|
||||
},
|
||||
}
|
||||
},
|
||||
"word":{
|
||||
"type": "word",
|
||||
"color": color,
|
||||
"extra": {
|
||||
"word": {
|
||||
"type": "normal",
|
||||
"autoColors": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"funnel":{
|
||||
"type": "funnel",
|
||||
"color": color,
|
||||
"padding": [15,15,0,15],
|
||||
"extra": {
|
||||
"funnel": {
|
||||
"activeOpacity": 0.3,
|
||||
"activeWidth": 10,
|
||||
"border": true,
|
||||
"borderWidth": 2,
|
||||
"borderColor": "#FFFFFF",
|
||||
"fillOpacity": 1,
|
||||
"labelAlign": "right"
|
||||
},
|
||||
}
|
||||
},
|
||||
"map":{
|
||||
"type": "map",
|
||||
"color": color,
|
||||
"padding": [0,0,0,0],
|
||||
"dataLabel": true,
|
||||
"extra": {
|
||||
"map": {
|
||||
"border": true,
|
||||
"borderWidth": 1,
|
||||
"borderColor": "#666666",
|
||||
"fillOpacity": 0.6,
|
||||
"activeBorderColor": "#F04864",
|
||||
"activeFillColor": "#FACC14",
|
||||
"activeFillOpacity": 1
|
||||
},
|
||||
}
|
||||
},
|
||||
"arcbar":{
|
||||
"type": "arcbar",
|
||||
"color": color,
|
||||
"title": {
|
||||
"name": "百分比",
|
||||
"fontSize": 25,
|
||||
"color": "#00FF00"
|
||||
},
|
||||
"subtitle": {
|
||||
"name": "默认标题",
|
||||
"fontSize": 15,
|
||||
"color": "#666666"
|
||||
},
|
||||
"extra": {
|
||||
"arcbar": {
|
||||
"type": "default",
|
||||
"width": 12,
|
||||
"backgroundColor": "#E9E9E9",
|
||||
"startAngle": 0.75,
|
||||
"endAngle": 0.25,
|
||||
"gap": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"line":{
|
||||
"type": "line",
|
||||
"color": color,
|
||||
"padding": [15,10,0,15],
|
||||
"xAxis": {
|
||||
"disableGrid": true,
|
||||
},
|
||||
"yAxis": {
|
||||
"gridType": "dash",
|
||||
"dashLength": 2,
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"line": {
|
||||
"type": "straight",
|
||||
"width": 2
|
||||
},
|
||||
}
|
||||
},
|
||||
"column":{
|
||||
"type": "column",
|
||||
"color": color,
|
||||
"padding": [15,15,0,5],
|
||||
"xAxis": {
|
||||
"disableGrid": true,
|
||||
},
|
||||
"yAxis": {
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"column": {
|
||||
"type": "group",
|
||||
"width": 30,
|
||||
"meterBorde": 1,
|
||||
"meterFillColor": "#FFFFFF",
|
||||
"activeBgColor": "#000000",
|
||||
"activeBgOpacity": 0.08
|
||||
},
|
||||
}
|
||||
},
|
||||
"area":{
|
||||
"type": "area",
|
||||
"color": color,
|
||||
"padding": [15,15,0,15],
|
||||
"xAxis": {
|
||||
"disableGrid": true,
|
||||
},
|
||||
"yAxis": {
|
||||
"gridType": "dash",
|
||||
"dashLength": 2,
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"area": {
|
||||
"type": "straight",
|
||||
"opacity": 0.2,
|
||||
"addLine": true,
|
||||
"width": 2,
|
||||
"gradient": false
|
||||
},
|
||||
}
|
||||
},
|
||||
"radar":{
|
||||
"type": "radar",
|
||||
"color": color,
|
||||
"padding": [5,5,5,5],
|
||||
"legend": {
|
||||
"show": true,
|
||||
"position": "right",
|
||||
"lineHeight": 25,
|
||||
},
|
||||
"extra": {
|
||||
"radar": {
|
||||
"gridType": "radar",
|
||||
"gridColor": "#CCCCCC",
|
||||
"gridCount": 3,
|
||||
"opacity": 0.2,
|
||||
"labelColor": "#666666",
|
||||
"max": 200
|
||||
},
|
||||
}
|
||||
},
|
||||
"gauge":{
|
||||
"type": "gauge",
|
||||
"color": color,
|
||||
"title": {
|
||||
"name": "66Km/H",
|
||||
"fontSize": 25,
|
||||
"color": "#2fc25b",
|
||||
"offsetY": 50
|
||||
},
|
||||
"subtitle": {
|
||||
"name": "实时速度",
|
||||
"fontSize": 15,
|
||||
"color": "#1890ff",
|
||||
"offsetY": -50
|
||||
},
|
||||
"extra": {
|
||||
"gauge": {
|
||||
"type": "default",
|
||||
"width": 30,
|
||||
"labelColor": "#666666",
|
||||
"startAngle": 0.75,
|
||||
"endAngle": 0.25,
|
||||
"startNumber": 0,
|
||||
"endNumber": 100,
|
||||
"labelFormat": "",
|
||||
"splitLine": {
|
||||
"fixRadius": 0,
|
||||
"splitNumber": 10,
|
||||
"width": 30,
|
||||
"color": "#FFFFFF",
|
||||
"childNumber": 5,
|
||||
"childWidth": 12
|
||||
},
|
||||
"pointer": {
|
||||
"width": 24,
|
||||
"color": "auto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"candle":{
|
||||
"type": "candle",
|
||||
"color": color,
|
||||
"padding": [15,15,0,15],
|
||||
"enableScroll": true,
|
||||
"enableMarkLine": true,
|
||||
"dataLabel": false,
|
||||
"xAxis": {
|
||||
"labelCount": 4,
|
||||
"itemCount": 40,
|
||||
"disableGrid": true,
|
||||
"gridColor": "#CCCCCC",
|
||||
"gridType": "solid",
|
||||
"dashLength": 4,
|
||||
"scrollShow": true,
|
||||
"scrollAlign": "left",
|
||||
"scrollColor": "#A6A6A6",
|
||||
"scrollBackgroundColor": "#EFEBEF"
|
||||
},
|
||||
"yAxis": {
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"candle": {
|
||||
"color": {
|
||||
"upLine": "#f04864",
|
||||
"upFill": "#f04864",
|
||||
"downLine": "#2fc25b",
|
||||
"downFill": "#2fc25b"
|
||||
},
|
||||
"average": {
|
||||
"show": true,
|
||||
"name": ["MA5","MA10","MA30"],
|
||||
"day": [5,10,20],
|
||||
"color": ["#1890ff","#2fc25b","#facc14"]
|
||||
}
|
||||
},
|
||||
"markLine": {
|
||||
"type": "dash",
|
||||
"dashLength": 5,
|
||||
"data": [
|
||||
{
|
||||
"value": 2150,
|
||||
"lineColor": "#f04864",
|
||||
"showLabel": true
|
||||
},
|
||||
{
|
||||
"value": 2350,
|
||||
"lineColor": "#f04864",
|
||||
"showLabel": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"mix":{
|
||||
"type": "mix",
|
||||
"color": color,
|
||||
"padding": [15,15,0,15],
|
||||
"xAxis": {
|
||||
"disableGrid": true,
|
||||
},
|
||||
"yAxis": {
|
||||
"disabled": false,
|
||||
"disableGrid": false,
|
||||
"splitNumber": 5,
|
||||
"gridType": "dash",
|
||||
"dashLength": 4,
|
||||
"gridColor": "#CCCCCC",
|
||||
"padding": 10,
|
||||
"showTitle": true,
|
||||
"data": []
|
||||
},
|
||||
"legend": {
|
||||
},
|
||||
"extra": {
|
||||
"mix": {
|
||||
"column": {
|
||||
"width": 20
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"point":{
|
||||
"type": "point",
|
||||
"color":color,
|
||||
"padding":[15,15,0,15],
|
||||
},
|
||||
"bubble":{
|
||||
"type": "bubble",
|
||||
"color":color,
|
||||
"padding":[15,15,0,15],
|
||||
}
|
||||
}
|
||||
201
addon/cashier/source/os/components/u-charts/license.md
Executable file
201
addon/cashier/source/os/components/u-charts/license.md
Executable file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
12
addon/cashier/source/os/components/u-charts/readme.md
Executable file
12
addon/cashier/source/os/components/u-charts/readme.md
Executable file
@@ -0,0 +1,12 @@
|
||||
# uCharts JSSDK说明
|
||||
1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`98kb`。
|
||||
2、如果100kb的体积仍需压缩,请手动删除u-charts.js内您不需要的图表类型,如k线图candle。
|
||||
3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
|
||||
3、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。
|
||||
|
||||
# v1.0转v2.0注意事项
|
||||
1、opts.colors变更为opts.color
|
||||
2、ring圆环图的扩展配置由extra.pie变更为extra.ring
|
||||
3、混合图借用的扩展配置由extra.column变更为extra.mix.column
|
||||
4、全部涉及到format的格式化属性变更为formatter
|
||||
5、不需要再传canvasId及$this参数,如果通过uChats获取context,可能会导致this实例混乱,导致小程序开发者工具报错。如果不使用qiun-data-charts官方组件,需要在new uCharts()实例化之前,自行获取canvas的上下文context(ctx),并传入new中的context(opts.context)。为了能跨更多的端,给您带来的不便敬请谅解。
|
||||
5910
addon/cashier/source/os/components/u-charts/u-charts-v2.0.0.js
Executable file
5910
addon/cashier/source/os/components/u-charts/u-charts-v2.0.0.js
Executable file
File diff suppressed because it is too large
Load Diff
808
addon/cashier/source/os/components/uni-data-checkbox/uni-data-checkbox.vue
Executable file
808
addon/cashier/source/os/components/uni-data-checkbox/uni-data-checkbox.vue
Executable file
@@ -0,0 +1,808 @@
|
||||
<template>
|
||||
<view class="uni-data-checklist" :style="{'margin-top':isTop+'px'}">
|
||||
<template >
|
||||
<checkbox-group v-if="multiple" class="checklist-group" :class="{'is-list':mode==='list' || wrap}" @change="chagne">
|
||||
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
|
||||
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
|
||||
<checkbox class="hidden" hidden :disabled="disabled || !!item.disabled" :value="item[map.value]+''" :checked="item.selected" />
|
||||
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="checkbox__inner" :style="item.styleIcon">
|
||||
<view class="checkbox__inner-icon"></view>
|
||||
</view>
|
||||
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
|
||||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||
<view v-if="mode === 'list' && icon === 'right'" class="checkobx__list" :style="item.styleBackgroud"></view>
|
||||
</view>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
<radio-group v-else class="checklist-group" :class="{'is-list':mode==='list','is-wrap':wrap}" @change="chagne">
|
||||
<label class="checklist-box" :class="['is--'+mode,item.selected?'is-checked':'',(disabled || !!item.disabled)?'is-disable':'',index!==0&&mode==='list'?'is-list-border':'']"
|
||||
:style="item.styleBackgroud" v-for="(item,index) in dataList" :key="index">
|
||||
<radio class="hidden" hidden :disabled="disabled || item.disabled" :value="item[map.value]+''" :checked="item.selected" />
|
||||
<view v-if="(mode !=='tag' && mode !== 'list') || ( mode === 'list' && icon === 'left')" class="radio__inner" :style="item.styleBackgroud">
|
||||
<view class="radio__inner-icon" :style="item.styleIcon"></view>
|
||||
</view>
|
||||
<view class="checklist-content" :class="{'list-content':mode === 'list' && icon ==='left'}">
|
||||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||
<view v-if="mode === 'list' && icon === 'right'" :style="item.styleRightIcon" class="checkobx__list"></view>
|
||||
</view>
|
||||
</label>
|
||||
</radio-group>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* DataChecklist 数据选择器
|
||||
* @description 通过数据渲染 checkbox 和 radio
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
|
||||
* @property {String} mode = [default| list | button | tag] 显示模式
|
||||
* @value default 默认横排模式
|
||||
* @value list 列表模式
|
||||
* @value button 按钮模式
|
||||
* @value tag 标签模式
|
||||
* @property {Boolean} multiple = [true|false] 是否多选
|
||||
* @property {Array|String|Number} value 默认值
|
||||
* @property {Array} localdata 本地数据 ,格式 [{text:'',value:''}]
|
||||
* @property {Number|String} min 最小选择个数 ,multiple为true时生效
|
||||
* @property {Number|String} max 最大选择个数 ,multiple为true时生效
|
||||
* @property {Boolean} wrap 是否换行显示
|
||||
* @property {String} icon = [left|right] list 列表模式下icon显示位置
|
||||
* @property {Boolean} selectedColor 选中颜色
|
||||
* @property {Boolean} emptyText 没有数据时显示的文字 ,本地数据无效
|
||||
* @property {Boolean} selectedTextColor 选中文本颜色,如不填写则自动显示
|
||||
* @property {Object} map 字段映射, 默认 map={text:'text',value:'value'}
|
||||
* @value left 左侧显示
|
||||
* @value right 右侧显示
|
||||
* @event {Function} change 选中发生变化触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'uniDataChecklist',
|
||||
mixins: [uniCloud.mixinDatacom || {}],
|
||||
emits:['input','update:modelValue','change'],
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: [Array, String, Number],
|
||||
default () {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
// TODO vue3
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default() {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
localdata: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
min: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
max: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
wrap: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
selectedColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
selectedTextColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
emptyText:{
|
||||
type: String,
|
||||
default: '暂无数据'
|
||||
},
|
||||
disabled:{
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
map:{
|
||||
type: Object,
|
||||
default(){
|
||||
return {
|
||||
text:'text',
|
||||
value:'value'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
localdata: {
|
||||
handler(newVal) {
|
||||
this.range = newVal;
|
||||
this.dataList = this.getDataList(this.getSelectedValue(newVal));
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
mixinDatacomResData(newVal) {
|
||||
this.range = newVal;
|
||||
this.dataList = this.getDataList(this.getSelectedValue(newVal));
|
||||
},
|
||||
value(newVal) {
|
||||
this.dataList = this.getDataList(newVal);
|
||||
// fix by mehaotian is_reset 在 uni-forms 中定义
|
||||
if(!this.is_reset){
|
||||
this.is_reset = false;
|
||||
this.formItem && this.formItem.setValue(newVal);
|
||||
}
|
||||
},
|
||||
modelValue(newVal) {
|
||||
this.dataList = this.getDataList(newVal);
|
||||
if(!this.is_reset){
|
||||
this.is_reset = false;
|
||||
this.formItem && this.formItem.setValue(newVal);
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataList: [],
|
||||
range: [],
|
||||
contentText: {
|
||||
contentdown: '查看更多',
|
||||
contentrefresh: '加载中',
|
||||
contentnomore: '没有更多'
|
||||
},
|
||||
isLocal:true,
|
||||
styles: {
|
||||
selectedColor: '$primary-color',
|
||||
selectedTextColor: '#666',
|
||||
},
|
||||
isTop:0
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
dataValue(){
|
||||
if(this.value === '')return this.modelValue;
|
||||
if(this.modelValue === '') return this.value;
|
||||
return this.value;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.getForm('uniForms');
|
||||
this.formItem = this.getForm('uniFormsItem');
|
||||
// this.formItem && this.formItem.setValue(this.value)
|
||||
|
||||
if (this.formItem) {
|
||||
this.isTop = 6;
|
||||
if (this.formItem.name) {
|
||||
// 如果存在name添加默认值,否则formData 中不存在这个字段不校验
|
||||
if(!this.is_reset){
|
||||
this.is_reset = false;
|
||||
this.formItem.setValue(this.dataValue);
|
||||
}
|
||||
this.rename = this.formItem.name;
|
||||
this.form.inputChildrens.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.localdata && this.localdata.length !== 0) {
|
||||
this.isLocal = true;
|
||||
this.range = this.localdata;
|
||||
this.dataList = this.getDataList(this.getSelectedValue(this.range));
|
||||
} else {
|
||||
if (this.collection) {
|
||||
this.isLocal = false;
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadData() {
|
||||
this.mixinDatacomGet().then(res=>{
|
||||
this.mixinDatacomResData = res.result.data;
|
||||
if(this.mixinDatacomResData.length === 0){
|
||||
this.isLocal = false;
|
||||
this.mixinDatacomErrorMessage = this.emptyText;
|
||||
}else{
|
||||
this.isLocal = true;
|
||||
}
|
||||
}).catch(err=>{
|
||||
this.mixinDatacomErrorMessage = err.message;
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniForms') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
chagne(e) {
|
||||
const values = e.detail.value;
|
||||
|
||||
let detail = {
|
||||
value: [],
|
||||
data: []
|
||||
};
|
||||
|
||||
if (this.multiple) {
|
||||
this.range.forEach(item => {
|
||||
if (values.includes(item[this.map.value] + '')) {
|
||||
detail.value.push(item[this.map.value]);
|
||||
detail.data.push(item);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const range = this.range.find(item => (item[this.map.value] + '') === values);
|
||||
if (range) {
|
||||
detail = {
|
||||
value: range[this.map.value],
|
||||
data: range
|
||||
}
|
||||
}
|
||||
}
|
||||
this.formItem && this.formItem.setValue(detail.value);
|
||||
// TODO 兼容 vue2
|
||||
this.$emit('input', detail.value);
|
||||
// // TOTO 兼容 vue3
|
||||
this.$emit('update:modelValue', detail.value);
|
||||
this.$emit('change', {
|
||||
detail
|
||||
});
|
||||
if (this.multiple) {
|
||||
// 如果 v-model 没有绑定 ,则走内部逻辑
|
||||
// if (this.value.length === 0) {
|
||||
this.dataList = this.getDataList(detail.value, true)
|
||||
// }
|
||||
} else {
|
||||
this.dataList = this.getDataList(detail.value)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取渲染的新数组
|
||||
* @param {Object} value 选中内容
|
||||
*/
|
||||
getDataList(value) {
|
||||
// 解除引用关系,破坏原引用关系,避免污染源数据
|
||||
let dataList = JSON.parse(JSON.stringify(this.range));
|
||||
let list = [];
|
||||
if (this.multiple) {
|
||||
if (!Array.isArray(value)) {
|
||||
value = []
|
||||
}
|
||||
}
|
||||
dataList.forEach((item, index) => {
|
||||
item.disabled = item.disable || item.disabled || false;
|
||||
if (this.multiple) {
|
||||
if (value.length > 0) {
|
||||
let have = value.find(val => val === item[this.map.value]);
|
||||
item.selected = have !== undefined;
|
||||
} else {
|
||||
item.selected = false;
|
||||
}
|
||||
} else {
|
||||
item.selected = value === item[this.map.value];
|
||||
}
|
||||
|
||||
list.push(item)
|
||||
});
|
||||
return this.setRange(list)
|
||||
},
|
||||
/**
|
||||
* 处理最大最小值
|
||||
* @param {Object} list
|
||||
*/
|
||||
setRange(list) {
|
||||
let selectList = list.filter(item => item.selected);
|
||||
let min = Number(this.min) || 0;
|
||||
let max = Number(this.max) || '';
|
||||
list.forEach((item, index) => {
|
||||
if (this.multiple) {
|
||||
if (selectList.length <= min) {
|
||||
let have = selectList.find(val => val[this.map.value] === item[this.map.value]);
|
||||
if (have !== undefined) {
|
||||
item.disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
if (selectList.length >= max && max !== '') {
|
||||
let have = selectList.find(val => val[this.map.value] === item[this.map.value]);
|
||||
if (have === undefined) {
|
||||
item.disabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setStyles(item, index);
|
||||
list[index] = item
|
||||
});
|
||||
return list
|
||||
},
|
||||
/**
|
||||
* 设置 class
|
||||
* @param {Object} item
|
||||
* @param {Object} index
|
||||
*/
|
||||
setStyles(item, index) {
|
||||
// 设置自定义样式
|
||||
item.styleBackgroud = this.setStyleBackgroud(item);
|
||||
item.styleIcon = this.setStyleIcon(item);
|
||||
item.styleIconText = this.setStyleIconText(item);
|
||||
item.styleRightIcon = this.setStyleRightIcon(item);
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取选中值
|
||||
* @param {Object} range
|
||||
*/
|
||||
getSelectedValue(range) {
|
||||
if (!this.multiple) return this.dataValue;
|
||||
let selectedArr = [];
|
||||
range.forEach((item) => {
|
||||
if (item.selected) {
|
||||
selectedArr.push(item[this.map.value])
|
||||
}
|
||||
});
|
||||
return this.dataValue && this.dataValue.length > 0 ? this.dataValue : selectedArr
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置背景样式
|
||||
*/
|
||||
setStyleBackgroud(item) {
|
||||
let styles = {}
|
||||
let selectedColor = this.selectedColor?this.selectedColor:''
|
||||
if (this.mode !== 'list') {
|
||||
styles['border-color'] = item.selected?selectedColor:''
|
||||
}
|
||||
if (this.mode === 'tag') {
|
||||
styles['background-color'] = item.selected? selectedColor:''
|
||||
}
|
||||
let classles = ''
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
setStyleIcon(item) {
|
||||
let styles = {}
|
||||
let classles = ''
|
||||
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
|
||||
styles['background-color'] = item.selected?selectedColor:'#fff'
|
||||
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
|
||||
|
||||
if(!item.selected && item.disabled){
|
||||
styles['background-color'] = '#F2F6FC'
|
||||
styles['border-color'] = item.selected?selectedColor:'#DCDFE6'
|
||||
}
|
||||
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
setStyleIconText(item) {
|
||||
let styles = {}
|
||||
let classles = ''
|
||||
let selectedColor = this.selectedColor?this.selectedColor:'#2979ff'
|
||||
if (this.mode === 'tag') {
|
||||
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:'#fff'):'#666'
|
||||
} else {
|
||||
styles.color = item.selected?(this.selectedTextColor?this.selectedTextColor:selectedColor):'#666'
|
||||
}
|
||||
if(!item.selected && item.disabled){
|
||||
styles.color = '#999'
|
||||
}
|
||||
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
return classles
|
||||
},
|
||||
setStyleRightIcon(item) {
|
||||
let styles = {}
|
||||
let classles = ''
|
||||
if (this.mode === 'list') {
|
||||
styles['border-color'] = item.selected?this.styles.selectedColor:'#DCDFE6'
|
||||
}
|
||||
for (let i in styles) {
|
||||
classles += `${i}:${styles[i]};`
|
||||
}
|
||||
|
||||
return classles
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$checked-color: $primary-color !important;
|
||||
$border-color: #DCDFE6;
|
||||
$disable:0.4;
|
||||
|
||||
@mixin flex {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-data-loading {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 0.36rem;
|
||||
padding-left: 0.1rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.uni-data-checklist {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
flex: 1;
|
||||
// 多选样式
|
||||
.checklist-group {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&.is-list {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.checklist-box {
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin: 0.05rem 0;
|
||||
margin-right: 0.25rem;
|
||||
|
||||
.hidden {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// 文字样式
|
||||
.checklist-content {
|
||||
@include flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.checklist-text {
|
||||
font-size: 0.14rem;
|
||||
color: #666;
|
||||
margin-left: 0.05rem;
|
||||
line-height: 0.14rem;
|
||||
}
|
||||
|
||||
.checkobx__list {
|
||||
border-right-width: 0.01rem;
|
||||
border-right-color: $primary-color;
|
||||
border-right-style: solid;
|
||||
border-bottom-width:0.01rem;
|
||||
border-bottom-color: $primary-color;
|
||||
border-bottom-style: solid;
|
||||
height: 0.12rem;
|
||||
width: 0.06rem;
|
||||
left: -0.05rem;
|
||||
transform-origin: center;
|
||||
transform: rotate(45deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 多选样式
|
||||
.checkbox__inner {
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
border: 0.01rem solid $border-color;
|
||||
border-radius: 0.04rem;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
/* #ifdef APP-NVUE */
|
||||
top: 0.02rem;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
top: 0.01rem;
|
||||
/* #endif */
|
||||
left: 0.05rem;
|
||||
height: 0.08rem;
|
||||
width: 0.04rem;
|
||||
border-right-width: 0.01rem;
|
||||
border-right-color: #fff;
|
||||
border-right-style: solid;
|
||||
border-bottom-width:0.01rem ;
|
||||
border-bottom-color: #fff;
|
||||
border-bottom-style: solid;
|
||||
opacity: 0;
|
||||
transform-origin: center;
|
||||
transform: rotate(40deg);
|
||||
}
|
||||
}
|
||||
|
||||
// 单选样式
|
||||
.radio__inner {
|
||||
@include flex;
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
border: 0.01rem solid $border-color;
|
||||
border-radius: 0.16rem;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
|
||||
.radio__inner-icon {
|
||||
width: 0.08rem;
|
||||
height: 0.08rem;
|
||||
border-radius: 0.1rem;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认样式
|
||||
&.is--default {
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.radio__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// 选中
|
||||
&.is-checked {
|
||||
.checkbox__inner {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
.radio__inner {
|
||||
border-color: $checked-color;
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
background-color: $checked-color;
|
||||
}
|
||||
}
|
||||
.checklist-text {
|
||||
color: $checked-color;
|
||||
}
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
.checkbox__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
opacity: $disable;
|
||||
}
|
||||
.radio__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按钮样式
|
||||
&.is--button {
|
||||
margin-right: 0.1rem;
|
||||
padding: 0.05rem 0.1rem;
|
||||
border: 0.01rem $border-color solid;
|
||||
border-radius: 0.03rem;
|
||||
transition: border-color 0.2s;
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
border: 0.01rem #eee solid;
|
||||
opacity: $disable;
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.radio__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
border-color: $checked-color;
|
||||
.checkbox__inner {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
|
||||
.radio__inner {
|
||||
border-color: $checked-color;
|
||||
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
background-color: $checked-color;
|
||||
}
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
color: $checked-color;
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 标签样式
|
||||
&.is--tag {
|
||||
margin-right: 0.1rem;
|
||||
padding: 0.05rem 0.1rem;
|
||||
border: 0.01rem $border-color solid;
|
||||
border-radius: 0.3rem;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.checklist-text {
|
||||
margin: 0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
background-color: $checked-color;
|
||||
border-color: $checked-color;
|
||||
|
||||
.checklist-text {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 列表样式
|
||||
&.is--list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
padding: 0.1rem 0.15rem;
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
|
||||
&.is-list-border {
|
||||
border-top: 0.01rem #eee solid;
|
||||
}
|
||||
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
.checkbox__inner {
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
}
|
||||
.checklist-text {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-checked {
|
||||
.checkbox__inner {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
.radio__inner {
|
||||
.radio__inner-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.checklist-text {
|
||||
color: $checked-color;
|
||||
}
|
||||
|
||||
.checklist-content {
|
||||
.checkobx__list {
|
||||
opacity: 1;
|
||||
border-color: $checked-color;
|
||||
}
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
.checkbox__inner {
|
||||
opacity: $disable;
|
||||
}
|
||||
|
||||
.checklist-text {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
45
addon/cashier/source/os/components/uni-data-picker/keypress.js
Executable file
45
addon/cashier/source/os/components/uni-data-picker/keypress.js
Executable file
@@ -0,0 +1,45 @@
|
||||
// #ifdef H5
|
||||
export default {
|
||||
name: 'Keypress',
|
||||
props: {
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const keyNames = {
|
||||
esc: ['Esc', 'Escape'],
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
space: [' ', 'Spacebar'],
|
||||
up: ['Up', 'ArrowUp'],
|
||||
left: ['Left', 'ArrowLeft'],
|
||||
right: ['Right', 'ArrowRight'],
|
||||
down: ['Down', 'ArrowDown'],
|
||||
delete: ['Backspace', 'Delete', 'Del']
|
||||
}
|
||||
const listener = ($event) => {
|
||||
if (this.disable) {
|
||||
return
|
||||
}
|
||||
const keyName = Object.keys(keyNames).find(key => {
|
||||
const keyName = $event.key
|
||||
const value = keyNames[key]
|
||||
return value === keyName || (Array.isArray(value) && value.includes(keyName))
|
||||
})
|
||||
if (keyName) {
|
||||
// 避免和其他按键事件冲突
|
||||
setTimeout(() => {
|
||||
this.$emit(keyName, {})
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
document.addEventListener('keyup', listener)
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
document.removeEventListener('keyup', listener)
|
||||
})
|
||||
},
|
||||
render: () => {}
|
||||
}
|
||||
// #endif
|
||||
555
addon/cashier/source/os/components/uni-data-picker/uni-data-picker.vue
Executable file
555
addon/cashier/source/os/components/uni-data-picker/uni-data-picker.vue
Executable file
@@ -0,0 +1,555 @@
|
||||
<template>
|
||||
<view class="uni-data-tree">
|
||||
<view class="uni-data-tree-input" @click="handleInput">
|
||||
<slot :options="options" :data="inputSelected" :error="errorMessage">
|
||||
<view class="input-value" :class="{'input-value-border': border}">
|
||||
<text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
|
||||
<view v-else-if="loading && !isOpened" class="selected-area">
|
||||
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||
</view>
|
||||
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
|
||||
<view class="selected-list">
|
||||
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
|
||||
<text class="text-color">{{item.text}}</text>
|
||||
<text v-if="index<inputSelected.length-1" class="input-split-line">{{split}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<text v-else class="selected-area placeholder">{{placeholder}}</text>
|
||||
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" @click.stop="clear">
|
||||
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
|
||||
</view>
|
||||
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
|
||||
<view class="input-arrow"></view>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
|
||||
<view class="uni-data-tree-dialog" v-if="isOpened">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
<view class="dialog-caption">
|
||||
<view class="title-area">
|
||||
<text class="dialog-title">{{popupTitle}}</text>
|
||||
</view>
|
||||
<view class="dialog-close" @click="handleClose">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
</view>
|
||||
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
|
||||
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
|
||||
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
|
||||
:map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
|
||||
</data-picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
|
||||
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
|
||||
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
|
||||
|
||||
/**
|
||||
* DataPicker 级联选择
|
||||
* @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||
* @property {String} popup-title 弹出窗口标题
|
||||
* @property {Array} localdata 本地数据,参考
|
||||
* @property {Boolean} border = [true|false] 是否有边框
|
||||
* @property {Boolean} readonly = [true|false] 是否仅读
|
||||
* @property {Boolean} preload = [true|false] 是否预加载数据
|
||||
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
|
||||
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
|
||||
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||
* @value true 启用分布查询,仅查询当前选中节点
|
||||
* @value false 关闭分布查询,一次查询出所有数据
|
||||
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||
* @property {String|DBCollectionString} collection 表名
|
||||
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||
* @property {String} orderby 排序字段及正序倒叙设置
|
||||
* @property {String|JQLString} where 查询条件
|
||||
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
|
||||
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
|
||||
*/
|
||||
export default {
|
||||
name: 'UniDataPicker',
|
||||
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
|
||||
mixins: [dataPicker],
|
||||
components: {
|
||||
DataPickerView,
|
||||
uniLoadMore
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: [Object, Array],
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
popupTitle: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
heightMobile: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
clearIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
split: {
|
||||
type: String,
|
||||
default: '/'
|
||||
},
|
||||
ellipsis: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isOpened: false,
|
||||
inputSelected: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.getForm('uniForms')
|
||||
this.formItem = this.getForm('uniFormsItem')
|
||||
if (this.formItem) {
|
||||
if (this.formItem.name) {
|
||||
this.rename = this.formItem.name
|
||||
this.form.inputChildrens.push(this)
|
||||
}
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
clear() {
|
||||
this.inputSelected.splice(0)
|
||||
this._dispatchEvent([])
|
||||
},
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
if (this.readonly) {
|
||||
this._processReadonly(this.localdata, this.dataValue)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
} else if (!this.parentField && !this.selfField && this.hasValue) {
|
||||
this.getNodeData(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
})
|
||||
} else if (this.hasValue) {
|
||||
this.getTreePath(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
})
|
||||
}
|
||||
},
|
||||
getForm(name = 'uniForms') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
show() {
|
||||
this.isOpened = true
|
||||
setTimeout(() => {
|
||||
this.$refs.pickerView.updateData({
|
||||
treeData: this._treeData,
|
||||
selected: this.selected,
|
||||
selectedIndex: this.selectedIndex
|
||||
})
|
||||
}, 200)
|
||||
this.$emit('popupopened')
|
||||
},
|
||||
hide() {
|
||||
this.isOpened = false
|
||||
this.$emit('popupclosed')
|
||||
},
|
||||
handleInput() {
|
||||
if (this.readonly) {
|
||||
return
|
||||
}
|
||||
this.show()
|
||||
},
|
||||
handleClose(e) {
|
||||
this.hide()
|
||||
},
|
||||
onnodeclick(e) {
|
||||
this.$emit('nodeclick', e)
|
||||
},
|
||||
ondatachange(e) {
|
||||
this._treeData = this.$refs.pickerView._treeData
|
||||
},
|
||||
onchange(e) {
|
||||
this.hide()
|
||||
this.$nextTick(() => {
|
||||
this.inputSelected = e;
|
||||
})
|
||||
this._dispatchEvent(e)
|
||||
},
|
||||
_processReadonly(dataList, value) {
|
||||
var isTree = dataList.findIndex((item) => {
|
||||
return item.children
|
||||
})
|
||||
if (isTree > -1) {
|
||||
let inputValue
|
||||
if (Array.isArray(value)) {
|
||||
inputValue = value[value.length - 1]
|
||||
if (typeof inputValue === 'object' && inputValue.value) {
|
||||
inputValue = inputValue.value
|
||||
}
|
||||
} else {
|
||||
inputValue = value
|
||||
}
|
||||
this.inputSelected = this._findNodePath(inputValue, this.localdata)
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.hasValue) {
|
||||
this.inputSelected = []
|
||||
return
|
||||
}
|
||||
|
||||
let result = []
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
var val = value[i]
|
||||
var item = dataList.find((v) => {
|
||||
return v.value == val
|
||||
})
|
||||
if (item) {
|
||||
result.push(item)
|
||||
}
|
||||
}
|
||||
if (result.length) {
|
||||
this.inputSelected = result
|
||||
}
|
||||
},
|
||||
_filterForArray(data, valueArray) {
|
||||
var result = []
|
||||
for (let i = 0; i < valueArray.length; i++) {
|
||||
var value = valueArray[i]
|
||||
var found = data.find((item) => {
|
||||
return item.value == value
|
||||
})
|
||||
if (found) {
|
||||
result.push(found)
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
_dispatchEvent(selected) {
|
||||
let item = {}
|
||||
if (selected.length) {
|
||||
var value = new Array(selected.length)
|
||||
for (var i = 0; i < selected.length; i++) {
|
||||
value[i] = selected[i].value
|
||||
}
|
||||
item = selected[selected.length - 1]
|
||||
} else {
|
||||
item.value = ''
|
||||
}
|
||||
if (this.formItem) {
|
||||
this.formItem.setValue(item.value)
|
||||
}
|
||||
|
||||
this.$emit('input', item.value)
|
||||
this.$emit('update:modelValue', item.value)
|
||||
this.$emit('change', {
|
||||
detail: {
|
||||
value: selected
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style >
|
||||
.uni-data-tree {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #DD524D;
|
||||
}
|
||||
|
||||
.input-value {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
font-size: 14px;
|
||||
/* line-height: 35px; */
|
||||
padding: 0 10px;
|
||||
padding-right: 5px;
|
||||
overflow: hidden;
|
||||
height: 35px;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.input-value-border {
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.selected-area {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
/* #ifndef APP-NVUE */
|
||||
margin-right: auto;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 40px;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
/* padding: 0 5px; */
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
flex-direction: row;
|
||||
/* padding: 0 1px; */
|
||||
/* #ifndef APP-NVUE */
|
||||
white-space: nowrap;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: grey;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.input-split-line {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.arrow-area {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
/* #ifndef APP-NVUE */
|
||||
margin-bottom: 5px;
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
transform: rotate(-45deg);
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.input-arrow {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-left: 1px solid #999;
|
||||
border-bottom: 1px solid #999;
|
||||
}
|
||||
|
||||
.uni-data-tree-cover {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, .4);
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.uni-data-tree-dialog {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 20%;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #FFFFFF;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
z-index: 102;
|
||||
overflow: hidden;
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 750rpx;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.dialog-caption {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
}
|
||||
|
||||
.title-area {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
margin: auto;
|
||||
/* #endif */
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
/* font-weight: bold; */
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.dialog-close-plus {
|
||||
width: 16px;
|
||||
height: 2px;
|
||||
background-color: #666;
|
||||
border-radius: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.dialog-close-rotate {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.picker-view {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon-clear {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* #ifdef H5 */
|
||||
@media all and (min-width: 768px) {
|
||||
.uni-data-tree-cover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.uni-data-tree-dialog {
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
height: auto;
|
||||
min-height: 400px;
|
||||
max-height: 50vh;
|
||||
background-color: #fff;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
overflow: unset;
|
||||
}
|
||||
|
||||
.dialog-caption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.icon-clear {
|
||||
/* margin-right: 5px; */
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
|
||||
/* #ifndef APP-NVUE */
|
||||
.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;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
563
addon/cashier/source/os/components/uni-data-pickerview/uni-data-picker.js
Executable file
563
addon/cashier/source/os/components/uni-data-pickerview/uni-data-picker.js
Executable file
@@ -0,0 +1,563 @@
|
||||
export default {
|
||||
props: {
|
||||
localdata: {
|
||||
type: [Array, Object],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
spaceInfo: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
collection: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
action: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
field: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
orderby: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
where: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
pageData: {
|
||||
type: String,
|
||||
default: 'add'
|
||||
},
|
||||
pageCurrent: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
getcount: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
getone: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
gettree: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
manual: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: [Array, String, Number],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
modelValue: {
|
||||
type: [Array, String, Number],
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
preload: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
stepSearh: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selfField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
parentField: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
map: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
text: "text",
|
||||
value: "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
errorMessage: '',
|
||||
loadMore: {
|
||||
contentdown: '',
|
||||
contentrefresh: '',
|
||||
contentnomore: ''
|
||||
},
|
||||
dataList: [],
|
||||
selected: [],
|
||||
selectedIndex: 0,
|
||||
page: {
|
||||
current: this.pageCurrent,
|
||||
size: this.pageSize,
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLocaldata() {
|
||||
return !this.collection.length
|
||||
},
|
||||
postField() {
|
||||
let fields = [this.field];
|
||||
if (this.parentField) {
|
||||
fields.push(`${this.parentField} as parent_value`);
|
||||
}
|
||||
return fields.join(',');
|
||||
},
|
||||
dataValue() {
|
||||
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
|
||||
return isModelValue ? this.modelValue : this.value
|
||||
},
|
||||
hasValue() {
|
||||
if (typeof this.dataValue === 'number') {
|
||||
return true
|
||||
}
|
||||
return (this.dataValue != null) && (this.dataValue.length > 0)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$watch(() => {
|
||||
var al = [];
|
||||
['pageCurrent',
|
||||
'pageSize',
|
||||
'spaceInfo',
|
||||
'value',
|
||||
'modelValue',
|
||||
'localdata',
|
||||
'collection',
|
||||
'action',
|
||||
'field',
|
||||
'orderby',
|
||||
'where',
|
||||
'getont',
|
||||
'getcount',
|
||||
'gettree'
|
||||
].forEach(key => {
|
||||
al.push(this[key])
|
||||
});
|
||||
return al
|
||||
}, (newValue, oldValue) => {
|
||||
let needReset = false
|
||||
for (let i = 2; i < newValue.length; i++) {
|
||||
if (newValue[i] != oldValue[i]) {
|
||||
needReset = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (newValue[0] != oldValue[0]) {
|
||||
this.page.current = this.pageCurrent
|
||||
}
|
||||
this.page.size = this.pageSize
|
||||
|
||||
this.onPropsChange()
|
||||
})
|
||||
this._treeData = []
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
},
|
||||
getCommand(options = {}) {
|
||||
/* eslint-disable no-undef */
|
||||
let db = uniCloud.database(this.spaceInfo)
|
||||
|
||||
const action = options.action || this.action
|
||||
if (action) {
|
||||
db = db.action(action)
|
||||
}
|
||||
|
||||
const collection = options.collection || this.collection
|
||||
db = db.collection(collection)
|
||||
|
||||
const where = options.where || this.where
|
||||
if (!(!where || !Object.keys(where).length)) {
|
||||
db = db.where(where)
|
||||
}
|
||||
|
||||
const field = options.field || this.field
|
||||
if (field) {
|
||||
db = db.field(field)
|
||||
}
|
||||
|
||||
const orderby = options.orderby || this.orderby
|
||||
if (orderby) {
|
||||
db = db.orderBy(orderby)
|
||||
}
|
||||
|
||||
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
|
||||
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
|
||||
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
|
||||
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
|
||||
|
||||
const getOptions = {
|
||||
getCount,
|
||||
getTree
|
||||
}
|
||||
if (options.getTreePath) {
|
||||
getOptions.getTreePath = options.getTreePath
|
||||
}
|
||||
|
||||
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
|
||||
|
||||
return db
|
||||
},
|
||||
getNodeData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: this._pathWhere()
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
this.selected = res.result.data
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
getTreePath(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
getTreePath: {
|
||||
startWith: `${this.selfField}=='${this.dataValue}'`
|
||||
}
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
let treePath = []
|
||||
this._extractTreePath(res.result.data, treePath)
|
||||
this.selected = treePath
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
loadData() {
|
||||
if (this.isLocaldata) {
|
||||
this._processLocalData()
|
||||
return
|
||||
}
|
||||
|
||||
if (this.dataValue != null) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
this._updateSelected()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (this.stepSearh) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
})
|
||||
} else {
|
||||
this._loadAllData((data) => {
|
||||
this._treeData = []
|
||||
this._extractTree(data, this._treeData, null)
|
||||
this._updateBindData()
|
||||
})
|
||||
}
|
||||
},
|
||||
_loadAllData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
gettree: true,
|
||||
startwith: `${this.selfField}=='${this.dataValue}'`
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_loadNodeData(callback, pw) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: pw || this._postWhere(),
|
||||
pageSize: 500
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_pathWhere() {
|
||||
let result = []
|
||||
let where_field = this._getParentNameByField();
|
||||
if (where_field) {
|
||||
result.push(`${where_field} == '${this.dataValue}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${result.join(' || ')})`
|
||||
}
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_postWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
let parentField = this.parentField
|
||||
if (parentField) {
|
||||
result.push(`${parentField} == null || ${parentField} == ""`)
|
||||
}
|
||||
if (selected.length) {
|
||||
for (var i = 0; i < selected.length - 1; i++) {
|
||||
result.push(`${parentField} == '${selected[i].value}'`)
|
||||
}
|
||||
}
|
||||
|
||||
let where = []
|
||||
if (this.where) {
|
||||
where.push(`(${this.where})`)
|
||||
}
|
||||
if (result.length) {
|
||||
where.push(`(${result.join(' || ')})`)
|
||||
}
|
||||
|
||||
return where.join(' && ')
|
||||
},
|
||||
_nodeWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
if (selected.length) {
|
||||
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${result.join(' || ')})`
|
||||
}
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_getParentNameByField() {
|
||||
const fields = this.field.split(',');
|
||||
let where_field = null;
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const items = fields[i].split('as');
|
||||
if (items.length < 2) {
|
||||
continue;
|
||||
}
|
||||
if (items[1].trim() === 'value') {
|
||||
where_field = items[0].trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where_field
|
||||
},
|
||||
_isTreeView() {
|
||||
return (this.parentField && this.selfField)
|
||||
},
|
||||
_updateSelected() {
|
||||
var dl = this.dataList
|
||||
var sl = this.selected
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (var i = 0; i < sl.length; i++) {
|
||||
var value = sl[i].value
|
||||
var dl2 = dl[i]
|
||||
for (var j = 0; j < dl2.length; j++) {
|
||||
var item2 = dl2[j]
|
||||
if (item2[valueField] === value) {
|
||||
sl[i].text = item2[textField]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_updateBindData(node) {
|
||||
const {
|
||||
dataList,
|
||||
hasNodes
|
||||
} = this._filterData(this._treeData, this.selected)
|
||||
|
||||
let isleaf = this._stepSearh === false && !hasNodes
|
||||
|
||||
if (node) {
|
||||
node.isleaf = isleaf
|
||||
}
|
||||
|
||||
this.dataList = dataList
|
||||
this.selectedIndex = dataList.length - 1
|
||||
|
||||
if (!isleaf && this.selected.length < dataList.length) {
|
||||
this.selected.push({
|
||||
value: null,
|
||||
text: "请选择"
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
isleaf,
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
_filterData(data, paths) {
|
||||
let dataList = []
|
||||
let hasNodes = true
|
||||
|
||||
dataList.push(data.filter((item) => {
|
||||
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
|
||||
}))
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
var value = paths[i].value
|
||||
var nodes = data.filter((item) => {
|
||||
return item.parent_value === value
|
||||
})
|
||||
|
||||
if (nodes.length) {
|
||||
dataList.push(nodes)
|
||||
} else {
|
||||
hasNodes = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dataList,
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
_extractTree(nodes, result, parent_value) {
|
||||
let list = result || []
|
||||
let valueField = this.map.value
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
|
||||
let child = {}
|
||||
for (let key in node) {
|
||||
if (key !== 'children') {
|
||||
child[key] = node[key]
|
||||
}
|
||||
}
|
||||
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
|
||||
child.parent_value = parent_value
|
||||
}
|
||||
result.push(child)
|
||||
|
||||
let children = node.children
|
||||
if (children) {
|
||||
this._extractTree(children, result, node[valueField])
|
||||
}
|
||||
}
|
||||
},
|
||||
_extractTreePath(nodes, result) {
|
||||
let list = result || []
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
|
||||
let child = {}
|
||||
for (let key in node) {
|
||||
if (key !== 'children') {
|
||||
child[key] = node[key]
|
||||
}
|
||||
}
|
||||
result.push(child)
|
||||
|
||||
let children = node.children
|
||||
if (children) {
|
||||
this._extractTreePath(children, result)
|
||||
}
|
||||
}
|
||||
},
|
||||
_findNodePath(key, nodes, path = []) {
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let node = nodes[i]
|
||||
let children = node.children
|
||||
let text = node[textField]
|
||||
let value = node[valueField]
|
||||
|
||||
path.push({
|
||||
value,
|
||||
text
|
||||
})
|
||||
|
||||
if (value === key) {
|
||||
return path
|
||||
}
|
||||
|
||||
if (children) {
|
||||
const p = this._findNodePath(key, children, path)
|
||||
if (p.length) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
|
||||
path.pop()
|
||||
}
|
||||
return []
|
||||
},
|
||||
_processLocalData() {
|
||||
this._treeData = []
|
||||
this._extractTree(this.localdata, this._treeData)
|
||||
|
||||
var inputValue = this.dataValue
|
||||
if (inputValue === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(inputValue)) {
|
||||
inputValue = inputValue[inputValue.length - 1]
|
||||
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
|
||||
inputValue = inputValue[this.map.value]
|
||||
}
|
||||
}
|
||||
|
||||
this.selected = this._findNodePath(inputValue, this.localdata)
|
||||
}
|
||||
}
|
||||
}
|
||||
330
addon/cashier/source/os/components/uni-data-pickerview/uni-data-pickerview.vue
Executable file
330
addon/cashier/source/os/components/uni-data-pickerview/uni-data-pickerview.vue
Executable file
@@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<view class="uni-data-pickerview">
|
||||
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
|
||||
<view class="selected-list">
|
||||
<template v-for="(item,index) in selected">
|
||||
<view class="selected-item" :class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}" v-if="item.text" @click="handleSelect(index)">
|
||||
<text>{{item.text}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-c">
|
||||
<template v-for="(child, i) in dataList" >
|
||||
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
|
||||
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child" @click="handleNodeClick(item, i, j)">
|
||||
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
|
||||
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<view class="loading-cover" v-if="loading">
|
||||
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||
</view>
|
||||
<view class="error-message" v-if="errorMessage">
|
||||
<text class="error-text">{{errorMessage}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dataPicker from "./uni-data-picker.js"
|
||||
|
||||
/**
|
||||
* DataPickerview
|
||||
* @description uni-data-pickerview
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
|
||||
* @property {Array} localdata 本地数据,参考
|
||||
* @property {Boolean} step-searh = [true|false] 是否分布查询
|
||||
* @value true 启用分布查询,仅查询当前选中节点
|
||||
* @value false 关闭分布查询,一次查询出所有数据
|
||||
* @property {String|DBFieldString} self-field 分布查询当前字段名称
|
||||
* @property {String|DBFieldString} parent-field 分布查询父字段名称
|
||||
* @property {String|DBCollectionString} collection 表名
|
||||
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
|
||||
* @property {String} orderby 排序字段及正序倒叙设置
|
||||
* @property {String|JQLString} where 查询条件
|
||||
*/
|
||||
export default {
|
||||
name: 'UniDataPickerView',
|
||||
emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
|
||||
mixins: [dataPicker],
|
||||
props: {
|
||||
managedMode: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
ellipsis: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (this.managedMode) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
} else if (this.dataValue.length) {
|
||||
this.getTreePath((res) => {
|
||||
this.loadData()
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelect(index) {
|
||||
this.selectedIndex = index
|
||||
},
|
||||
handleNodeClick(item, i, j) {
|
||||
if (item.disable) {
|
||||
return
|
||||
}
|
||||
const node = this.dataList[i][j]
|
||||
const text = node[this.map.text]
|
||||
const value = node[this.map.value]
|
||||
if (i < this.selected.length - 1) {
|
||||
this.selected.splice(i, this.selected.length - i)
|
||||
this.selected.push({
|
||||
text,
|
||||
value
|
||||
})
|
||||
} else if (i === this.selected.length - 1) {
|
||||
this.selected.splice(i, 1, {
|
||||
text,
|
||||
value
|
||||
})
|
||||
}
|
||||
|
||||
if (node.isleaf) {
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
return
|
||||
}
|
||||
|
||||
const {
|
||||
isleaf,
|
||||
hasNodes
|
||||
} = this._updateBindData()
|
||||
|
||||
if (!this._isTreeView() && !hasNodes) {
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLocaldata && (!hasNodes || isleaf)) {
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isleaf && !hasNodes) {
|
||||
this._loadNodeData((data) => {
|
||||
if (!data.length) {
|
||||
node.isleaf = true
|
||||
} else {
|
||||
this._treeData.push(...data)
|
||||
this._updateBindData(node)
|
||||
}
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
}, this._nodeWhere())
|
||||
return
|
||||
}
|
||||
|
||||
this.onSelectedChange(node, false)
|
||||
},
|
||||
updateData(data) {
|
||||
this._treeData = data.treeData
|
||||
this.selected = data.selected
|
||||
if (!this._treeData.length) {
|
||||
this.loadData()
|
||||
} else {
|
||||
//this.selected = data.selected
|
||||
this._updateBindData()
|
||||
}
|
||||
},
|
||||
onDataChange() {
|
||||
this.$emit('datachange')
|
||||
},
|
||||
onSelectedChange(node, isleaf) {
|
||||
if (isleaf) {
|
||||
this._dispatchEvent()
|
||||
}
|
||||
|
||||
if (node) {
|
||||
this.$emit('nodeclick', node)
|
||||
}
|
||||
},
|
||||
_dispatchEvent() {
|
||||
this.$emit('change', this.selected.slice(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.uni-data-pickerview {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #DD524D;
|
||||
}
|
||||
|
||||
.loading-cover {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
/* #ifndef APP-NVUE */
|
||||
margin: auto;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 15px;
|
||||
opacity: .9;
|
||||
z-index: 102;
|
||||
}
|
||||
|
||||
/* #ifdef APP-NVUE */
|
||||
.selected-area {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.selected-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 5px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
}
|
||||
|
||||
.selected-item {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
padding: 12px 0;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
white-space: nowrap;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-item-text-overflow {
|
||||
width: 168px;
|
||||
/* fix nvue */
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 6em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.selected-item-active {
|
||||
border-bottom: 2px solid $primary-color;
|
||||
}
|
||||
|
||||
.selected-item-text {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.tab-c {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 12px 15px;
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
/* flex: 1; */
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.item-text-overflow {
|
||||
width: 280px;
|
||||
/* fix nvue */
|
||||
overflow: hidden;
|
||||
/* #ifndef APP-NVUE */
|
||||
width: 20em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
-o-text-overflow: ellipsis;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-right: 5px;
|
||||
border: 2px solid $primary-color;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
height: 12px;
|
||||
width: 6px;
|
||||
transform-origin: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
transition: all 0.3s;
|
||||
/* #endif */
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
435
addon/cashier/source/os/components/uni-data-select/uni-data-select.vue
Executable file
435
addon/cashier/source/os/components/uni-data-select/uni-data-select.vue
Executable file
@@ -0,0 +1,435 @@
|
||||
<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">{{current}}</view>
|
||||
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
|
||||
<uni-icons v-if="current && clear" type="clear" color="#c0c4cc" size="24" @click="clearVal" />
|
||||
<uni-icons v-else :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
|
||||
</view>
|
||||
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
|
||||
<view class="uni-select__selector" v-if="showSelector">
|
||||
<view class="uni-popper__arrow"></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 是否禁用
|
||||
* @event {Function} change 选中发生变化触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: "uni-stat-select",
|
||||
mixins: [uniCloud.mixinDatacom || {}],
|
||||
data() {
|
||||
return {
|
||||
showSelector: false,
|
||||
current: '',
|
||||
mixinDatacomResData: [],
|
||||
apps: [],
|
||||
channels: []
|
||||
};
|
||||
},
|
||||
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
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.last = `${this.collection}_last_selected_option_value`
|
||||
if (this.collection && !this.localdata.length) {
|
||||
this.mixinDatacomEasyGet()
|
||||
}
|
||||
},
|
||||
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
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
localdata: {
|
||||
immediate: true,
|
||||
handler(val, old) {
|
||||
if (Array.isArray(val) && old !== val) {
|
||||
this.mixinDatacomResData = val
|
||||
}
|
||||
}
|
||||
},
|
||||
// #ifndef VUE3
|
||||
value() {
|
||||
this.initDefVal()
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
modelValue() {
|
||||
this.initDefVal()
|
||||
},
|
||||
// #endif
|
||||
mixinDatacomResData: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (val.length) {
|
||||
this.initDefVal()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initDefVal() {
|
||||
let defValue = ''
|
||||
if ((this.value || this.value === 0) && !this.isDisabled(this.value)) {
|
||||
defValue = this.value
|
||||
} else if ((this.modelValue || this.modelValue === 0) && !this.isDisabled(this.modelValue)) {
|
||||
defValue = this.modelValue
|
||||
} else {
|
||||
let strogeValue
|
||||
if (this.collection) {
|
||||
strogeValue = uni.getStorageSync(this.last)
|
||||
}
|
||||
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
|
||||
}
|
||||
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) {
|
||||
uni.removeStorageSync(this.last)
|
||||
}
|
||||
},
|
||||
change(item) {
|
||||
if (!item.disable) {
|
||||
this.showSelector = false
|
||||
this.current = this.formatItemName(item)
|
||||
this.emit(item.value)
|
||||
}
|
||||
},
|
||||
emit(val) {
|
||||
this.$emit('change', val)
|
||||
this.$emit('input', val)
|
||||
this.$emit('update:modelValue', val)
|
||||
if (this.collection) {
|
||||
uni.setStorageSync(this.last, val)
|
||||
}
|
||||
},
|
||||
|
||||
toggleSelector() {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.showSelector = !this.showSelector
|
||||
},
|
||||
formatItemName(item) {
|
||||
let {
|
||||
text,
|
||||
value,
|
||||
channel_code
|
||||
} = item
|
||||
channel_code = channel_code ? `(${channel_code})` : ''
|
||||
return this.collection.indexOf('app-list') > 0 ?
|
||||
`${text}(${value})` :
|
||||
(
|
||||
text ? text : `未命名${channel_code}`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</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;
|
||||
cursor: pointer;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
.uni-select__selector-scroll {
|
||||
/* #ifndef APP-NVUE */
|
||||
max-height: 200px;
|
||||
box-sizing: border-box;
|
||||
/* #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,
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
416
addon/cashier/source/os/components/uni-data-table/uni-data-table-new.vue
Executable file
416
addon/cashier/source/os/components/uni-data-table/uni-data-table-new.vue
Executable file
@@ -0,0 +1,416 @@
|
||||
<template>
|
||||
<view class="table-container">
|
||||
<view class="thead">
|
||||
<view class="th" v-for="(th, thIndex) in cols" :key="thIndex" :style="{ flex: th.width, maxWidth: th.width + '%', textAlign: th.align ? th.align : 'center' }">
|
||||
<view class="content">
|
||||
<block v-if="th.checkbox">
|
||||
<view class="all-select" @mouseenter="allSelectShow()" @mouseleave="allSelectHide()">
|
||||
<view class="all-select-label">
|
||||
<text>全选<text v-if="allSelect.num > 0">({{ allSelect.num }})</text></text>
|
||||
<text class="iconfont iconxiala"></text>
|
||||
</view>
|
||||
<view class="all-select-option" :style="allSelect.show? 'display:block;' : ''">
|
||||
<view
|
||||
v-for="(oVal) in allSelect.optionList"
|
||||
:class="allSelect.hoverOption==oVal.id? 'on' : ''"
|
||||
@mouseenter="allSelect.hoverOption = oVal.id"
|
||||
@click="allSelectClick(oVal)"
|
||||
>{{ oVal.name }}
|
||||
<text v-if="(oVal.id == 'curr' && allSelect.pageSelected[page]) || (oVal.id == 'all' && allSelect.selected)" style="color:red;margin-left: 4px;">√</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<text v-else>{{ th.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tbody">
|
||||
<view class="tr" v-for="(d, index) in list" :key="index" v-if="list.length">
|
||||
<view class="td" v-for="(th, thIndex) in cols" :key="thIndex" :style="{ flex: th.width, maxWidth: th.width + '%', textAlign: th.align ? th.align : 'center' }">
|
||||
<view class="content" :class="{ action: th.action }">
|
||||
<view v-if="th.checkbox">
|
||||
<text v-if="typeof th.disabled == 'function' && th.disabled(d)" class="iconfont iconfuxuankuang2 disabled"></text>
|
||||
<text v-else @click="single(d, index)" class="iconfont" :class="{
|
||||
iconfuxuankuang2: Boolean(selectedData[d[pk]]) == false,
|
||||
iconfuxuankuang1: Boolean(selectedData[d[pk]]) == true,
|
||||
}"></text>
|
||||
</view>
|
||||
<slot v-else-if="th.action" name="action" :value="d" :index="index"></slot>
|
||||
<view v-else-if="th.templet" v-html="th.templet(d)"></view>
|
||||
<view v-else-if="th.return">{{ th.return(d) }}</view>
|
||||
<view v-else>{{ d[th.field] }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tr empty" v-if="!list.length">
|
||||
<view class="td">
|
||||
<view class="iconfont iconwushuju"></view>
|
||||
<view>暂无数据</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tpage" v-if="list.length && classType == false">
|
||||
<view class="batch-action">
|
||||
<slot name="batchaction" :value="selected"></slot>
|
||||
</view>
|
||||
<uni-pagination :total="total" :showIcon="true" @change="pageChange" :pageSize="pagesize" :value="page" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'uniDataTableNew',
|
||||
props: {
|
||||
cols: {
|
||||
type: Array
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
pagesize: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
classType: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
data: {
|
||||
type: Object | Array,
|
||||
default: function () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
pk: {//主键id
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.url && this.load({page:1});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
selected: [],
|
||||
selectedIndex: [],
|
||||
selectedData:{},
|
||||
unselectedData:{},
|
||||
page: 1,
|
||||
total: 0,
|
||||
pageCount:0,
|
||||
allSelect:{
|
||||
optionList:[
|
||||
{id:'curr',name:'当前页'},
|
||||
{id:'all',name:'所有页'},
|
||||
],
|
||||
show:false,
|
||||
num:0,
|
||||
hoverOption:'',
|
||||
selected:false,//所有页选中
|
||||
pageSelected:{},
|
||||
},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler(nVal, oVal) {
|
||||
if (Object.keys(nVal).length) this.list = Object.values(nVal)
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
allSelectShow(){
|
||||
this.allSelect.show = true;
|
||||
},
|
||||
allSelectHide(){
|
||||
this.allSelect.show = false;
|
||||
this.allSelect.hoverOption = '';
|
||||
},
|
||||
allSelectInitData(){
|
||||
this.allSelect.pageSelected = {};
|
||||
this.allSelect.selected = false;
|
||||
if(this.pageCount > 0){
|
||||
for(let i = 1; i < this.pageCount; i++){
|
||||
this.allSelect.pageSelected[i] = false;
|
||||
}
|
||||
}
|
||||
this.selectedData = {};
|
||||
this.unselectedData = {};
|
||||
this.allSelect.num = 0;
|
||||
},
|
||||
allSelectClick(item){
|
||||
if(item.id == 'curr'){
|
||||
this.allSelect.pageSelected[this.page] = !this.allSelect.pageSelected[this.page];
|
||||
}else{
|
||||
this.allSelect.selected = !this.allSelect.selected;
|
||||
for(let i in this.allSelect.pageSelected){
|
||||
this.allSelect.pageSelected[i] = this.allSelect.selected;
|
||||
}
|
||||
if(!this.allSelect.selected){
|
||||
this.selectedData = {};
|
||||
this.unselectedData = {};
|
||||
}
|
||||
}
|
||||
this.handleSelectData();
|
||||
this.allSelectNum();
|
||||
this.allSelectHide();
|
||||
},
|
||||
allSelectNum(){
|
||||
if(this.allSelect.selected){
|
||||
this.allSelect.num = this.total - Object.values(this.unselectedData).length;
|
||||
}else{
|
||||
this.allSelect.num = Object.values(this.selectedData).length;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
handleSelectData() {
|
||||
if (this.list.length) {
|
||||
let firstTh = this.cols[0];
|
||||
if(this.allSelect.pageSelected[this.page]){
|
||||
this.list.forEach((item)=>{
|
||||
if (typeof firstTh.disabled == 'function' && firstTh.disabled(item)) return;
|
||||
if(!this.selectedData[item[this.pk]]){
|
||||
this.selectedData[item[this.pk]] = item;
|
||||
}
|
||||
if(this.unselectedData[item[this.pk]]){
|
||||
delete this.unselectedData[item[this.pk]];
|
||||
}
|
||||
})
|
||||
}else{
|
||||
this.list.forEach((item)=>{
|
||||
if (typeof firstTh.disabled == 'function' && firstTh.disabled(item)) return;
|
||||
if(!this.unselectedData[item[this.pk]]){
|
||||
this.unselectedData[item[this.pk]] = item;
|
||||
}
|
||||
if(this.selectedData[item[this.pk]]){
|
||||
delete this.selectedData[item[this.pk]];
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 单选
|
||||
* @param {Object} item
|
||||
* @param {Object} index
|
||||
*/
|
||||
single(item, index) {
|
||||
if(this.selectedData[item[this.pk]]){
|
||||
delete this.selectedData[item[this.pk]];
|
||||
}else{
|
||||
this.selectedData[item[this.pk]] = item;
|
||||
}
|
||||
if(this.unselectedData[item[this.pk]]){
|
||||
delete this.unselectedData[item[this.pk]];
|
||||
}else{
|
||||
this.unselectedData[item[this.pk]] = item;
|
||||
}
|
||||
this.allSelectNum();
|
||||
},
|
||||
/**
|
||||
* 设置默认选中数据
|
||||
*/
|
||||
defaultSelectData(selected, selectedIndex) {
|
||||
this.selected = selected;
|
||||
this.selectedIndex = selectedIndex;
|
||||
},
|
||||
pageChange(e) {
|
||||
this.page = e.current;
|
||||
this.load();
|
||||
this.$emit('pageChange', this.page);
|
||||
},
|
||||
load(option = {}) {
|
||||
let data = {
|
||||
page: option.page || this.page,
|
||||
page_size: this.pagesize
|
||||
};
|
||||
if (this.option) Object.assign(data, this.option);
|
||||
if (option) Object.assign(data, option);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: this.url,
|
||||
data: data,
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.list = res.data.list;
|
||||
this.total = res.data.count;
|
||||
this.pageCount = res.data.page_count;
|
||||
|
||||
this.selected = [];
|
||||
this.selectedIndex = [];
|
||||
this.$emit('tableData', this.list);
|
||||
if (option.page) {
|
||||
this.page = option.page;
|
||||
if(option.page == 1){
|
||||
this.allSelectInitData();
|
||||
}
|
||||
delete option.page;
|
||||
}
|
||||
this.handleSelectData();
|
||||
} else {
|
||||
this.$util.showToast({ title: res.message });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
this.$util.showToast({ title: '请求失败' });
|
||||
}
|
||||
});
|
||||
},
|
||||
//库存页面清除选中
|
||||
clearCheck() {
|
||||
this.allSelectInitData();
|
||||
},
|
||||
//返回选择数据
|
||||
getSelectData(){
|
||||
return {
|
||||
selectedData: this.selectedData,
|
||||
unselectedData: this.unselectedData,
|
||||
allSelected: this.allSelect.selected,
|
||||
selectedNum: this.allSelect.num,
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.table-container {
|
||||
width: 100%;
|
||||
|
||||
.iconcheckbox_weiquanxuan,
|
||||
.iconfuxuankuang1,
|
||||
.iconfuxuankuang2 {
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
font-size: 0.16rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.iconfuxuankuang2 {
|
||||
color: #e6e6e6;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background: #eee;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
color: #e6e6e6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.thead {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
background: #f7f8fa;
|
||||
align-items: center;
|
||||
|
||||
.th {
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
/* overflow: hidden; */
|
||||
text-overflow: ellipsis;
|
||||
.all-select{
|
||||
position: relative;
|
||||
.all-select-label{
|
||||
cursor: pointer;
|
||||
padding:4px;
|
||||
}
|
||||
.all-select-option{
|
||||
position: absolute;
|
||||
display: none;
|
||||
left:50%;
|
||||
transform: translateX(-50%);
|
||||
background: #fff;
|
||||
padding: 4px 0;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0px 0px 2px #ccc;
|
||||
view{
|
||||
color: #000;
|
||||
cursor:pointer;
|
||||
margin: 4px 0;
|
||||
padding:4px 20px;
|
||||
&.on{
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tr {
|
||||
display: flex;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
min-height: 0.5rem;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
padding: 0.1rem 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.td {
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty {
|
||||
justify-content: center;
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
|
||||
.iconfont {
|
||||
font-size: 0.25rem;
|
||||
margin: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tpage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.1rem 0;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
.uni-pagination {
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
294
addon/cashier/source/os/components/uni-data-table/uni-data-table.vue
Executable file
294
addon/cashier/source/os/components/uni-data-table/uni-data-table.vue
Executable file
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<view class="table-container">
|
||||
<view class="thead">
|
||||
<view class="th" v-for="(th, thIndex) in cols" :key="thIndex" :style="{ flex: th.width, maxWidth: th.width + '%', textAlign: th.align ? th.align : 'center' }">
|
||||
<view class="content">
|
||||
<view v-if="th.checkbox" class="iconfont" @click="all" :class="{
|
||||
iconfuxuankuang2: selected.length == 0,
|
||||
iconcheckbox_weiquanxuan: selected.length != list.length,
|
||||
iconfuxuankuang1: selected.length > 0 && selected.length == list.length
|
||||
}"></view>
|
||||
<text v-else>{{ th.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tbody">
|
||||
<view class="tr" v-for="(d, index) in list" :key="index" v-if="list.length">
|
||||
<view class="td" v-for="(th, thIndex) in cols" :key="thIndex" :style="{ flex: th.width, maxWidth: th.width + '%', textAlign: th.align ? th.align : 'center' }">
|
||||
<view class="content" :class="{ action: th.action }">
|
||||
<view v-if="th.checkbox">
|
||||
<text v-if="typeof th.disabled == 'function' && th.disabled(d)" class="iconfont iconfuxuankuang2 disabled"></text>
|
||||
<text v-else @click="single(d, index)" class="iconfont" :class="{
|
||||
iconfuxuankuang2: selectedIndex.indexOf(index) == -1,
|
||||
iconfuxuankuang1: selectedIndex.indexOf(index) != -1
|
||||
}"></text>
|
||||
</view>
|
||||
<slot v-else-if="th.action" name="action" :value="d" :index="index"></slot>
|
||||
<view v-else-if="th.templet" v-html="th.templet(d)"></view>
|
||||
<view v-else-if="th.return">{{ th.return(d) }}</view>
|
||||
<view v-else>{{ d[th.field] }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tr empty" v-if="!list.length">
|
||||
<view class="td">
|
||||
<view class="iconfont iconwushuju"></view>
|
||||
<view>暂无数据</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tpage" v-if="list.length && classType == false">
|
||||
<view class="batch-action">
|
||||
<slot name="batchaction" :value="selected"></slot>
|
||||
</view>
|
||||
<uni-pagination :total="total" :showIcon="true" @change="pageChange" :pageSize="pagesize" :value="page" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'uniDataTable',
|
||||
props: {
|
||||
cols: {
|
||||
type: Array
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
pagesize: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
option: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
classType: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
data: {
|
||||
type: Object | Array,
|
||||
default: function () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.url && this.load();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
selected: [],
|
||||
selectedIndex: [],
|
||||
page: 1,
|
||||
total: 0
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
data: {
|
||||
handler(nVal, oVal) {
|
||||
if (Object.keys(nVal).length) this.list = Object.values(nVal)
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 全选
|
||||
*/
|
||||
all() {
|
||||
if (this.list.length) {
|
||||
if (this.selected.length == this.list.length) {
|
||||
this.selected = [];
|
||||
this.selectedIndex = [];
|
||||
} else {
|
||||
let selectedIndex = [],
|
||||
selected = [],
|
||||
firstTh = this.cols[0];
|
||||
this.list.forEach((item, index) => {
|
||||
if (typeof firstTh.disabled == 'function' && firstTh.disabled(item)) return;
|
||||
selectedIndex.push(index);
|
||||
selected.push(item);
|
||||
});
|
||||
this.selectedIndex = selectedIndex;
|
||||
this.selected = selected;
|
||||
}
|
||||
this.$emit('checkBox', this.selected);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 单选
|
||||
* @param {Object} item
|
||||
* @param {Object} index
|
||||
*/
|
||||
single(item, index) {
|
||||
let _index = this.selectedIndex.indexOf(index);
|
||||
if (_index == -1) {
|
||||
this.selectedIndex.push(index);
|
||||
this.selected.push(item);
|
||||
} else {
|
||||
this.selectedIndex.splice(_index, 1);
|
||||
this.selected.splice(_index, 1);
|
||||
}
|
||||
this.$emit('checkBox', this.selected, this.selectedIndex);
|
||||
},
|
||||
/**
|
||||
* 设置默认选中数据
|
||||
*/
|
||||
defaultSelectData(selected, selectedIndex) {
|
||||
this.selected = selected;
|
||||
this.selectedIndex = selectedIndex;
|
||||
},
|
||||
pageChange(e) {
|
||||
this.page = e.current;
|
||||
this.load();
|
||||
this.$emit('pageChange', this.page);
|
||||
},
|
||||
load(option = {}) {
|
||||
let data = {
|
||||
page: option.page || this.page,
|
||||
page_size: this.pagesize
|
||||
};
|
||||
if (this.option) Object.assign(data, this.option);
|
||||
if (option) Object.assign(data, option);
|
||||
|
||||
this.$api.sendRequest({
|
||||
url: this.url,
|
||||
data: data,
|
||||
success: res => {
|
||||
if (res.code >= 0) {
|
||||
this.list = res.data.list;
|
||||
this.total = res.data.count;
|
||||
|
||||
this.selected = [];
|
||||
this.selectedIndex = [];
|
||||
this.$emit('tableData', this.list);
|
||||
if (option.page) {
|
||||
this.page = option.page;
|
||||
delete option.page;
|
||||
}
|
||||
} else {
|
||||
this.$util.showToast({ title: res.message });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
this.$util.showToast({ title: '请求失败' });
|
||||
}
|
||||
});
|
||||
},
|
||||
clearCheck() {//库存页面清除选中
|
||||
this.selected = [];
|
||||
this.selectedIndex = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.table-container {
|
||||
width: 100%;
|
||||
|
||||
.iconcheckbox_weiquanxuan,
|
||||
.iconfuxuankuang1,
|
||||
.iconfuxuankuang2 {
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
font-size: 0.16rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.iconfuxuankuang2 {
|
||||
color: #e6e6e6;
|
||||
|
||||
&:hover {
|
||||
color: $primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
background: #eee;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover {
|
||||
color: #e6e6e6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.thead {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 0.5rem;
|
||||
background: #f7f8fa;
|
||||
align-items: center;
|
||||
|
||||
.th {
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tr {
|
||||
display: flex;
|
||||
border-bottom: 0.01rem solid #e6e6e6;
|
||||
min-height: 0.5rem;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s;
|
||||
padding: 0.1rem 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.td {
|
||||
padding: 0 0.1rem;
|
||||
box-sizing: border-box;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty {
|
||||
justify-content: center;
|
||||
|
||||
.td {
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
|
||||
.iconfont {
|
||||
font-size: 0.25rem;
|
||||
margin: 0.05rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tpage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.1rem 0;
|
||||
margin-bottom: 0.1rem;
|
||||
|
||||
.uni-pagination {
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
183
addon/cashier/source/os/components/uni-datetime-picker/calendar-item.vue
Executable file
183
addon/cashier/source/os/components/uni-datetime-picker/calendar-item.vue
Executable file
@@ -0,0 +1,183 @@
|
||||
<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--isDay': weeks.isDay}"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
weeks: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
choiceDate(weeks) {
|
||||
this.$emit('change', weeks)
|
||||
},
|
||||
handleMousemove(weeks) {
|
||||
this.$emit('handleMouse', weeks)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uni-calendar-item__weeks-box {
|
||||
flex: 1;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0.01rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-text {
|
||||
font-size: 0.14rem;
|
||||
// font-family: Lato-Bold, Lato;
|
||||
font-weight: bold;
|
||||
color: #455997;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-lunar-text {
|
||||
font-size: 0.12rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 0.4rem;
|
||||
height: 0.4rem;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-circle {
|
||||
position: absolute;
|
||||
top: 0.05rem;
|
||||
right: 0.05rem;
|
||||
width: 0.08rem;
|
||||
height: 0.08rem;
|
||||
border-radius: 0.08rem;
|
||||
background-color: #dd524d;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--disable {
|
||||
// background-color: rgba(249, 249, 249, $uni-opacity-disabled);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.uni-calendar-item--disable .uni-calendar-item__weeks-box-text-disable {
|
||||
color: #D1D1D1;
|
||||
}
|
||||
|
||||
.uni-calendar-item--isDay {
|
||||
position: absolute;
|
||||
top: 0.1rem;
|
||||
right: 17%;
|
||||
background-color: #dd524d;
|
||||
width: 0.06rem;
|
||||
height: 0.06rem;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.uni-calendar-item--extra {
|
||||
color: #dd524d;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box .uni-calendar-item--checked {
|
||||
background-color: $primary-color;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 0.03rem 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: $primary-color;
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
border: 0.03rem 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: 0.5rem;
|
||||
border-bottom-left-radius: 0.5rem;
|
||||
box-sizing: border-box;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
|
||||
.uni-calendar-item--after-checked-x {
|
||||
border-top-right-radius: 0.5rem;
|
||||
border-bottom-right-radius: 0.5rem;
|
||||
background-color: #F6F7FC;
|
||||
}
|
||||
</style>
|
||||
883
addon/cashier/source/os/components/uni-datetime-picker/calendar.vue
Executable file
883
addon/cashier/source/os/components/uni-datetime-picker/calendar.vue
Executable file
@@ -0,0 +1,883 @@
|
||||
<template>
|
||||
<view class="uni-calendar" @mouseleave="leaveCale">
|
||||
<view v-if="!insert&&show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}" @click="clean"></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 v-if="left" class="uni-calendar__header-btn-box" @click.stop="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||'') + ' 年 ' + ( nowDate.month||'') +' 月'}}</text>
|
||||
</picker>
|
||||
<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
|
||||
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||
</view>
|
||||
<view v-if="!insert" class="dialog-close" @click="clean">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
<!-- <text class="uni-calendar__backtoday" @click="backtoday">回到今天</text> -->
|
||||
</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: 0.07rem;">
|
||||
<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" :lunar="lunar" :checkHover="range" @change="choiceDate" @handleMouse="handleMouse"></calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top" style="padding: 0 0.8rem;">
|
||||
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
|
||||
<time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time" :disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style"></time-picker>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && range && typeHasTime" 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="reactStartTime" v-model="timeRange.startTime" :border="false" :hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
<uni-icons type="arrowthinright" color="#999" style="line-height: 0.5rem;"></uni-icons>
|
||||
<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="reactEndTime" 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-calendar__header-btn-box">
|
||||
<text class="uni-calendar__button-text uni-calendar--fixed-width">{{okText}}</text>
|
||||
</view> -->
|
||||
<view class="uni-datetime-picker--btn" @click="confirm">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Calendar from './util.js';
|
||||
import calendarItem from './calendar-item.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
import uniIcons from '@/components/uni-icons/uni-icons';
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(messages)
|
||||
/**
|
||||
* Calendar 日历
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
|
||||
* @property {String} date 自定义当前时间,默认为今天
|
||||
* @property {Boolean} lunar 显示农历
|
||||
* @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 是否选择月份为背景
|
||||
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||
* @event {Function} monthSwitch 切换月份时触发
|
||||
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
uniIcons,
|
||||
calendarItem,
|
||||
timePicker
|
||||
},
|
||||
props: {
|
||||
date: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
defTime: {
|
||||
type: [String, Object],
|
||||
default: ''
|
||||
},
|
||||
selectableTimes: {
|
||||
type: [Object],
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
selected: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
range: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
typeHasTime: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
insert: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
clearDate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
left: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
right: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
pleStatus: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
before: '',
|
||||
after: '',
|
||||
data: [],
|
||||
fulldate: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
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, oldVal) {
|
||||
if (!this.range) {
|
||||
this.tempSingleDate = newVal
|
||||
setTimeout(() => {
|
||||
this.init(newVal)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
defTime: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (!this.range) {
|
||||
this.time = newVal
|
||||
} else {
|
||||
this.timeRange.startTime = newVal.start
|
||||
this.timeRange.endTime = newVal.end
|
||||
}
|
||||
}
|
||||
},
|
||||
startDate(val) {
|
||||
this.cale.resetSatrtDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
endDate(val) {
|
||||
this.cale.resetEndDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
selected(newVal) {
|
||||
this.cale.setSelectInfo(this.nowDate.fullDate, newVal)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
pleStatus: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
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 {
|
||||
this.cale.setDefaultMultiple(before, after)
|
||||
if (which === 'left') {
|
||||
this.setDate(before)
|
||||
this.weeks = this.cale.weeks
|
||||
} else {
|
||||
this.setDate(after)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
this.cale.lastHover = true
|
||||
}
|
||||
}, 16)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
reactStartTime() {
|
||||
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
|
||||
const res = activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||
return res
|
||||
},
|
||||
reactEndTime() {
|
||||
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
|
||||
const res = activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||
return res
|
||||
},
|
||||
/**
|
||||
* 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")
|
||||
},
|
||||
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")
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// 获取日历方法实例
|
||||
this.cale = new Calendar({
|
||||
// date: new Date(),
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
// multipleStatus: this.pleStatus
|
||||
})
|
||||
// 选中某一天
|
||||
// this.cale.setDate(this.date)
|
||||
this.init(this.date)
|
||||
// this.setDay
|
||||
},
|
||||
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
|
||||
},
|
||||
|
||||
// 取消穿透
|
||||
clean() {
|
||||
this.close()
|
||||
},
|
||||
|
||||
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()
|
||||
},
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.init(value)
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
this.cale.setDate(date)
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.calendar = this.cale.getInfo(date)
|
||||
},
|
||||
// choiceDate(weeks) {
|
||||
// if (weeks.disable) return
|
||||
// this.calendar = weeks
|
||||
// // 设置多选
|
||||
// this.cale.setMultiple(this.calendar.fullDate, true)
|
||||
// this.weeks = this.cale.weeks
|
||||
// this.tempSingleDate = this.calendar.fullDate
|
||||
// this.tempRange.before = this.cale.multipleStatus.before
|
||||
// this.tempRange.after = this.cale.multipleStatus.after
|
||||
// this.change()
|
||||
// },
|
||||
/**
|
||||
* 打开日历弹窗
|
||||
*/
|
||||
open() {
|
||||
// 弹窗模式并且清理数据
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanMultipleStatus()
|
||||
// this.cale.setDate(this.date)
|
||||
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() {
|
||||
if (!this.insert) return
|
||||
this.setEmit('change')
|
||||
},
|
||||
/**
|
||||
* 选择月份触发
|
||||
*/
|
||||
monthSwitch() {
|
||||
let {
|
||||
year,
|
||||
month
|
||||
} = this.nowDate
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month: Number(month)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 派发事件
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
lunar,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
range: this.cale.multipleStatus,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
time: this.time,
|
||||
timeRange: this.timeRange,
|
||||
fulldate: fullDate,
|
||||
lunar,
|
||||
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
|
||||
this.tempRange.before = this.cale.multipleStatus.before
|
||||
this.tempRange.after = this.cale.multipleStatus.after
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 回到今天
|
||||
*/
|
||||
backtoday() {
|
||||
let date = this.cale.getDate(new Date()).fullDate
|
||||
// this.cale.setDate(date)
|
||||
this.init(date)
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 上个月
|
||||
*/
|
||||
pre() {
|
||||
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
|
||||
this.setDate(preDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
* 下个月
|
||||
*/
|
||||
next() {
|
||||
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
|
||||
this.setDate(nextDate)
|
||||
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" scoped>
|
||||
.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(4.6rem);
|
||||
/* #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: 0.1rem;
|
||||
border-top-right-radius: 0.1rem;
|
||||
box-shadow: 0 0 0.05rem 0.03rem 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: 0.5rem;
|
||||
}
|
||||
|
||||
.uni-calendar__header-mobile {
|
||||
padding: 0.1rem;
|
||||
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: 0.01rem;
|
||||
}
|
||||
|
||||
.uni-calendar--fixed-width {
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
.uni-calendar__backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0.125rem;
|
||||
padding: 0 0.05rem;
|
||||
padding-left: 0.1rem;
|
||||
height: 0.25rem;
|
||||
line-height: 0.25rem;
|
||||
font-size: 0.2rem;
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
color: #fff;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
.uni-calendar__header-text {
|
||||
text-align: center;
|
||||
width: 1rem;
|
||||
font-size: 0.15rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.uni-calendar__button-text {
|
||||
text-align: center;
|
||||
width: 1rem;
|
||||
font-size: 0.14rem;
|
||||
color: $primary-color;
|
||||
/* #ifndef APP-NVUE */
|
||||
letter-spacing: 0.03rem;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn-box {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.uni-calendar__header-btn {
|
||||
width: 0.09rem;
|
||||
height: 0.09rem;
|
||||
border-left-color: #808080;
|
||||
border-left-style: solid;
|
||||
border-left-width: 0.01rem;
|
||||
border-top-color: #555555;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.01rem;
|
||||
}
|
||||
|
||||
.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: 0.4rem;
|
||||
border-bottom-color: #F5F5F5;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 0.01rem;
|
||||
}
|
||||
|
||||
.uni-calendar__weeks-day-text {
|
||||
font-size: 0.2rem;
|
||||
color: #B2B2B2;
|
||||
}
|
||||
|
||||
.uni-calendar__box {
|
||||
position: relative;
|
||||
// padding: 0 0.1rem;
|
||||
padding-bottom: 0.07rem;
|
||||
}
|
||||
|
||||
.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: 2rem;
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
opacity: 0.1;
|
||||
text-align: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
line-height: 1;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-date-changed {
|
||||
padding: 0 0.1rem;
|
||||
// line-height: 0.5rem;
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-top-color: #DCDCDC;
|
||||
;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.01rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-date-btn--ok {
|
||||
padding: 0.2rem 0.15rem;
|
||||
}
|
||||
|
||||
.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: 0.5rem;
|
||||
margin-right: 0.05rem;
|
||||
// opacity: 0.6;
|
||||
}
|
||||
|
||||
.time-picker-style {
|
||||
// width: 62px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.mr-10 {
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.dialog-close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 0.25rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.dialog-close-plus {
|
||||
width: 0.16rem;
|
||||
height: 0.02rem;
|
||||
background-color: #737987;
|
||||
border-radius: 0.02rem;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.dialog-close-rotate {
|
||||
position: absolute;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.uni-datetime-picker--btn {
|
||||
border-radius: 1rem;
|
||||
height: 0.4rem;
|
||||
line-height: 0.4rem;
|
||||
background-color: $primary-color;
|
||||
color: #fff;
|
||||
font-size: 0.16rem;
|
||||
letter-spacing: 0.05rem;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-datetime-picker--btn:active {
|
||||
opacity: 0.7;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/en.json
Executable file
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/en.json
Executable file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "select date",
|
||||
"uni-datetime-picker.selectTime": "select time",
|
||||
"uni-datetime-picker.selectDateTime": "select datetime",
|
||||
"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-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"
|
||||
}
|
||||
8
addon/cashier/source/os/components/uni-datetime-picker/i18n/index.js
Executable file
8
addon/cashier/source/os/components/uni-datetime-picker/i18n/index.js
Executable 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
|
||||
}
|
||||
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/zh-Hans.json
Executable file
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/zh-Hans.json
Executable file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"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-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六"
|
||||
}
|
||||
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/zh-Hant.json
Executable file
19
addon/cashier/source/os/components/uni-datetime-picker/i18n/zh-Hant.json
Executable file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"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-calender.SUN": "日",
|
||||
"uni-calender.MON": "一",
|
||||
"uni-calender.TUE": "二",
|
||||
"uni-calender.WED": "三",
|
||||
"uni-calender.THU": "四",
|
||||
"uni-calender.FRI": "五",
|
||||
"uni-calender.SAT": "六"
|
||||
}
|
||||
45
addon/cashier/source/os/components/uni-datetime-picker/keypress.js
Executable file
45
addon/cashier/source/os/components/uni-datetime-picker/keypress.js
Executable file
@@ -0,0 +1,45 @@
|
||||
// #ifdef H5
|
||||
export default {
|
||||
name: 'Keypress',
|
||||
props: {
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const keyNames = {
|
||||
esc: ['Esc', 'Escape'],
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
space: [' ', 'Spacebar'],
|
||||
up: ['Up', 'ArrowUp'],
|
||||
left: ['Left', 'ArrowLeft'],
|
||||
right: ['Right', 'ArrowRight'],
|
||||
down: ['Down', 'ArrowDown'],
|
||||
delete: ['Backspace', 'Delete', 'Del']
|
||||
}
|
||||
const listener = ($event) => {
|
||||
if (this.disable) {
|
||||
return
|
||||
}
|
||||
const keyName = Object.keys(keyNames).find(key => {
|
||||
const keyName = $event.key
|
||||
const value = keyNames[key]
|
||||
return value === keyName || (Array.isArray(value) && value.includes(keyName))
|
||||
})
|
||||
if (keyName) {
|
||||
// 避免和其他按键事件冲突
|
||||
setTimeout(() => {
|
||||
this.$emit(keyName, {})
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
document.addEventListener('keyup', listener)
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
document.removeEventListener('keyup', listener)
|
||||
})
|
||||
},
|
||||
render: () => {}
|
||||
}
|
||||
// #endif
|
||||
921
addon/cashier/source/os/components/uni-datetime-picker/time-picker.vue
Executable file
921
addon/cashier/source/os/components/uni-datetime-picker/time-picker.vue
Executable file
@@ -0,0 +1,921 @@
|
||||
<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>
|
||||
<!-- #ifdef H5 -->
|
||||
<!-- <keypress v-if="visible" @esc="tiggerTimePicker" @enter="setTime" /> -->
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef H5
|
||||
import keypress from './keypress'
|
||||
// #endif
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const { t } = initVueI18n(messages)
|
||||
|
||||
/**
|
||||
* 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',
|
||||
components: {
|
||||
// #ifdef H5
|
||||
keypress
|
||||
// #endif
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
indicatorStyle: `height: 0.5rem;`,
|
||||
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,
|
||||
}
|
||||
},
|
||||
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: {
|
||||
value: {
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
this.parseValue(Date.now())
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
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(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
end: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式
|
||||
},
|
||||
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) && typeof value !== NaN) {
|
||||
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) && Number(point) !== NaN) {
|
||||
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();
|
||||
},
|
||||
|
||||
//兼容 iOS、safari 日期格式
|
||||
fixIosDateFormat(value) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
/**
|
||||
* 生成时间戳
|
||||
* @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 = this.fixIosDateFormat(this.value)
|
||||
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>
|
||||
.uni-datetime-picker {
|
||||
/* #ifndef APP-NVUE */
|
||||
/* width: 100%; */
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-view {
|
||||
height: 1.3rem;
|
||||
width: 2.7rem;
|
||||
/* #ifndef APP-NVUE */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-item {
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
text-align: center;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn {
|
||||
margin-top: 0.6rem;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-text {
|
||||
font-size: 0.14rem;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-btn-group {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-cancel {
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 998;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-popup {
|
||||
border-radius: 0.08rem;
|
||||
padding: 0.3rem;
|
||||
width: 2.7rem;
|
||||
/* #ifdef APP-NVUE */
|
||||
height: 5rem;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
width: 3.3rem;
|
||||
/* #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: 3.3rem;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-datetime-picker-time {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-column {
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-timebox {
|
||||
|
||||
border: 0.01rem solid #E5E5E5;
|
||||
border-radius: 0.05rem;
|
||||
padding: 0.07rem 0.1rem;
|
||||
/* #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: 0.14rem;
|
||||
}
|
||||
|
||||
.uni-datetime-picker-sign {
|
||||
position: absolute;
|
||||
top: 0.53rem;
|
||||
/* 减掉 0.1rem 的元素高度,兼容nvue */
|
||||
color: #999;
|
||||
/* #ifdef APP-NVUE */
|
||||
font-size: 0.16rem;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.sign-left {
|
||||
left: 0.86rem;
|
||||
}
|
||||
|
||||
.sign-right {
|
||||
right: 0.86rem;
|
||||
}
|
||||
|
||||
.sign-center {
|
||||
left: 1.35rem;
|
||||
}
|
||||
|
||||
.uni-datetime-picker__container-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
.time-hide-second {
|
||||
width: 1.8rem;
|
||||
}
|
||||
</style>
|
||||
973
addon/cashier/source/os/components/uni-datetime-picker/uni-datetime-picker.vue
Executable file
973
addon/cashier/source/os/components/uni-datetime-picker/uni-datetime-picker.vue
Executable file
@@ -0,0 +1,973 @@
|
||||
<template>
|
||||
<view class="uni-date">
|
||||
<view class="uni-date-editor" @click="show">
|
||||
<slot>
|
||||
<view class="uni-date-editor--x" :class="{'uni-date-editor--x__disabled': disabled,'uni-date-x--border': border}">
|
||||
<view v-if="!isRange" class="uni-date-x uni-date-single">
|
||||
<uni-icons type="calendar" color="#e1e1e1" size="22"></uni-icons>
|
||||
<input class="uni-date__x-input" type="text" v-model="singleVal" :placeholder="singlePlaceholderText" :disabled="inputDisabled" />
|
||||
</view>
|
||||
<view v-else class="uni-date-x uni-date-range">
|
||||
<uni-icons type="calendar" color="#e1e1e1" size="22"></uni-icons>
|
||||
<input class="uni-date__x-input t-c" type="text" v-model="range.startDate" :placeholder="startPlaceholderText" :disabled="inputDisabled" />
|
||||
<slot>
|
||||
<view>{{rangeSeparator}}</view>
|
||||
</slot>
|
||||
<input class="uni-date__x-input t-c" type="text" v-model="range.endDate" :placeholder="endPlaceholderText" :disabled="inputDisabled" />
|
||||
</view>
|
||||
<view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
|
||||
<uni-icons type="clear" color="#e1e1e1" size="18"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</slot>
|
||||
</view>
|
||||
|
||||
<view v-show="popup" class="uni-date-mask" @click="close"></view>
|
||||
<view v-if="!isPhone" ref="datePicker" v-show="popup" class="uni-date-picker__container">
|
||||
<view v-if="!isRange" class="uni-date-single--x" :style="popover">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
<view v-if="hasTime" class="uni-date-changed popup-x-header">
|
||||
<input class="uni-date__input t-c" type="text" v-model="tempSingleDate" :placeholder="selectDateText" />
|
||||
<time-picker type="time" v-model="time" :border="false" :disabled="!tempSingleDate" :start="reactStartTime" :end="reactEndTime" :hideSecond="hideSecond" style="width: 100%;">
|
||||
<input class="uni-date__input t-c" type="text" v-model="time" :placeholder="selectTimeText" :disabled="!tempSingleDate" />
|
||||
</time-picker>
|
||||
</view>
|
||||
<calendar ref="pcSingle" :showMonth="false" :start-date="caleRange.startDate" :end-date="caleRange.endDate" :date="defSingleDate" @change="singleChange" style="padding: 0 0.08rem;" />
|
||||
<view v-if="hasTime" class="popup-x-footer">
|
||||
<!-- <text>此刻</text> -->
|
||||
<text class="confirm" @click="confirmSingleChange">{{okText}}</text>
|
||||
</view>
|
||||
<view class="uni-date-popper__arrow"></view>
|
||||
</view>
|
||||
|
||||
<view v-else class="uni-date-range--x" :style="popover">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
<view v-if="hasTime" class="popup-x-header uni-date-changed">
|
||||
<view class="popup-x-header--datetime">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate" :placeholder="startDateText" />
|
||||
<time-picker type="time" v-model="tempRange.startTime" :start="reactStartTime" :border="false" :disabled="!tempRange.startDate" :hideSecond="hideSecond">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startTime" :placeholder="startTimeText" :disabled="!tempRange.startDate" />
|
||||
</time-picker>
|
||||
</view>
|
||||
<uni-icons type="arrowthinright" color="#999" style="line-height: 0.4rem;"></uni-icons>
|
||||
<view class="popup-x-header--datetime">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate" :placeholder="endDateText" />
|
||||
<time-picker type="time" v-model="tempRange.endTime" :end="reactEndTime" :border="false" :disabled="!tempRange.endDate" :hideSecond="hideSecond">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime" :placeholder="endTimeText" :disabled="!tempRange.endDate" />
|
||||
</time-picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-x-body">
|
||||
<calendar ref="left" :showMonth="false"
|
||||
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
|
||||
@change="leftChange" :pleStatus="endMultipleStatus" @firstEnterCale="updateRightCale"
|
||||
@monthSwitch="leftMonthSwitch" style="padding: 0 0.08rem;" />
|
||||
<calendar ref="right" :showMonth="false"
|
||||
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :range="true"
|
||||
@change="rightChange" :pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale"
|
||||
@monthSwitch="rightMonthSwitch" style="padding: 0 0.08rem;border-left: 0.01rem solid #F1F1F1;" />
|
||||
</view>
|
||||
<view v-if="hasTime" class="popup-x-footer">
|
||||
<text @click="clear">{{clearText}}</text>
|
||||
<text class="confirm" @click="confirmRangeChange">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<calendar v-show="isPhone" ref="mobile" :clearDate="false" :date="defSingleDate" :defTime="reactMobDefTime"
|
||||
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime"
|
||||
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false"
|
||||
:hideSecond="hideSecond" @confirm="mobileChange" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
/**
|
||||
* DatetimePicker 时间选择器
|
||||
* @description 同时支持 PC 和移动端使用日历选择日期和日期范围
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3962
|
||||
* @property {String} type 选择器类型
|
||||
* @property {String|Number|Array|Date} value 绑定值
|
||||
* @property {String} placeholder 单选择时的占位内容
|
||||
* @property {String} start 起始时间
|
||||
* @property {String} end 终止时间
|
||||
* @property {String} start-placeholder 范围选择时开始日期的占位内容
|
||||
* @property {String} end-placeholder 范围选择时结束日期的占位内容
|
||||
* @property {String} range-separator 选择范围时的分隔符
|
||||
* @property {Boolean} border = [true|false] 是否有边框
|
||||
* @property {Boolean} disabled = [true|false] 是否禁用
|
||||
* @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用)
|
||||
* @event {Function} change 确定日期时触发的事件
|
||||
* @event {Function} show 打开弹出层
|
||||
* @event {Function} close 关闭弹出层
|
||||
* @event {Function} clear 清除上次选中的状态和值
|
||||
**/
|
||||
import calendar from './calendar.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const {
|
||||
t
|
||||
} = initVueI18n(messages)
|
||||
|
||||
export default {
|
||||
name: 'UniDatetimePicker',
|
||||
components: {
|
||||
calendar,
|
||||
timePicker
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isRange: false,
|
||||
hasTime: false,
|
||||
mobileRange: false,
|
||||
// 单选
|
||||
singleVal: '',
|
||||
tempSingleDate: '',
|
||||
defSingleDate: '',
|
||||
time: '',
|
||||
// 范围选
|
||||
caleRange: {
|
||||
startDate: '',
|
||||
startTime: '',
|
||||
endDate: '',
|
||||
endTime: ''
|
||||
},
|
||||
range: {
|
||||
startDate: '',
|
||||
// startTime: '',
|
||||
endDate: '',
|
||||
// endTime: ''
|
||||
},
|
||||
tempRange: {
|
||||
startDate: '',
|
||||
startTime: '',
|
||||
endDate: '',
|
||||
endTime: ''
|
||||
},
|
||||
// 左右日历同步数据
|
||||
startMultipleStatus: {
|
||||
before: '',
|
||||
after: '',
|
||||
data: [],
|
||||
fulldate: ''
|
||||
},
|
||||
endMultipleStatus: {
|
||||
before: '',
|
||||
after: '',
|
||||
data: [],
|
||||
fulldate: ''
|
||||
},
|
||||
visible: false,
|
||||
popup: false,
|
||||
popover: null,
|
||||
isEmitValue: false,
|
||||
isPhone: false,
|
||||
isFirstShow: true,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
inputDisabled: {
|
||||
type: [Boolean],
|
||||
default: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'datetime'
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Array, Date],
|
||||
default: ''
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number, Array, Date],
|
||||
default: ''
|
||||
},
|
||||
start: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
end: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
returnType: {
|
||||
type: String,
|
||||
default: 'string'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
startPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
endPlaceholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
rangeSeparator: {
|
||||
type: String,
|
||||
default: '-'
|
||||
},
|
||||
border: {
|
||||
type: [Boolean],
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
clearIcon: {
|
||||
type: [Boolean],
|
||||
default: true
|
||||
},
|
||||
hideSecond: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
type: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (newVal.indexOf('time') !== -1) {
|
||||
this.hasTime = true
|
||||
} else {
|
||||
this.hasTime = false
|
||||
}
|
||||
if (newVal.indexOf('range') !== -1) {
|
||||
this.isRange = true
|
||||
} else {
|
||||
this.isRange = false
|
||||
}
|
||||
}
|
||||
},
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (this.isEmitValue) {
|
||||
this.isEmitValue = false
|
||||
return
|
||||
}
|
||||
this.initPicker(newVal)
|
||||
}
|
||||
},
|
||||
|
||||
start: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (!newVal) return
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.caleRange.startDate = defDate
|
||||
if (this.hasTime) {
|
||||
this.caleRange.startTime = defTime
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
end: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (!newVal) return
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.caleRange.endDate = defDate
|
||||
if (this.hasTime) {
|
||||
this.caleRange.endTime = defTime
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
reactStartTime() {
|
||||
const activeDate = this.isRange ? this.tempRange.startDate : this.tempSingleDate
|
||||
const res = activeDate === this.caleRange.startDate ? this.caleRange.startTime : ''
|
||||
return res
|
||||
},
|
||||
reactEndTime() {
|
||||
const activeDate = this.isRange ? this.tempRange.endDate : this.tempSingleDate
|
||||
const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : ''
|
||||
return res
|
||||
},
|
||||
reactMobDefTime() {
|
||||
const times = {
|
||||
start: this.tempRange.startTime,
|
||||
end: this.tempRange.endTime
|
||||
}
|
||||
return this.isRange ? times : this.time
|
||||
},
|
||||
mobSelectableTime() {
|
||||
return {
|
||||
start: this.caleRange.startTime,
|
||||
end: this.caleRange.endTime
|
||||
}
|
||||
},
|
||||
datePopupWidth() {
|
||||
// todo
|
||||
return this.isRange ? 653 : 301
|
||||
},
|
||||
|
||||
/**
|
||||
* for i18n
|
||||
*/
|
||||
singlePlaceholderText() {
|
||||
return this.placeholder || (this.type === 'date' ? this.selectDateText : t(
|
||||
"uni-datetime-picker.selectDateTime"))
|
||||
},
|
||||
startPlaceholderText() {
|
||||
return this.startPlaceholder || this.startDateText
|
||||
},
|
||||
endPlaceholderText() {
|
||||
return this.endPlaceholder || this.endDateText
|
||||
},
|
||||
selectDateText() {
|
||||
return t("uni-datetime-picker.selectDate")
|
||||
},
|
||||
selectTimeText() {
|
||||
return t("uni-datetime-picker.selectTime")
|
||||
},
|
||||
startDateText() {
|
||||
return this.startPlaceholder || t("uni-datetime-picker.startDate")
|
||||
},
|
||||
startTimeText() {
|
||||
return t("uni-datetime-picker.startTime")
|
||||
},
|
||||
endDateText() {
|
||||
return this.endPlaceholder || t("uni-datetime-picker.endDate")
|
||||
},
|
||||
endTimeText() {
|
||||
return t("uni-datetime-picker.endTime")
|
||||
},
|
||||
okText() {
|
||||
return t("uni-datetime-picker.ok")
|
||||
},
|
||||
clearText() {
|
||||
return t("uni-datetime-picker.clear")
|
||||
},
|
||||
showClearIcon() {
|
||||
const { clearIcon, disabled, singleVal, range } = this
|
||||
const bool = clearIcon && !disabled && (singleVal || (range.startDate && range.endDate))
|
||||
return bool
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.getForm('uniForms')
|
||||
this.formItem = this.getForm('uniFormsItem')
|
||||
|
||||
// if (this.formItem) {
|
||||
// if (this.formItem.name) {
|
||||
// this.rename = this.formItem.name
|
||||
// this.form.inputChildrens.push(this)
|
||||
// }
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
this.platform()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getForm(name = 'uniForms') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
initPicker(newVal) {
|
||||
if (!newVal || Array.isArray(newVal) && !newVal.length) {
|
||||
this.$nextTick(() => {
|
||||
this.clear(false)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!Array.isArray(newVal) && !this.isRange) {
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.singleVal = defDate
|
||||
this.tempSingleDate = defDate
|
||||
this.defSingleDate = defDate
|
||||
if (this.hasTime) {
|
||||
this.singleVal = defDate + ' ' + defTime
|
||||
this.time = defTime
|
||||
}
|
||||
} else {
|
||||
const [before, after] = newVal
|
||||
if (!before && !after) return
|
||||
const defBefore = this.parseDate(before)
|
||||
const defAfter = this.parseDate(after)
|
||||
const startDate = defBefore.defDate
|
||||
const endDate = defAfter.defDate
|
||||
this.range.startDate = this.tempRange.startDate = startDate
|
||||
this.range.endDate = this.tempRange.endDate = endDate
|
||||
|
||||
if (this.hasTime) {
|
||||
this.range.startDate = defBefore.defDate + ' ' + defBefore.defTime
|
||||
this.range.endDate = defAfter.defDate + ' ' + defAfter.defTime
|
||||
this.tempRange.startTime = defBefore.defTime
|
||||
this.tempRange.endTime = defAfter.defTime
|
||||
}
|
||||
const defaultRange = {
|
||||
before: defBefore.defDate,
|
||||
after: defAfter.defDate
|
||||
}
|
||||
this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
|
||||
which: 'right'
|
||||
})
|
||||
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
|
||||
which: 'left'
|
||||
})
|
||||
}
|
||||
},
|
||||
updateLeftCale(e) {
|
||||
const left = this.$refs.left
|
||||
// 设置范围选
|
||||
left.cale.setHoverMultiple(e.after)
|
||||
left.setDate(this.$refs.left.nowDate.fullDate)
|
||||
},
|
||||
updateRightCale(e) {
|
||||
const right = this.$refs.right
|
||||
// 设置范围选
|
||||
right.cale.setHoverMultiple(e.after)
|
||||
right.setDate(this.$refs.right.nowDate.fullDate)
|
||||
},
|
||||
platform() {
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
this.isPhone = systemInfo.windowWidth <= 500
|
||||
this.windowWidth = systemInfo.windowWidth
|
||||
},
|
||||
show(event) {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
this.platform()
|
||||
if (this.isPhone) {
|
||||
this.$refs.mobile.open()
|
||||
return
|
||||
}
|
||||
this.popover = {
|
||||
top: '0.1rem'
|
||||
}
|
||||
const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
|
||||
dateEditor.boundingClientRect(rect => {
|
||||
if (this.windowWidth - rect.left < this.datePopupWidth) {
|
||||
this.popover.right = 0
|
||||
}
|
||||
}).exec()
|
||||
setTimeout(() => {
|
||||
this.popup = !this.popup
|
||||
if (!this.isPhone && this.isRange && this.isFirstShow) {
|
||||
this.isFirstShow = false
|
||||
const {
|
||||
startDate,
|
||||
endDate
|
||||
} = this.range
|
||||
if (startDate && endDate) {
|
||||
if (this.diffDate(startDate, endDate) < 30) {
|
||||
this.$refs.right.next()
|
||||
}
|
||||
} else {
|
||||
this.$refs.right.next()
|
||||
this.$refs.right.cale.lastHover = false
|
||||
}
|
||||
}
|
||||
|
||||
}, 50)
|
||||
},
|
||||
|
||||
close() {
|
||||
setTimeout(() => {
|
||||
this.popup = false
|
||||
this.$emit('maskClick', this.value)
|
||||
}, 20)
|
||||
},
|
||||
setEmit(value) {
|
||||
if (this.returnType === "timestamp" || this.returnType === "date") {
|
||||
if (!Array.isArray(value)) {
|
||||
if (!this.hasTime) {
|
||||
value = value + ' ' + '00:00:00'
|
||||
}
|
||||
value = this.createTimestamp(value)
|
||||
if (this.returnType === "date") {
|
||||
value = new Date(value)
|
||||
}
|
||||
} else {
|
||||
if (!this.hasTime) {
|
||||
value[0] = value[0] + ' ' + '00:00:00'
|
||||
value[1] = value[1] + ' ' + '00:00:00'
|
||||
}
|
||||
value[0] = this.createTimestamp(value[0])
|
||||
value[1] = this.createTimestamp(value[1])
|
||||
if (this.returnType === "date") {
|
||||
value[0] = new Date(value[0])
|
||||
value[1] = new Date(value[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
this.formItem && this.formItem.setValue(value)
|
||||
this.$emit('change', value)
|
||||
this.$emit('input', value)
|
||||
this.$emit('update:modelValue', value)
|
||||
this.isEmitValue = true
|
||||
},
|
||||
createTimestamp(date) {
|
||||
date = this.fixIosDateFormat(date)
|
||||
return Date.parse(new Date(date))
|
||||
},
|
||||
singleChange(e) {
|
||||
this.tempSingleDate = e.fulldate
|
||||
if (this.hasTime) return
|
||||
this.confirmSingleChange()
|
||||
},
|
||||
|
||||
confirmSingleChange() {
|
||||
if (!this.tempSingleDate) {
|
||||
this.popup = false
|
||||
return
|
||||
}
|
||||
if (this.hasTime) {
|
||||
this.singleVal = this.tempSingleDate + ' ' + (this.time ? this.time : '00:00:00')
|
||||
} else {
|
||||
this.singleVal = this.tempSingleDate
|
||||
}
|
||||
this.setEmit(this.singleVal)
|
||||
this.popup = false
|
||||
},
|
||||
|
||||
leftChange(e) {
|
||||
const {
|
||||
before,
|
||||
after
|
||||
} = e.range
|
||||
this.rangeChange(before, after)
|
||||
const obj = {
|
||||
before: e.range.before,
|
||||
after: e.range.after,
|
||||
data: e.range.data,
|
||||
fulldate: e.fulldate
|
||||
}
|
||||
this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj)
|
||||
},
|
||||
|
||||
rightChange(e) {
|
||||
const {
|
||||
before,
|
||||
after
|
||||
} = e.range
|
||||
this.rangeChange(before, after)
|
||||
const obj = {
|
||||
before: e.range.before,
|
||||
after: e.range.after,
|
||||
data: e.range.data,
|
||||
fulldate: e.fulldate
|
||||
}
|
||||
this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj)
|
||||
},
|
||||
|
||||
mobileChange(e) {
|
||||
if (this.isRange) {
|
||||
const {
|
||||
before,
|
||||
after
|
||||
} = e.range
|
||||
this.handleStartAndEnd(before, after, true)
|
||||
if (this.hasTime) {
|
||||
const {
|
||||
startTime,
|
||||
endTime
|
||||
} = e.timeRange
|
||||
this.tempRange.startTime = startTime
|
||||
this.tempRange.endTime = endTime
|
||||
}
|
||||
this.confirmRangeChange()
|
||||
|
||||
} else {
|
||||
if (this.hasTime) {
|
||||
this.singleVal = e.fulldate + ' ' + e.time
|
||||
} else {
|
||||
this.singleVal = e.fulldate
|
||||
}
|
||||
this.setEmit(this.singleVal)
|
||||
}
|
||||
this.$refs.mobile.close()
|
||||
},
|
||||
|
||||
rangeChange(before, after) {
|
||||
if (!(before && after)) return
|
||||
this.handleStartAndEnd(before, after, true)
|
||||
if (this.hasTime) return
|
||||
this.confirmRangeChange()
|
||||
},
|
||||
|
||||
confirmRangeChange() {
|
||||
if (!this.tempRange.startDate && !this.tempRange.endDate) {
|
||||
this.popup = false
|
||||
return
|
||||
}
|
||||
let start, end
|
||||
if (!this.hasTime) {
|
||||
start = this.range.startDate = this.tempRange.startDate
|
||||
end = this.range.endDate = this.tempRange.endDate
|
||||
} else {
|
||||
start = this.range.startDate = this.tempRange.startDate + ' ' +
|
||||
(this.tempRange.startTime ? this.tempRange.startTime : '00:00:00')
|
||||
end = this.range.endDate = this.tempRange.endDate + ' ' +
|
||||
(this.tempRange.endTime ? this.tempRange.endTime : '00:00:00')
|
||||
}
|
||||
const displayRange = [start, end]
|
||||
this.setEmit(displayRange)
|
||||
this.popup = false
|
||||
},
|
||||
|
||||
handleStartAndEnd(before, after, temp = false) {
|
||||
if (!(before && after)) return
|
||||
const type = temp ? 'tempRange' : 'range'
|
||||
if (this.dateCompare(before, after)) {
|
||||
this[type].startDate = before
|
||||
this[type].endDate = after
|
||||
} else {
|
||||
this[type].startDate = after
|
||||
this[type].endDate = before
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 比较时间差
|
||||
*/
|
||||
diffDate(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
const diff = (endDate - startDate) / (24 * 60 * 60 * 1000)
|
||||
return Math.abs(diff)
|
||||
},
|
||||
|
||||
clear(needEmit = true) {
|
||||
if (!this.isRange) {
|
||||
this.singleVal = ''
|
||||
this.tempSingleDate = ''
|
||||
this.time = ''
|
||||
if (this.isPhone) {
|
||||
this.$refs.mobile && this.$refs.mobile.clearCalender()
|
||||
} else {
|
||||
this.$refs.pcSingle && this.$refs.pcSingle.clearCalender()
|
||||
}
|
||||
if (needEmit) {
|
||||
this.formItem && this.formItem.setValue('')
|
||||
this.$emit('change', '')
|
||||
this.$emit('input', '')
|
||||
this.$emit('update:modelValue', '')
|
||||
}
|
||||
} else {
|
||||
this.range.startDate = ''
|
||||
this.range.endDate = ''
|
||||
this.tempRange.startDate = ''
|
||||
this.tempRange.startTime = ''
|
||||
this.tempRange.endDate = ''
|
||||
this.tempRange.endTime = ''
|
||||
if (this.isPhone) {
|
||||
this.$refs.mobile && this.$refs.mobile.clearCalender()
|
||||
} else {
|
||||
this.$refs.left && this.$refs.left.clearCalender()
|
||||
this.$refs.right && this.$refs.right.clearCalender()
|
||||
this.$refs.right && this.$refs.right.next()
|
||||
}
|
||||
if (needEmit) {
|
||||
this.formItem && this.formItem.setValue([])
|
||||
this.$emit('change', [])
|
||||
this.$emit('input', [])
|
||||
this.$emit('update:modelValue', [])
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
parseDate(date) {
|
||||
date = this.fixIosDateFormat(date)
|
||||
const defVal = new Date(date)
|
||||
const year = defVal.getFullYear()
|
||||
const month = defVal.getMonth() + 1
|
||||
const day = defVal.getDate()
|
||||
const hour = defVal.getHours()
|
||||
const minute = defVal.getMinutes()
|
||||
const second = defVal.getSeconds()
|
||||
const defDate = year + '-' + this.lessTen(month) + '-' + this.lessTen(day)
|
||||
const defTime = this.lessTen(hour) + ':' + this.lessTen(minute) + (this.hideSecond ? '' : (':' + this
|
||||
.lessTen(second)))
|
||||
return {
|
||||
defDate,
|
||||
defTime
|
||||
}
|
||||
},
|
||||
|
||||
lessTen(item) {
|
||||
return item < 10 ? '0' + item : item
|
||||
},
|
||||
|
||||
//兼容 iOS、safari 日期格式
|
||||
fixIosDateFormat(value) {
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
leftMonthSwitch(e) {
|
||||
// console.log('leftMonthSwitch 返回:', e)
|
||||
},
|
||||
rightMonthSwitch(e) {
|
||||
// console.log('rightMonthSwitch 返回:', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.uni-date-x {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 0.1rem;
|
||||
border-radius: 0.02rem;
|
||||
background-color: #fff;
|
||||
color: #666;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.uni-date-x--border {
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.02rem;
|
||||
border: 0.01rem solid #dcdfe6;
|
||||
}
|
||||
|
||||
.uni-icons{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.uni-date-editor--x {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.uni-date-editor--x .uni-date__icon-clear {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
border: 0.09rem solid transparent;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-date__x-input {
|
||||
padding: 0 0.08rem;
|
||||
/* height: 0.4rem; */
|
||||
width: 100%;
|
||||
/* line-height: 0.4rem; */
|
||||
font-size: 0.14rem;
|
||||
|
||||
}
|
||||
|
||||
.t-c {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.uni-date__input {
|
||||
height: 0.4rem;
|
||||
width: 100%;
|
||||
line-height: 0.4rem;
|
||||
font-size: 0.14rem;
|
||||
}
|
||||
|
||||
.uni-date-range__input {
|
||||
text-align: center;
|
||||
max-width: 1.42rem;
|
||||
}
|
||||
|
||||
.uni-date-picker__container {
|
||||
position: relative;
|
||||
/* position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 996;
|
||||
font-size: 0.14rem; */
|
||||
}
|
||||
|
||||
.uni-date-mask {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
transition-duration: 0.3s;
|
||||
z-index: 996;
|
||||
}
|
||||
|
||||
.uni-date-single--x {
|
||||
/* padding: 0 0.08rem; */
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
border: 0.01rem solid #EBEEF5;
|
||||
box-shadow: 0 0.02rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 0.04rem;
|
||||
}
|
||||
|
||||
.uni-date-range--x {
|
||||
/* padding: 0 0.08rem; */
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
border: 0.01rem solid #EBEEF5;
|
||||
box-shadow: 0 0.02rem 0.12rem 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 0.04rem;
|
||||
}
|
||||
|
||||
.uni-date-editor--x__disabled {
|
||||
opacity: 0.4;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.uni-date-editor--logo {
|
||||
width: 0.16rem;
|
||||
height: 0.16rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 添加时间 */
|
||||
.popup-x-header {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
/* justify-content: space-between; */
|
||||
}
|
||||
|
||||
.popup-x-header--datetime {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.popup-x-body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.popup-x-footer {
|
||||
padding: 0 0.15rem;
|
||||
border-top-color: #F1F1F1;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0.01rem;
|
||||
/* background-color: #fff; */
|
||||
line-height: 0.4rem;
|
||||
text-align: right;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.popup-x-footer text:hover {
|
||||
color: $primary-color;
|
||||
cursor: pointer;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.popup-x-footer .confirm {
|
||||
margin-left: 0.2rem;
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.uni-date-changed {
|
||||
/* background-color: #fff; */
|
||||
text-align: center;
|
||||
color: #333;
|
||||
border-bottom-color: #F1F1F1;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 0.01rem;
|
||||
/* padding: 0 50px; */
|
||||
}
|
||||
|
||||
.uni-date-changed--time text {
|
||||
/* padding: 0 20px; */
|
||||
height: 0.5rem;
|
||||
line-height: 0.5rem;
|
||||
}
|
||||
|
||||
.uni-date-changed .uni-date-changed--time {
|
||||
/* display: flex; */
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.uni-date-changed--time-date {
|
||||
color: #333;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.mr-50 {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
|
||||
.uni-popper__arrow,
|
||||
.uni-popper__arrow::after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
border-width: 0.06rem;
|
||||
}
|
||||
|
||||
.uni-popper__arrow {
|
||||
filter: drop-shadow(0 0.02rem 0.12rem rgba(0, 0, 0, 0.03));
|
||||
top: -0.06rem;
|
||||
left: 10%;
|
||||
margin-right: 0.03rem;
|
||||
border-top-width: 0;
|
||||
border-bottom-color: #EBEEF5;
|
||||
}
|
||||
|
||||
.uni-popper__arrow::after {
|
||||
content: " ";
|
||||
top: 0.01rem;
|
||||
margin-left: -0.06rem;
|
||||
border-top-width: 0;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
</style>
|
||||
410
addon/cashier/source/os/components/uni-datetime-picker/util.js
Executable file
410
addon/cashier/source/os/components/uni-datetime-picker/util.js
Executable file
@@ -0,0 +1,410 @@
|
||||
class Calendar {
|
||||
constructor({
|
||||
date,
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range,
|
||||
// multipleStatus
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDate(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
this.range = range
|
||||
// 多选状态
|
||||
this.cleanMultipleStatus()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
// this._getWeek(this.date.fullDate)
|
||||
// this.multipleStatus = multipleStatus
|
||||
this.lastHover = false
|
||||
}
|
||||
/**
|
||||
* 设置日期
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.selectDate = this.getDate(date)
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理多选状态
|
||||
*/
|
||||
cleanMultipleStatus() {
|
||||
this.multipleStatus = {
|
||||
before: '',
|
||||
after: '',
|
||||
data: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置开始日期
|
||||
*/
|
||||
resetSatrtDate(startDate) {
|
||||
// 范围开始
|
||||
this.startDate = startDate
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置结束日期
|
||||
*/
|
||||
resetEndDate(endDate) {
|
||||
// 范围结束
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任意时间
|
||||
*/
|
||||
getDate(date, AddDayCount = 0, str = 'day') {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
}
|
||||
break
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上月剩余天数
|
||||
*/
|
||||
_getLastMonthDays(firstDay, full) {
|
||||
let dateArr = []
|
||||
for (let i = firstDay; i > 0; i--) {
|
||||
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
|
||||
dateArr.push({
|
||||
date: beforeDate,
|
||||
month: full.month - 1,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取本月天数
|
||||
*/
|
||||
_currentMonthDys(dateData, full) {
|
||||
let dateArr = []
|
||||
let fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= dateData; i++) {
|
||||
let isinfo = false
|
||||
let nowDate = full.year + '-' + (full.month < 10 ?
|
||||
full.month : full.month) + '-' + (i < 10 ?
|
||||
'0' + i : i)
|
||||
// 是否今天
|
||||
let isDay = fullDate === nowDate
|
||||
// 获取打点信息
|
||||
let info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(nowDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
|
||||
// 日期禁用
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
|
||||
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
|
||||
disableBefore = this.dateCompare(this.startDate, nowDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
|
||||
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
|
||||
disableAfter = this.dateCompare(nowDate, this.endDate)
|
||||
}
|
||||
let multiples = this.multipleStatus.data
|
||||
let checked = false
|
||||
let multiplesStatus = -1
|
||||
if (this.range) {
|
||||
if (multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, nowDate)
|
||||
})
|
||||
}
|
||||
if (multiplesStatus !== -1) {
|
||||
checked = true
|
||||
}
|
||||
}
|
||||
let data = {
|
||||
fullDate: nowDate,
|
||||
year: full.year,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
month: full.month,
|
||||
disable: !(disableBefore && disableAfter),
|
||||
isDay,
|
||||
userChecked: false
|
||||
}
|
||||
if (info) {
|
||||
data.extraInfo = info
|
||||
}
|
||||
|
||||
dateArr.push(data)
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
/**
|
||||
* 获取下月天数
|
||||
*/
|
||||
_getNextMonthDays(surplus, full) {
|
||||
let dateArr = []
|
||||
for (let i = 1; i < surplus + 1; i++) {
|
||||
dateArr.push({
|
||||
date: i,
|
||||
month: Number(full.month) + 1,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期详情
|
||||
* @param {Object} date
|
||||
*/
|
||||
getInfo(date) {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
|
||||
return dateInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (before.getTime() - after.getTime() === 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较真实起始日期
|
||||
*/
|
||||
|
||||
isLogicBefore(currentDay, before, after) {
|
||||
let logicBefore = before
|
||||
if (before && after) {
|
||||
logicBefore = this.dateCompare(before, after) ? before : after
|
||||
}
|
||||
return this.dateEqual(logicBefore, currentDay)
|
||||
}
|
||||
|
||||
isLogicAfter(currentDay, before, after) {
|
||||
let logicAfter = after
|
||||
if (before && after) {
|
||||
logicAfter = this.dateCompare(before, after) ? after : before
|
||||
}
|
||||
return this.dateEqual(logicAfter, currentDay)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取日期范围内所有日期
|
||||
* @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.getDate(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
if (!this.range) return
|
||||
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.lastHover = false
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (this.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._getWeek(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标 hover 更新多选状态
|
||||
*/
|
||||
setHoverMultiple(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
|
||||
if (!this.range) return
|
||||
if (this.lastHover) return
|
||||
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (this.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._getWeek(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新默认值多选状态
|
||||
*/
|
||||
setDefaultMultiple(before, after) {
|
||||
this.multipleStatus.before = before
|
||||
this.multipleStatus.after = after
|
||||
if (before && after) {
|
||||
if (this.dateCompare(before, after)) {
|
||||
this.multipleStatus.data = this.geDateAll(before, after);
|
||||
this._getWeek(after)
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(after, before);
|
||||
this._getWeek(before)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
_getWeek(dateData) {
|
||||
const {
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
day
|
||||
} = this.getDate(dateData)
|
||||
let firstDay = new Date(year, month - 1, 1).getDay()
|
||||
let currentDay = new Date(year, month, 0).getDate()
|
||||
let dates = {
|
||||
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
|
||||
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
weeks: []
|
||||
}
|
||||
let canlender = []
|
||||
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
|
||||
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
let weeks = {}
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 === 0) {
|
||||
weeks[parseInt(i / 7)] = new Array(7)
|
||||
}
|
||||
weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
this.canlender = canlender
|
||||
this.weeks = weeks
|
||||
}
|
||||
|
||||
//静态方法
|
||||
// static init(date) {
|
||||
// if (!this.instance) {
|
||||
// this.instance = new Calendar(date);
|
||||
// }
|
||||
// return this.instance;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
export default Calendar
|
||||
90
addon/cashier/source/os/components/uni-dropdown/uni-dropdown.vue
Executable file
90
addon/cashier/source/os/components/uni-dropdown/uni-dropdown.vue
Executable file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<view class="dropdown">
|
||||
<view class="dropdown-link" @click="open">
|
||||
<slot name="dropdown-link"></slot>
|
||||
</view>
|
||||
<uni-transition key="1" name="mask" mode-class="fade" :styles="maskClass" :duration="300" :show="showTrans" @click="close" />
|
||||
<uni-transition key="2" :mode-class="direction" class="dropdown-box" name="content" :style="dropdownClass" :duration="300" :show="showTrans">
|
||||
<view class="dropdown-content" @click="close">
|
||||
<slot name="dropdown"></slot>
|
||||
</view>
|
||||
</uni-transition>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "uniDropdown",
|
||||
props: {
|
||||
direction: {
|
||||
type: String,
|
||||
default: "slide-top",
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showTrans: false,
|
||||
maskClass: {
|
||||
position: "fixed",
|
||||
zIndex: 1,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0)",
|
||||
},
|
||||
dropdownClass: {},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.showTrans = true;
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select(".dropdown-link").boundingClientRect((data) => {
|
||||
switch (this.direction) {
|
||||
case "slide-top":
|
||||
this.dropdownClass = {
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
top: "100%",
|
||||
right: "0px",
|
||||
};
|
||||
break;
|
||||
case "slide-bottom":
|
||||
this.dropdownClass = {
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
bottom: "100%",
|
||||
left: "0px",
|
||||
};
|
||||
break;
|
||||
|
||||
}
|
||||
}).exec();
|
||||
},
|
||||
close() {
|
||||
this.showTrans = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.dropdown-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: none;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropdown-box {
|
||||
z-index: 999 !important;
|
||||
}
|
||||
</style>
|
||||
1115
addon/cashier/source/os/components/uni-icons/icons.js
Executable file
1115
addon/cashier/source/os/components/uni-icons/icons.js
Executable file
File diff suppressed because it is too large
Load Diff
89
addon/cashier/source/os/components/uni-icons/uni-icons.vue
Executable file
89
addon/cashier/source/os/components/uni-icons/uni-icons.vue
Executable file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" @click="_onClick">{{unicode}}</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<text :style="{ color: color, 'font-size': size + 'px' }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './icons.js';
|
||||
// #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: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: icons.glyphs
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
unicode(){
|
||||
let code = this.icons.find(v=>v.font_class === this.type)
|
||||
if(code){
|
||||
return unescape(`%u${code.unicode}`)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_onClick() {
|
||||
this.$emit('click')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* #ifndef APP-NVUE */
|
||||
@import './uniicons.css';
|
||||
@font-face {
|
||||
font-family: uniicons;
|
||||
src: url('./uniicons.ttf') format('truetype');
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.uni-icons {
|
||||
font-family: uniicons;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
663
addon/cashier/source/os/components/uni-icons/uniicons.css
Executable file
663
addon/cashier/source/os/components/uni-icons/uniicons.css
Executable file
@@ -0,0 +1,663 @@
|
||||
.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-gift-filled:before {
|
||||
content: "\e6c4";
|
||||
}
|
||||
|
||||
.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-back:before {
|
||||
content: "\e6b9";
|
||||
}
|
||||
|
||||
.uniui-forward:before {
|
||||
content: "\e6ba";
|
||||
}
|
||||
|
||||
.uniui-arrow-right:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.uniui-arrowthinright:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.uniui-arrow-left:before {
|
||||
content: "\e6bc";
|
||||
}
|
||||
|
||||
.uniui-arrowthinleft:before {
|
||||
content: "\e6bc";
|
||||
}
|
||||
|
||||
.uniui-arrow-up:before {
|
||||
content: "\e6bd";
|
||||
}
|
||||
|
||||
.uniui-arrowthinup:before {
|
||||
content: "\e6bd";
|
||||
}
|
||||
|
||||
.uniui-arrow-down:before {
|
||||
content: "\e6be";
|
||||
}
|
||||
|
||||
.uniui-arrowthindown:before {
|
||||
content: "\e6be";
|
||||
}
|
||||
|
||||
.uniui-bottom:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.uniui-arrowdown:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.uniui-right:before {
|
||||
content: "\e6b5";
|
||||
}
|
||||
|
||||
.uniui-arrowright:before {
|
||||
content: "\e6b5";
|
||||
}
|
||||
|
||||
.uniui-top:before {
|
||||
content: "\e6b6";
|
||||
}
|
||||
|
||||
.uniui-arrowup:before {
|
||||
content: "\e6b6";
|
||||
}
|
||||
|
||||
.uniui-left:before {
|
||||
content: "\e6b7";
|
||||
}
|
||||
|
||||
.uniui-arrowleft:before {
|
||||
content: "\e6b7";
|
||||
}
|
||||
|
||||
.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-cart-filled:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.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";
|
||||
}
|
||||
BIN
addon/cashier/source/os/components/uni-icons/uniicons.ttf
Executable file
BIN
addon/cashier/source/os/components/uni-icons/uniicons.ttf
Executable file
Binary file not shown.
5
addon/cashier/source/os/components/uni-load-more/i18n/en.json
Executable file
5
addon/cashier/source/os/components/uni-load-more/i18n/en.json
Executable file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"uni-load-more.contentdown": "Pull up to show more",
|
||||
"uni-load-more.contentrefresh": "loading...",
|
||||
"uni-load-more.contentnomore": "No more data"
|
||||
}
|
||||
8
addon/cashier/source/os/components/uni-load-more/i18n/index.js
Executable file
8
addon/cashier/source/os/components/uni-load-more/i18n/index.js
Executable 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
|
||||
}
|
||||
5
addon/cashier/source/os/components/uni-load-more/i18n/zh-Hans.json
Executable file
5
addon/cashier/source/os/components/uni-load-more/i18n/zh-Hans.json
Executable file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"uni-load-more.contentdown": "上拉显示更多",
|
||||
"uni-load-more.contentrefresh": "正在加载...",
|
||||
"uni-load-more.contentnomore": "没有更多数据了"
|
||||
}
|
||||
5
addon/cashier/source/os/components/uni-load-more/i18n/zh-Hant.json
Executable file
5
addon/cashier/source/os/components/uni-load-more/i18n/zh-Hant.json
Executable file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"uni-load-more.contentdown": "上拉顯示更多",
|
||||
"uni-load-more.contentrefresh": "正在加載...",
|
||||
"uni-load-more.contentnomore": "沒有更多數據了"
|
||||
}
|
||||
392
addon/cashier/source/os/components/uni-load-more/uni-load-more.vue
Executable file
392
addon/cashier/source/os/components/uni-load-more/uni-load-more.vue
Executable file
File diff suppressed because one or more lines are too long
407
addon/cashier/source/os/components/uni-pagination/uni-pagination.vue
Executable file
407
addon/cashier/source/os/components/uni-pagination/uni-pagination.vue
Executable file
@@ -0,0 +1,407 @@
|
||||
<template>
|
||||
<view class="uni-pagination">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view class="uni-pagination__total is-phone-hide">共 {{ total }} 条</view>
|
||||
<!-- #endif -->
|
||||
<view
|
||||
class="uni-pagination__btn"
|
||||
:class="currentIndex === 1 ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
|
||||
:hover-class="currentIndex === 1 ? '' : 'uni-pagination--hover'"
|
||||
:hover-start-time="20"
|
||||
:hover-stay-time="70"
|
||||
@click="clickLeft"
|
||||
>
|
||||
<template v-if="showIcon === true || showIcon === 'true'">
|
||||
<text class="iconfont iconqianhou1"></text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text class="uni-pagination__child-btn">{{ prevPageText }}</text>
|
||||
</template>
|
||||
</view>
|
||||
<view class="uni-pagination__num uni-pagination__num-flex-none">
|
||||
<view class="uni-pagination__num-current">
|
||||
<text class="uni-pagination__num-current-text is-pc-hide text-color">{{ currentIndex }}</text>
|
||||
<text class="uni-pagination__num-current-text is-pc-hide">/{{ maxPage || 0 }}</text>
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view
|
||||
v-for="(item, index) in paper" :key="index"
|
||||
:class="{ 'page--active': item === currentIndex }"
|
||||
class="uni-pagination__num-tag tag--active is-phone-hide"
|
||||
@click.top="selectPage(item, index)"
|
||||
>
|
||||
<text>{{ item }}</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="uni-pagination__btn"
|
||||
:class="currentIndex >= maxPage ? 'uni-pagination--disabled' : 'uni-pagination--enabled'"
|
||||
:hover-class="currentIndex === maxPage ? '' : 'uni-pagination--hover'"
|
||||
:hover-start-time="20"
|
||||
:hover-stay-time="70"
|
||||
@click="clickRight"
|
||||
>
|
||||
<template v-if="showIcon === true || showIcon === 'true'">
|
||||
<text class="iconfont iconqianhou2"></text>
|
||||
</template>
|
||||
<template v-else>
|
||||
<text class="uni-pagination__child-btn">{{ nextPageText }}</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Pagination 分页器
|
||||
* @description 分页器组件,用于展示页码、请求数据等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=32
|
||||
* @property {String} prevText 左侧按钮文字
|
||||
* @property {String} nextText 右侧按钮文字
|
||||
* @property {Number} current 当前页
|
||||
* @property {Number} total 数据总量
|
||||
* @property {Number} pageSize 每页数据量
|
||||
* @property {Number} showIcon = [true|false] 是否以 icon 形式展示按钮
|
||||
* @event {Function} change 点击页码按钮时触发 ,e={type,current} current为当前页,type值为:next/prev,表示点击的是上一页还是下一个
|
||||
*/
|
||||
export default {
|
||||
name: 'UniPagination',
|
||||
emits: ['update:modelValue', 'input', 'change'],
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
modelValue: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
prevText: {
|
||||
type: String
|
||||
},
|
||||
nextText: {
|
||||
type: String
|
||||
},
|
||||
current: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
total: {
|
||||
// 数据总量
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
pageSize: {
|
||||
// 每页数据量
|
||||
type: [Number, String],
|
||||
default: 10
|
||||
},
|
||||
showIcon: {
|
||||
// 是否以 icon 形式展示按钮
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
},
|
||||
pagerCount: {
|
||||
type: Number,
|
||||
default: 7
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 1,
|
||||
paperData: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
prevPageText() {
|
||||
return this.prevText || '上一页';
|
||||
},
|
||||
nextPageText() {
|
||||
return this.nextText || '下一页';
|
||||
},
|
||||
maxPage() {
|
||||
let maxPage = 1;
|
||||
let total = Number(this.total);
|
||||
let pageSize = Number(this.pageSize);
|
||||
if (total && pageSize) {
|
||||
maxPage = Math.ceil(total / pageSize);
|
||||
}
|
||||
return maxPage;
|
||||
},
|
||||
paper() {
|
||||
const num = this.currentIndex;
|
||||
// TODO 最大页数
|
||||
const pagerCount = this.pagerCount;
|
||||
// const total = 181
|
||||
const total = this.total;
|
||||
const pageSize = this.pageSize;
|
||||
let totalArr = [];
|
||||
let showPagerArr = [];
|
||||
let pagerNum = Math.ceil(total / pageSize);
|
||||
for (let i = 0; i < pagerNum; i++) {
|
||||
totalArr.push(i + 1);
|
||||
}
|
||||
showPagerArr.push(1);
|
||||
const totalNum = totalArr[totalArr.length - (pagerCount + 1) / 2];
|
||||
totalArr.forEach((item, index) => {
|
||||
if ((pagerCount + 1) / 2 >= num) {
|
||||
if (item < pagerCount + 1 && item > 1) {
|
||||
showPagerArr.push(item);
|
||||
}
|
||||
} else if (num + 2 <= totalNum) {
|
||||
if (item > num - (pagerCount + 1) / 2 && item < num + (pagerCount + 1) / 2) {
|
||||
showPagerArr.push(item);
|
||||
}
|
||||
} else {
|
||||
if ((item > num - (pagerCount + 1) / 2 || pagerNum - pagerCount < item) && item < totalArr[totalArr.length - 1]) {
|
||||
showPagerArr.push(item);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (pagerNum > pagerCount) {
|
||||
if ((pagerCount + 1) / 2 >= num) {
|
||||
showPagerArr[showPagerArr.length - 1] = '...';
|
||||
} else if (num + 2 <= totalNum) {
|
||||
showPagerArr[1] = '...';
|
||||
showPagerArr[showPagerArr.length - 1] = '...';
|
||||
} else {
|
||||
showPagerArr[1] = '...';
|
||||
}
|
||||
showPagerArr.push(totalArr[totalArr.length - 1]);
|
||||
} else {
|
||||
if ((pagerCount + 1) / 2 >= num) {
|
||||
} else if (num + 2 <= totalNum) {
|
||||
} else {
|
||||
showPagerArr.shift();
|
||||
showPagerArr.push(totalArr[totalArr.length - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return showPagerArr;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
current: {
|
||||
immediate: true,
|
||||
handler(val, old) {
|
||||
if (val < 1) {
|
||||
this.currentIndex = 1;
|
||||
} else {
|
||||
this.currentIndex = val;
|
||||
}
|
||||
}
|
||||
},
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (Number(this.current) !== 1) return;
|
||||
if (val < 1) {
|
||||
this.currentIndex = 1;
|
||||
} else {
|
||||
this.currentIndex = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 选择标签
|
||||
selectPage(e, index) {
|
||||
if (parseInt(e)) {
|
||||
this.currentIndex = e;
|
||||
this.change('current');
|
||||
} else {
|
||||
let pagerNum = Math.ceil(this.total / this.pageSize);
|
||||
// let pagerNum = Math.ceil(181 / this.pageSize)
|
||||
// 上一页
|
||||
if (index <= 1) {
|
||||
if (this.currentIndex - 5 > 1) {
|
||||
this.currentIndex -= 5;
|
||||
} else {
|
||||
this.currentIndex = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 下一页
|
||||
if (index >= 6) {
|
||||
if (this.currentIndex + 5 > pagerNum) {
|
||||
this.currentIndex = pagerNum;
|
||||
} else {
|
||||
this.currentIndex += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
clickLeft() {
|
||||
if (Number(this.currentIndex) === 1) {
|
||||
return;
|
||||
}
|
||||
this.currentIndex -= 1;
|
||||
this.change('prev');
|
||||
},
|
||||
clickRight() {
|
||||
if (Number(this.currentIndex) >= this.maxPage) {
|
||||
return;
|
||||
}
|
||||
this.currentIndex += 1;
|
||||
this.change('next');
|
||||
},
|
||||
change(e) {
|
||||
this.$emit('input', this.currentIndex);
|
||||
this.$emit('update:modelValue', this.currentIndex);
|
||||
this.$emit('change', {
|
||||
type: e,
|
||||
current: this.currentIndex
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.uni-pagination {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-pagination__total {
|
||||
font-size: 0.14rem;
|
||||
color: #999;
|
||||
margin-right: 0.15rem;
|
||||
}
|
||||
|
||||
.uni-pagination__btn {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
padding: 0 0.08rem;
|
||||
line-height: 0.3rem;
|
||||
font-size: $uni-font-size-base;
|
||||
position: relative;
|
||||
background-color: #f0f0f0;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
border-radius: 0.05rem;
|
||||
// border-width: .01rem;
|
||||
// border-style: solid;
|
||||
// border-color: $uni-border-color;
|
||||
}
|
||||
|
||||
.uni-pagination__child-btn {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
color: #0f1214;
|
||||
font-size: 0.12rem;
|
||||
}
|
||||
|
||||
.uni-pagination__num {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 0.3rem;
|
||||
line-height: 0.3rem;
|
||||
font-size: $uni-font-size-base;
|
||||
color: $uni-text-color;
|
||||
margin: 0 0.05rem;
|
||||
}
|
||||
|
||||
.uni-pagination__num-tag {
|
||||
cursor: pointer;
|
||||
min-width: 0.3rem;
|
||||
margin: 0 0.05rem;
|
||||
height: 0.3rem;
|
||||
text-align: center;
|
||||
line-height: 0.3rem;
|
||||
// border: .01rem red solid;
|
||||
color: #666;
|
||||
border-radius: 0.04rem;
|
||||
// border-width: .01rem;
|
||||
// border-style: solid;
|
||||
// border-color: $uni-border-color;
|
||||
}
|
||||
|
||||
.uni-pagination__num-current {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.uni-pagination__num-current-text {
|
||||
font-size: 0.15rem;
|
||||
}
|
||||
|
||||
.uni-pagination--enabled {
|
||||
color: #333333;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.uni-pagination--disabled {
|
||||
opacity: 0.5;
|
||||
/* #ifdef H5 */
|
||||
cursor: default;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-pagination--hover {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
background-color: $uni-bg-color-hover;
|
||||
}
|
||||
|
||||
.tag--active:hover {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.page--active {
|
||||
color: #fff;
|
||||
background-color: $primary-color;
|
||||
}
|
||||
|
||||
.page--active:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.is-pc-hide {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.is-phone-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 450px) {
|
||||
.is-pc-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.is-phone-hide {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.uni-pagination__num-flex-none {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
45
addon/cashier/source/os/components/uni-popup/keypress.js
Executable file
45
addon/cashier/source/os/components/uni-popup/keypress.js
Executable file
@@ -0,0 +1,45 @@
|
||||
// #ifdef H5
|
||||
export default {
|
||||
name: 'Keypress',
|
||||
props: {
|
||||
disable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const keyNames = {
|
||||
esc: ['Esc', 'Escape'],
|
||||
tab: 'Tab',
|
||||
enter: 'Enter',
|
||||
space: [' ', 'Spacebar'],
|
||||
up: ['Up', 'ArrowUp'],
|
||||
left: ['Left', 'ArrowLeft'],
|
||||
right: ['Right', 'ArrowRight'],
|
||||
down: ['Down', 'ArrowDown'],
|
||||
delete: ['Backspace', 'Delete', 'Del']
|
||||
}
|
||||
const listener = ($event) => {
|
||||
if (this.disable) {
|
||||
return
|
||||
}
|
||||
const keyName = Object.keys(keyNames).find(key => {
|
||||
const keyName = $event.key
|
||||
const value = keyNames[key]
|
||||
return value === keyName || (Array.isArray(value) && value.includes(keyName))
|
||||
})
|
||||
if (keyName) {
|
||||
// 避免和其他按键事件冲突
|
||||
setTimeout(() => {
|
||||
this.$emit(keyName, {})
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
document.addEventListener('keyup', listener)
|
||||
// this.$once('hook:beforeDestroy', () => {
|
||||
// document.removeEventListener('keyup', listener)
|
||||
// })
|
||||
},
|
||||
render: () => {}
|
||||
}
|
||||
// #endif
|
||||
26
addon/cashier/source/os/components/uni-popup/popup.js
Executable file
26
addon/cashier/source/os/components/uni-popup/popup.js
Executable file
@@ -0,0 +1,26 @@
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.popup = this.getParent()
|
||||
},
|
||||
methods:{
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getParent(name = 'uniPopup') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
}
|
||||
}
|
||||
436
addon/cashier/source/os/components/uni-popup/uni-popup.vue
Executable file
436
addon/cashier/source/os/components/uni-popup/uni-popup.vue
Executable file
@@ -0,0 +1,436 @@
|
||||
<template>
|
||||
<view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']" @touchmove.stop.prevent="clear">
|
||||
<view @touchstart="touchstart">
|
||||
<uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
|
||||
<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration"
|
||||
:show="showTrans" @click="onTap">
|
||||
<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear">
|
||||
<slot />
|
||||
</view>
|
||||
</uni-transition>
|
||||
</view>
|
||||
<!-- #ifdef H5 -->
|
||||
<keypress v-if="maskShow" @esc="onTap" />
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef H5
|
||||
import keypress from './keypress.js'
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* PopUp 弹出层
|
||||
* @description 弹出层组件,为了解决遮罩弹层的问题
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
|
||||
* @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
|
||||
* @value top 顶部弹出
|
||||
* @value center 中间弹出
|
||||
* @value bottom 底部弹出
|
||||
* @value left 左侧弹出
|
||||
* @value right 右侧弹出
|
||||
* @value message 消息提示
|
||||
* @value dialog 对话框
|
||||
* @value share 底部分享示例
|
||||
* @property {Boolean} animation = [ture|false] 是否开启动画
|
||||
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
|
||||
* @property {String} backgroundColor 主窗口背景色
|
||||
* @property {Boolean} safeArea 是否适配底部安全区
|
||||
* @event {Function} change 打开关闭弹窗触发,e={show: false}
|
||||
* @event {Function} maskClick 点击遮罩触发
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: 'uniPopup',
|
||||
components: {
|
||||
// #ifdef H5
|
||||
keypress
|
||||
// #endif
|
||||
},
|
||||
emits: ['change', 'maskClick'],
|
||||
props: {
|
||||
// 开启动画
|
||||
animation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
|
||||
// message: 消息提示 ; dialog : 对话框
|
||||
type: {
|
||||
type: String,
|
||||
default: 'center'
|
||||
},
|
||||
// maskClick
|
||||
maskClick: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: 'none'
|
||||
},
|
||||
safeArea: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
customPosition: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
/**
|
||||
* 监听type类型
|
||||
*/
|
||||
type: {
|
||||
handler: function(type) {
|
||||
if (!this.config[type]) return
|
||||
this[this.config[type]](true)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
isDesktop: {
|
||||
handler: function(newVal) {
|
||||
if (!this.config[newVal]) return
|
||||
this[this.config[this.type]](true)
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
/**
|
||||
* 监听遮罩是否可点击
|
||||
* @param {Object} val
|
||||
*/
|
||||
maskClick: {
|
||||
handler: function(val) {
|
||||
this.mkclick = val
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
duration: 300,
|
||||
ani: [],
|
||||
showPopup: false,
|
||||
showTrans: false,
|
||||
popupWidth: 0,
|
||||
popupHeight: 0,
|
||||
config: {
|
||||
top: 'top',
|
||||
bottom: 'bottom',
|
||||
center: 'center',
|
||||
left: 'left',
|
||||
right: 'right',
|
||||
message: 'top',
|
||||
dialog: 'center',
|
||||
share: 'bottom',
|
||||
custom: 'custom'
|
||||
},
|
||||
maskClass: {
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.4)'
|
||||
},
|
||||
transClass: {
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
right: 0
|
||||
},
|
||||
maskShow: true,
|
||||
mkclick: true,
|
||||
popupstyle: this.isDesktop ? 'fixforpc-top' : 'top',
|
||||
callback: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isDesktop() {
|
||||
return this.popupWidth >= 500 && this.popupHeight >= 500
|
||||
},
|
||||
bg() {
|
||||
if (this.backgroundColor === '' || this.backgroundColor === 'none') {
|
||||
return 'transparent'
|
||||
}
|
||||
return this.backgroundColor
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const fixSize = () => {
|
||||
const {
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
windowTop,
|
||||
safeAreaInsets
|
||||
} = uni.getSystemInfoSync()
|
||||
this.popupWidth = windowWidth
|
||||
this.popupHeight = windowHeight + windowTop
|
||||
// 是否适配底部安全区
|
||||
if (this.safeArea) {
|
||||
this.safeAreaInsets = safeAreaInsets
|
||||
} else {
|
||||
this.safeAreaInsets = 0
|
||||
}
|
||||
}
|
||||
fixSize()
|
||||
// #ifdef H5
|
||||
// window.addEventListener('resize', fixSize)
|
||||
// this.$once('hook:beforeDestroy', () => {
|
||||
// window.removeEventListener('resize', fixSize)
|
||||
// })
|
||||
// #endif
|
||||
},
|
||||
created() {
|
||||
this.mkclick = this.maskClick
|
||||
if (this.animation) {
|
||||
this.duration = 300
|
||||
} else {
|
||||
this.duration = 0
|
||||
}
|
||||
// TODO 处理 message 组件生命周期异常的问题
|
||||
this.messageChild = null
|
||||
// TODO 解决头条冒泡的问题
|
||||
this.clearPropagation = false
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 公用方法,不显示遮罩层
|
||||
*/
|
||||
closeMask() {
|
||||
this.maskShow = false
|
||||
},
|
||||
/**
|
||||
* 公用方法,遮罩层禁止点击
|
||||
*/
|
||||
disableMask() {
|
||||
this.mkclick = false
|
||||
},
|
||||
// TODO nvue 取消冒泡
|
||||
clear(e) {
|
||||
// #ifndef APP-NVUE
|
||||
e.stopPropagation()
|
||||
// #endif
|
||||
this.clearPropagation = true
|
||||
},
|
||||
|
||||
open(direction, callback) {
|
||||
let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'custom', 'share']
|
||||
if (!(direction && innerType.indexOf(direction) !== -1)) {
|
||||
direction = this.type
|
||||
}
|
||||
if (!this.config[direction]) {
|
||||
console.error('缺少类型:', direction)
|
||||
return
|
||||
}
|
||||
if (callback) this.callback = callback;
|
||||
this[this.config[direction]]()
|
||||
this.$emit('change', {
|
||||
show: true,
|
||||
type: direction
|
||||
})
|
||||
},
|
||||
close(type) {
|
||||
this.showTrans = false
|
||||
this.$emit('change', {
|
||||
show: false,
|
||||
type: this.type
|
||||
})
|
||||
clearTimeout(this.timer)
|
||||
// // 自定义关闭事件
|
||||
// this.customOpen && this.customClose()
|
||||
this.timer = setTimeout(() => {
|
||||
this.showPopup = false
|
||||
}, 300)
|
||||
|
||||
if (this.callback) this.callback.call(this);
|
||||
},
|
||||
// TODO 处理冒泡事件,头条的冒泡事件有问题 ,先这样兼容
|
||||
touchstart() {
|
||||
this.clearPropagation = false
|
||||
},
|
||||
|
||||
onTap() {
|
||||
if (this.clearPropagation) {
|
||||
// fix by mehaotian 兼容 nvue
|
||||
this.clearPropagation = false
|
||||
return
|
||||
}
|
||||
this.$emit('maskClick')
|
||||
if (!this.mkclick) return
|
||||
this.close()
|
||||
},
|
||||
/**
|
||||
* 顶部弹出样式处理
|
||||
*/
|
||||
custom(type) {
|
||||
this.popupstyle = 'center'
|
||||
this.ani = ['zoom-out', 'fade']
|
||||
this.transClass = this.customPosition;
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
},
|
||||
/**
|
||||
* 顶部弹出样式处理
|
||||
*/
|
||||
top(type) {
|
||||
this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
|
||||
this.ani = ['slide-top']
|
||||
this.transClass = {
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
right: 0,
|
||||
backgroundColor: this.bg
|
||||
}
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
this.$nextTick(() => {
|
||||
if (this.messageChild && this.type === 'message') {
|
||||
this.messageChild.timerClose()
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 底部弹出样式处理
|
||||
*/
|
||||
bottom(type) {
|
||||
this.popupstyle = 'bottom'
|
||||
this.ani = ['slide-bottom']
|
||||
|
||||
this.transClass = {
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
paddingBottom: (this.safeAreaInsets && this.safeAreaInsets.bottom) || 0,
|
||||
backgroundColor: this.bg
|
||||
}
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
},
|
||||
/**
|
||||
* 中间弹出样式处理
|
||||
*/
|
||||
center(type) {
|
||||
this.popupstyle = 'center'
|
||||
this.ani = ['zoom-out', 'fade']
|
||||
this.transClass = {
|
||||
position: 'fixed',
|
||||
/* #ifndef APP-NVUE */
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
/* #endif */
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
},
|
||||
left(type) {
|
||||
this.popupstyle = 'left'
|
||||
this.ani = ['slide-left']
|
||||
this.transClass = {
|
||||
position: 'fixed',
|
||||
left: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
backgroundColor: this.bg,
|
||||
/* #ifndef APP-NVUE */
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
/* #endif */
|
||||
}
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
},
|
||||
right(type) {
|
||||
this.popupstyle = 'right'
|
||||
this.ani = ['slide-right']
|
||||
this.transClass = {
|
||||
position: 'fixed',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
backgroundColor: this.bg,
|
||||
/* #ifndef APP-NVUE */
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
/* #endif */
|
||||
}
|
||||
// TODO 兼容 type 属性 ,后续会废弃
|
||||
if (type) return
|
||||
this.showPopup = true
|
||||
this.showTrans = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.uni-popup {
|
||||
position: fixed;
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 99;
|
||||
|
||||
/* #endif */
|
||||
&.top,
|
||||
&.left,
|
||||
&.right {
|
||||
/* #ifdef H5 */
|
||||
top: var(--window-top);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
top: 0;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-popup__wrapper {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: block;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
|
||||
/* iphonex 等安全区设置,底部安全区适配 */
|
||||
/* #ifndef APP-NVUE */
|
||||
// padding-bottom: constant(safe-area-inset-bottom);
|
||||
// padding-bottom: env(safe-area-inset-bottom);
|
||||
/* #endif */
|
||||
&.left,
|
||||
&.right {
|
||||
/* #ifdef H5 */
|
||||
padding-top: var(--window-top);
|
||||
/* #endif */
|
||||
/* #ifndef H5 */
|
||||
padding-top: 0;
|
||||
/* #endif */
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fixforpc-z-index {
|
||||
/* #ifndef APP-NVUE */
|
||||
z-index: 999;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.fixforpc-top {
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
||||
454
addon/cashier/source/os/components/uni-table/uni-table.vue
Executable file
454
addon/cashier/source/os/components/uni-table/uni-table.vue
Executable file
@@ -0,0 +1,454 @@
|
||||
<template>
|
||||
<view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }">
|
||||
<!-- #ifdef H5 -->
|
||||
<table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
|
||||
<slot></slot>
|
||||
<view v-if="noData" class="uni-table-loading">
|
||||
<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
|
||||
</view>
|
||||
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
|
||||
</table>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }">
|
||||
<slot></slot>
|
||||
<view v-if="noData" class="uni-table-loading">
|
||||
<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
|
||||
</view>
|
||||
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Table 表格
|
||||
* @description 用于展示多条结构类似的数据
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Boolean} border 是否带有纵向边框
|
||||
* @property {Boolean} stripe 是否显示斑马线
|
||||
* @property {Boolean} type 是否开启多选
|
||||
* @property {String} emptyText 空数据时显示的文本内容
|
||||
* @property {Boolean} loading 显示加载中
|
||||
* @event {Function} selection-change 开启多选时,当选择项发生变化时会触发该事件
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTable',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
emits:['selection-change'],
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 是否有竖线
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否显示斑马线
|
||||
stripe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 多选
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 没有更多数据
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: '没有更多数据'
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
rowKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
noData: true,
|
||||
minWidth: 0,
|
||||
multiTableHeads: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
loading(val) {},
|
||||
data(newVal) {
|
||||
let theadChildren = this.theadChildren
|
||||
let rowspan = 1
|
||||
if (this.theadChildren) {
|
||||
rowspan = this.theadChildren.rowspan
|
||||
}
|
||||
|
||||
// this.trChildren.length - rowspan
|
||||
this.noData = false
|
||||
// this.noData = newVal.length === 0
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 定义tr的实例数组
|
||||
this.trChildren = []
|
||||
this.thChildren = []
|
||||
this.theadChildren = null
|
||||
this.backData = []
|
||||
this.backIndexData = []
|
||||
},
|
||||
methods: {
|
||||
isNodata() {
|
||||
let theadChildren = this.theadChildren
|
||||
let rowspan = 1
|
||||
if (this.theadChildren) {
|
||||
rowspan = this.theadChildren.rowspan
|
||||
}
|
||||
this.noData = this.trChildren.length - rowspan <= 0
|
||||
},
|
||||
/**
|
||||
* 选中所有
|
||||
*/
|
||||
selectionAll() {
|
||||
let startIndex = 1
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
} else {
|
||||
startIndex = theadChildren.rowspan - 1
|
||||
}
|
||||
let isHaveData = this.data && this.data.length.length > 0
|
||||
theadChildren.checked = true
|
||||
theadChildren.indeterminate = false
|
||||
this.trChildren.forEach((item, index) => {
|
||||
if (!item.disabled) {
|
||||
item.checked = true
|
||||
if (isHaveData && item.keyValue) {
|
||||
const row = this.data.find(v => v[this.rowKey] === item.keyValue)
|
||||
if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) {
|
||||
this.backData.push(row)
|
||||
}
|
||||
}
|
||||
if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) {
|
||||
this.backIndexData.push(index - startIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
// this.backData = JSON.parse(JSON.stringify(this.data))
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index: this.backIndexData
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中)
|
||||
*/
|
||||
toggleRowSelection(row, selected) {
|
||||
// if (!this.theadChildren) return
|
||||
row = [].concat(row)
|
||||
|
||||
this.trChildren.forEach((item, index) => {
|
||||
// if (item.keyValue) {
|
||||
|
||||
const select = row.findIndex(v => {
|
||||
//
|
||||
if (typeof v === 'number') {
|
||||
return v === index - 1
|
||||
} else {
|
||||
return v[this.rowKey] === item.keyValue
|
||||
}
|
||||
})
|
||||
let ischeck = item.checked
|
||||
if (select !== -1) {
|
||||
if (typeof selected === 'boolean') {
|
||||
item.checked = selected
|
||||
} else {
|
||||
item.checked = !item.checked
|
||||
}
|
||||
if (ischeck !== item.checked) {
|
||||
this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true)
|
||||
}
|
||||
}
|
||||
// }
|
||||
})
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index:this.backIndexData
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 用于多选表格,清空用户的选择
|
||||
*/
|
||||
clearSelection() {
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
}
|
||||
// if (!this.theadChildren) return
|
||||
theadChildren.checked = false
|
||||
theadChildren.indeterminate = false
|
||||
this.trChildren.forEach(item => {
|
||||
// if (item.keyValue) {
|
||||
item.checked = false
|
||||
// }
|
||||
})
|
||||
this.backData = []
|
||||
this.backIndexData = []
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: [],
|
||||
index: []
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 用于多选表格,切换所有行的选中状态
|
||||
*/
|
||||
toggleAllSelection() {
|
||||
let list = []
|
||||
let startIndex = 1
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
} else {
|
||||
startIndex = theadChildren.rowspan - 1
|
||||
}
|
||||
this.trChildren.forEach((item, index) => {
|
||||
if (!item.disabled) {
|
||||
if (index > (startIndex - 1) ) {
|
||||
list.push(index-startIndex)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.toggleRowSelection(list)
|
||||
},
|
||||
|
||||
/**
|
||||
* 选中\取消选中
|
||||
* @param {Object} child
|
||||
* @param {Object} check
|
||||
* @param {Object} rowValue
|
||||
*/
|
||||
check(child, check, keyValue, emit) {
|
||||
let theadChildren = this.theadChildren
|
||||
if (!this.theadChildren) {
|
||||
theadChildren = this.trChildren[0]
|
||||
}
|
||||
|
||||
|
||||
|
||||
let childDomIndex = this.trChildren.findIndex((item, index) => child === item)
|
||||
if(childDomIndex < 0){
|
||||
childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1
|
||||
}
|
||||
const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length
|
||||
if (childDomIndex === 0) {
|
||||
check ? this.selectionAll() : this.clearSelection()
|
||||
return
|
||||
}
|
||||
|
||||
if (check) {
|
||||
if (keyValue) {
|
||||
this.backData.push(child)
|
||||
}
|
||||
this.backIndexData.push(childDomIndex - 1)
|
||||
} else {
|
||||
const index = this.backData.findIndex(v => v[this.rowKey] === keyValue)
|
||||
const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1)
|
||||
if (keyValue) {
|
||||
this.backData.splice(index, 1)
|
||||
}
|
||||
this.backIndexData.splice(idx, 1)
|
||||
}
|
||||
|
||||
const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled)
|
||||
if (!domCheckAll) {
|
||||
theadChildren.indeterminate = false
|
||||
theadChildren.checked = true
|
||||
} else {
|
||||
theadChildren.indeterminate = true
|
||||
theadChildren.checked = false
|
||||
}
|
||||
|
||||
if (this.backIndexData.length === 0) {
|
||||
theadChildren.indeterminate = false
|
||||
}
|
||||
|
||||
if (!emit) {
|
||||
this.$emit('selection-change', {
|
||||
detail: {
|
||||
value: this.backData,
|
||||
index: this.backIndexData
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-scroll {
|
||||
width: 100%;
|
||||
/* #ifndef APP-NVUE */
|
||||
overflow-x: auto;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.uni-table {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
// box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
|
||||
background-color: #fff;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
display: table;
|
||||
overflow-x: auto;
|
||||
::v-deep .uni-table-tr:nth-child(n + 2) {
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
}
|
||||
::v-deep .uni-table-thead {
|
||||
.uni-table-tr {
|
||||
// background-color: #f5f7fa;
|
||||
&:hover {
|
||||
background-color:#fafafa;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border: 1px $border-color solid;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.border-none {
|
||||
/* #ifndef APP-NVUE */
|
||||
border-bottom: none;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.table--stripe {
|
||||
/* #ifndef APP-NVUE */
|
||||
::v-deep .uni-table-tr:nth-child(2n + 3) {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* 表格加载、无数据样式 */
|
||||
.uni-table-loading {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-row;
|
||||
/* #endif */
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.empty-border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
.uni-table-text {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.uni-table-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
z-index: 99;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
margin: auto;
|
||||
transition: all 0.5s;
|
||||
/* #endif */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uni-table--loader {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 2px solid #aaa;
|
||||
// border-bottom-color: transparent;
|
||||
border-radius: 50%;
|
||||
/* #ifndef APP-NVUE */
|
||||
animation: 2s uni-table--loader linear infinite;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@keyframes uni-table--loader {
|
||||
0% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
|
||||
10% {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
20% {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
30% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
40% {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
60% {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
70% {
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
80% {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
90% {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
28
addon/cashier/source/os/components/uni-tbody/uni-tbody.vue
Executable file
28
addon/cashier/source/os/components/uni-tbody/uni-tbody.vue
Executable file
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<tbody>
|
||||
<slot></slot>
|
||||
</tbody>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'uniBody',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
90
addon/cashier/source/os/components/uni-td/uni-td.vue
Executable file
90
addon/cashier/source/os/components/uni-td/uni-td.vue
Executable file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<td class="uni-table-td" :rowspan="rowspan" :colspan="colspan" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
|
||||
<slot></slot>
|
||||
</td>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<!-- :class="{'table--border':border}" -->
|
||||
<view class="uni-table-td" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
|
||||
<slot></slot>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Td 单元格
|
||||
* @description 表格中的标准单元格组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Number} align = [left|center|right] 单元格对齐方式
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTd',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
props: {
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
rowspan: {
|
||||
type: [Number,String],
|
||||
default: 1
|
||||
},
|
||||
colspan: {
|
||||
type: [Number,String],
|
||||
default: 1
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable()
|
||||
this.border = this.root.border
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable() {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== 'uniTable') {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color:#EBEEF5;
|
||||
|
||||
.uni-table-td {
|
||||
display: table-cell;
|
||||
padding: 8px 10px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-weight: 400;
|
||||
color: #606266;
|
||||
line-height: 23px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
</style>
|
||||
499
addon/cashier/source/os/components/uni-th/filter-dropdown.vue
Executable file
499
addon/cashier/source/os/components/uni-th/filter-dropdown.vue
Executable file
@@ -0,0 +1,499 @@
|
||||
<template>
|
||||
<view class="uni-filter-dropdown">
|
||||
<view class="dropdown-btn" @click="onDropdown">
|
||||
<view class="icon-select" :class="{active: canReset}" v-if="isSelect || isRange"></view>
|
||||
<view class="icon-search" :class="{active: canReset}" v-if="isSearch">
|
||||
<view class="icon-search-0"></view>
|
||||
<view class="icon-search-1"></view>
|
||||
</view>
|
||||
<view class="icon-calendar" :class="{active: canReset}" v-if="isDate">
|
||||
<view class="icon-calendar-0"></view>
|
||||
<view class="icon-calendar-1"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-dropdown-cover" v-if="isOpened" @click="handleClose"></view>
|
||||
<view class="dropdown-popup dropdown-popup-right" v-if="isOpened" @click.stop>
|
||||
<!-- select-->
|
||||
<view v-if="isSelect" class="list">
|
||||
<label class="flex-r a-i-c list-item" v-for="(item,index) in dataList" :key="index" @click="onItemClick($event, index)">
|
||||
<check-box class="check" :checked="item.checked" />
|
||||
<view class="checklist-content">
|
||||
<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
|
||||
</view>
|
||||
</label>
|
||||
</view>
|
||||
<view v-if="isSelect" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSelectReset">{{resource.reset}}</view>
|
||||
<view class="flex-f btn btn-submit" @click="handleSelectSubmit">{{resource.submit}}</view>
|
||||
</view>
|
||||
<!-- search -->
|
||||
<view v-if="isSearch" class="search-area">
|
||||
<input class="search-input" v-model="filterValue" />
|
||||
</view>
|
||||
<view v-if="isSearch" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-submit" @click="handleSearchSubmit">{{resource.search}}</view>
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSearchReset">{{resource.reset}}</view>
|
||||
</view>
|
||||
<!-- range -->
|
||||
<view v-if="isRange">
|
||||
<view class="input-label">{{resource.gt}}</view>
|
||||
<input class="input" v-model="gtValue" />
|
||||
<view class="input-label">{{resource.lt}}</view>
|
||||
<input class="input" v-model="ltValue" />
|
||||
</view>
|
||||
<view v-if="isRange" class="flex-r opera-area">
|
||||
<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleRangeReset">{{resource.reset}}</view>
|
||||
<view class="flex-f btn btn-submit" @click="handleRangeSubmit">{{resource.submit}}</view>
|
||||
</view>
|
||||
<!-- date -->
|
||||
<view v-if="isDate">
|
||||
<uni-datetime-picker ref="datetimepicker" :value="dateRange" type="datetimerange" return-type="timestamp" @change="datetimechange" @maskClick="timepickerclose">
|
||||
<view></view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import checkBox from '../uni-tr/table-checkbox.vue'
|
||||
|
||||
const resource = {
|
||||
"reset": "重置",
|
||||
"search": "搜索",
|
||||
"submit": "确定",
|
||||
"filter": "筛选",
|
||||
"gt": "大于等于",
|
||||
"lt": "小于等于",
|
||||
"date": "日期范围"
|
||||
}
|
||||
|
||||
const DropdownType = {
|
||||
Select: "select",
|
||||
Search: "search",
|
||||
Range: "range",
|
||||
Date: "date",
|
||||
Timestamp: "timestamp"
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'FilterDropdown',
|
||||
emits:['change'],
|
||||
components: {
|
||||
checkBox
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
props: {
|
||||
filterType: {
|
||||
type: String,
|
||||
default: DropdownType.Select
|
||||
},
|
||||
filterData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
map: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
text: 'text',
|
||||
value: 'value'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
canReset() {
|
||||
if (this.isSearch) {
|
||||
return this.filterValue.length > 0
|
||||
}
|
||||
if (this.isSelect) {
|
||||
return this.checkedValues.length > 0
|
||||
}
|
||||
if (this.isRange) {
|
||||
return (this.gtValue.length > 0 && this.ltValue.length > 0)
|
||||
}
|
||||
if (this.isDate) {
|
||||
return this.dateSelect.length > 0
|
||||
}
|
||||
return false
|
||||
},
|
||||
isSelect() {
|
||||
return this.filterType === DropdownType.Select
|
||||
},
|
||||
isSearch() {
|
||||
return this.filterType === DropdownType.Search
|
||||
},
|
||||
isRange() {
|
||||
return this.filterType === DropdownType.Range
|
||||
},
|
||||
isDate() {
|
||||
return (this.filterType === DropdownType.Date || this.filterType === DropdownType.Timestamp)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterData(newVal) {
|
||||
this._copyFilters()
|
||||
},
|
||||
indeterminate(newVal) {
|
||||
this.isIndeterminate = newVal
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
resource,
|
||||
enabled: true,
|
||||
isOpened: false,
|
||||
dataList: [],
|
||||
filterValue: '',
|
||||
checkedValues: [],
|
||||
gtValue: '',
|
||||
ltValue: '',
|
||||
dateRange: [],
|
||||
dateSelect: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this._copyFilters()
|
||||
},
|
||||
methods: {
|
||||
_copyFilters() {
|
||||
let dl = JSON.parse(JSON.stringify(this.filterData))
|
||||
for (let i = 0; i < dl.length; i++) {
|
||||
if (dl[i].checked === undefined) {
|
||||
dl[i].checked = false
|
||||
}
|
||||
}
|
||||
this.dataList = dl
|
||||
},
|
||||
openPopup() {
|
||||
this.isOpened = true
|
||||
if (this.isDate) {
|
||||
this.$nextTick(() => {
|
||||
if (!this.dateRange.length) {
|
||||
this.resetDate()
|
||||
}
|
||||
this.$refs.datetimepicker.show()
|
||||
})
|
||||
}
|
||||
},
|
||||
closePopup() {
|
||||
this.isOpened = false
|
||||
},
|
||||
handleClose(e) {
|
||||
this.closePopup()
|
||||
},
|
||||
resetDate() {
|
||||
let date = new Date()
|
||||
let dateText = date.toISOString().split('T')[0]
|
||||
this.dateRange = [dateText + ' 0:00:00', dateText + ' 23:59:59']
|
||||
},
|
||||
onDropdown(e) {
|
||||
this.openPopup()
|
||||
},
|
||||
onItemClick(e, index) {
|
||||
let items = this.dataList
|
||||
let listItem = items[index]
|
||||
if (listItem.checked === undefined) {
|
||||
items[index].checked = true
|
||||
} else {
|
||||
items[index].checked = !listItem.checked
|
||||
}
|
||||
|
||||
let checkvalues = []
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
if (item.checked) {
|
||||
checkvalues.push(item.value)
|
||||
}
|
||||
}
|
||||
this.checkedValues = checkvalues
|
||||
},
|
||||
datetimechange(e) {
|
||||
this.closePopup()
|
||||
this.dateRange = e
|
||||
this.dateSelect = e
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: e
|
||||
})
|
||||
},
|
||||
timepickerclose(e) {
|
||||
this.closePopup()
|
||||
},
|
||||
handleSelectSubmit() {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: this.checkedValues
|
||||
})
|
||||
},
|
||||
handleSelectReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
var items = this.dataList
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let item = items[i]
|
||||
this.$set(item, 'checked', false)
|
||||
}
|
||||
this.checkedValues = []
|
||||
this.handleSelectSubmit()
|
||||
},
|
||||
handleSearchSubmit() {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: this.filterValue
|
||||
})
|
||||
},
|
||||
handleSearchReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
this.filterValue = ''
|
||||
this.handleSearchSubmit()
|
||||
},
|
||||
handleRangeSubmit(isReset) {
|
||||
this.closePopup()
|
||||
this.$emit('change', {
|
||||
filterType: this.filterType,
|
||||
filter: isReset === true ? [] : [parseInt(this.gtValue), parseInt(this.ltValue)]
|
||||
})
|
||||
},
|
||||
handleRangeReset() {
|
||||
if (!this.canReset) {
|
||||
return;
|
||||
}
|
||||
this.gtValue = ''
|
||||
this.ltValue = ''
|
||||
this.handleRangeSubmit(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.flex-r {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.flex-f {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.a-i-c {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.j-c-c {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-select {
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
border: solid 6px transparent;
|
||||
border-top: solid 6px #ddd;
|
||||
border-bottom: none;
|
||||
background-color: #ddd;
|
||||
background-clip: content-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.icon-select.active {
|
||||
background-color: $primary-color;
|
||||
border-top-color: $primary-color;
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
width: 12px;
|
||||
height: 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon-search-0 {
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
|
||||
.icon-search-1 {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 0;
|
||||
width: 1px;
|
||||
height: 7px;
|
||||
background-color: #ddd;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-0 {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-1 {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
|
||||
.icon-calendar {
|
||||
color: #ddd;
|
||||
width: 14px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.icon-calendar-0 {
|
||||
height: 4px;
|
||||
margin-top: 3px;
|
||||
margin-bottom: 1px;
|
||||
background-color: #ddd;
|
||||
border-radius: 2px 2px 1px 1px;
|
||||
position: relative;
|
||||
}
|
||||
.icon-calendar-0:before, .icon-calendar-0:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
width: 4px;
|
||||
height: 3px;
|
||||
border-radius: 1px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
.icon-calendar-0:before {
|
||||
left: 2px;
|
||||
}
|
||||
.icon-calendar-0:after {
|
||||
right: 2px;
|
||||
}
|
||||
|
||||
.icon-calendar-1 {
|
||||
height: 9px;
|
||||
background-color: #ddd;
|
||||
border-radius: 1px 1px 2px 2px;
|
||||
}
|
||||
|
||||
.icon-calendar.active {
|
||||
color: $primary-color;
|
||||
}
|
||||
|
||||
.icon-calendar.active .icon-calendar-0,
|
||||
.icon-calendar.active .icon-calendar-1,
|
||||
.icon-calendar.active .icon-calendar-0:before,
|
||||
.icon-calendar.active .icon-calendar-0:after {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
|
||||
.uni-filter-dropdown {
|
||||
position: relative;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.dropdown-popup {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
|
||||
min-width: 150px;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.dropdown-popup-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dropdown-popup-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.uni-dropdown-cover {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: transparent;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
padding: 5px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-item:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.check {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
min-width: 150px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.input-label {
|
||||
margin: 10px 10px 5px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
margin: 10px;
|
||||
padding: 2px 5px;
|
||||
min-width: 150px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.opera-area {
|
||||
cursor: default;
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.opera-area .btn {
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
margin: 5px;
|
||||
padding: 4px 4px;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.btn-default.disable {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: $primary-color;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
278
addon/cashier/source/os/components/uni-th/uni-th.vue
Executable file
278
addon/cashier/source/os/components/uni-th/uni-th.vue
Executable file
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }">
|
||||
<view class="uni-table-th-row">
|
||||
<view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
|
||||
<slot></slot>
|
||||
<view v-if="sortable" class="arrow-box">
|
||||
<text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
|
||||
<text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
|
||||
</view>
|
||||
</view>
|
||||
<dropdown v-if="filterType || filterData.length" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
|
||||
</view>
|
||||
</th>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// #ifdef H5
|
||||
import dropdown from './filter-dropdown.vue'
|
||||
// #endif
|
||||
/**
|
||||
* Th 表头
|
||||
* @description 表格内的表头单元格组件
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=3270
|
||||
* @property {Number | String} width 单元格宽度(支持纯数字、携带单位px或rpx)
|
||||
* @property {Boolean} sortable 是否启用排序
|
||||
* @property {Number} align = [left|center|right] 单元格对齐方式
|
||||
* @value left 单元格文字左侧对齐
|
||||
* @value center 单元格文字居中
|
||||
* @value right 单元格文字右侧对齐
|
||||
* @property {Array} filterData 筛选数据
|
||||
* @property {String} filterType [search|select] 筛选类型
|
||||
* @value search 关键字搜素
|
||||
* @value select 条件选择
|
||||
* @event {Function} sort-change 排序触发事件
|
||||
*/
|
||||
export default {
|
||||
name: 'uniTh',
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
components: {
|
||||
// #ifdef H5
|
||||
dropdown
|
||||
// #endif
|
||||
},
|
||||
emits:['sort-change','filter-change'],
|
||||
props: {
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
align: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
rowspan: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
colspan: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
sortable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
filterType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
filterData: {
|
||||
type: Array,
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false,
|
||||
ascending: false,
|
||||
descending: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 根据props中的width属性 自动匹配当前th的宽度(px)
|
||||
customWidth(){
|
||||
if(typeof this.width === 'number'){
|
||||
return this.width
|
||||
} else if(typeof this.width === 'string') {
|
||||
let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g)
|
||||
let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g)
|
||||
let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g)
|
||||
if (this.width.match(regexHaveUnitPx) !== null) { // 携带了 px
|
||||
return this.width.replace('px', '')
|
||||
} else if (this.width.match(regexHaveUnitRpx) !== null) { // 携带了 rpx
|
||||
let numberRpx = Number(this.width.replace('rpx', ''))
|
||||
let widthCoe = uni.getSystemInfoSync().screenWidth / 750
|
||||
return Math.round(numberRpx * widthCoe)
|
||||
} else if (this.width.match(regexHaveNotUnit) !== null) { // 未携带 rpx或px 的纯数字 String
|
||||
return this.width
|
||||
} else { // 不符合格式
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
contentAlign() {
|
||||
let align = 'left'
|
||||
switch (this.align) {
|
||||
case 'left':
|
||||
align = 'flex-start'
|
||||
break
|
||||
case 'center':
|
||||
align = 'center'
|
||||
break
|
||||
case 'right':
|
||||
align = 'flex-end'
|
||||
break
|
||||
}
|
||||
return align
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable('uniTable')
|
||||
this.rootTr = this.getTable('uniTr')
|
||||
this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140)
|
||||
this.border = this.root.border
|
||||
this.root.thChildren.push(this)
|
||||
},
|
||||
methods: {
|
||||
sort() {
|
||||
if (!this.sortable) return
|
||||
this.clearOther()
|
||||
if (!this.ascending && !this.descending) {
|
||||
this.ascending = true
|
||||
this.$emit('sort-change', { order: 'ascending' })
|
||||
return
|
||||
}
|
||||
if (this.ascending && !this.descending) {
|
||||
this.ascending = false
|
||||
this.descending = true
|
||||
this.$emit('sort-change', { order: 'descending' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.ascending && this.descending) {
|
||||
this.ascending = false
|
||||
this.descending = false
|
||||
this.$emit('sort-change', { order: null })
|
||||
}
|
||||
},
|
||||
ascendingFn() {
|
||||
this.clearOther()
|
||||
this.ascending = !this.ascending
|
||||
this.descending = false
|
||||
this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
|
||||
},
|
||||
descendingFn() {
|
||||
this.clearOther()
|
||||
this.descending = !this.descending
|
||||
this.ascending = false
|
||||
this.$emit('sort-change', { order: this.descending ? 'descending' : null })
|
||||
},
|
||||
clearOther() {
|
||||
this.root.thChildren.map(item => {
|
||||
if (item !== this) {
|
||||
item.ascending = false
|
||||
item.descending = false
|
||||
}
|
||||
return item
|
||||
})
|
||||
},
|
||||
ondropdown(e) {
|
||||
this.$emit("filter-change", e)
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable(name) {
|
||||
let parent = this.$parent
|
||||
let parentName = parent.$options.name
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-th {
|
||||
padding: 12px 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-cell;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: #909399;
|
||||
border-bottom: 1px $border-color solid;
|
||||
}
|
||||
|
||||
.uni-table-th-row {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
.uni-table-th-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
.arrow-box {
|
||||
}
|
||||
.arrow {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 10px;
|
||||
height: 8px;
|
||||
// border: 1px red solid;
|
||||
left: 5px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.down {
|
||||
top: 3px;
|
||||
::after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: -5px;
|
||||
transform: rotate(45deg);
|
||||
background-color: #ccc;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
.up {
|
||||
::after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 5px;
|
||||
transform: rotate(45deg);
|
||||
background-color: #ccc;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: $primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
129
addon/cashier/source/os/components/uni-thead/uni-thead.vue
Executable file
129
addon/cashier/source/os/components/uni-thead/uni-thead.vue
Executable file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<!-- #ifdef H5 -->
|
||||
<thead class="uni-table-thead">
|
||||
<tr class="uni-table-tr">
|
||||
<th :rowspan="rowspan" colspan="1" class="checkbox" :class="{ 'tr-table--border': border }">
|
||||
<table-checkbox :indeterminate="indeterminate" :checked="checked" @checkboxSelected="checkboxSelected"></table-checkbox>
|
||||
</th>
|
||||
</tr>
|
||||
<slot></slot>
|
||||
</thead>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 -->
|
||||
<view class="uni-table-thead"><slot></slot></view>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import tableCheckbox from '../uni-tr/table-checkbox.vue'
|
||||
export default {
|
||||
name: 'uniThead',
|
||||
components: {
|
||||
tableCheckbox
|
||||
},
|
||||
options: {
|
||||
virtualHost: true
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
border: false,
|
||||
selection: false,
|
||||
rowspan: 1,
|
||||
indeterminate: false,
|
||||
checked: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.root = this.getTable()
|
||||
// #ifdef H5
|
||||
this.root.theadChildren = this
|
||||
// #endif
|
||||
this.border = this.root.border
|
||||
this.selection = this.root.type
|
||||
},
|
||||
methods: {
|
||||
init(self) {
|
||||
this.rowspan++
|
||||
},
|
||||
checkboxSelected(e) {
|
||||
this.indeterminate = false
|
||||
const backIndexData = this.root.backIndexData
|
||||
const data = this.root.trChildren.filter(v => !v.disabled && v.keyValue)
|
||||
if (backIndexData.length === data.length) {
|
||||
this.checked = false
|
||||
this.root.clearSelection()
|
||||
} else {
|
||||
this.checked = true
|
||||
this.root.selectionAll()
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 获取父元素实例
|
||||
*/
|
||||
getTable(name = 'uniTable') {
|
||||
let parent = this.$parent
|
||||
let parentName = parent.$options.name
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent
|
||||
if (!parent) return false
|
||||
parentName = parent.$options.name
|
||||
}
|
||||
return parent
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
|
||||
.uni-table-thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
.uni-table-tr {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-row;
|
||||
transition: all 0.3s;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
border: 1px red solid;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
padding: 0 8px;
|
||||
width: 26px;
|
||||
padding-left: 12px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
/* #endif */
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-size: 14px;
|
||||
// text-align: center;
|
||||
}
|
||||
|
||||
.tr-table--border {
|
||||
border-right: 1px $border-color solid;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
.uni-table-tr {
|
||||
::v-deep .uni-table-th {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uni-table-td {
|
||||
&.table--border:last-child {
|
||||
// border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
177
addon/cashier/source/os/components/uni-tr/table-checkbox.vue
Executable file
177
addon/cashier/source/os/components/uni-tr/table-checkbox.vue
Executable file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<view class="uni-table-checkbox" @click="selected">
|
||||
<view v-if="!indeterminate" class="checkbox__inner" :class="{'is-checked':isChecked,'is-disable':isDisabled}">
|
||||
<view class="checkbox__inner-icon"></view>
|
||||
</view>
|
||||
<view v-else class="checkbox__inner checkbox--indeterminate">
|
||||
<view class="checkbox__inner-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TableCheckbox',
|
||||
emits:['checkboxSelected'],
|
||||
props: {
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
checked: {
|
||||
type: [Boolean,String],
|
||||
default: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
default: -1
|
||||
},
|
||||
cellData: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
checked(newVal){
|
||||
if(typeof this.checked === 'boolean'){
|
||||
this.isChecked = newVal
|
||||
}else{
|
||||
this.isChecked = true
|
||||
}
|
||||
},
|
||||
indeterminate(newVal){
|
||||
this.isIndeterminate = newVal
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isChecked: false,
|
||||
isDisabled: false,
|
||||
isIndeterminate:false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(typeof this.checked === 'boolean'){
|
||||
this.isChecked = this.checked
|
||||
}
|
||||
this.isDisabled = this.disabled
|
||||
},
|
||||
methods: {
|
||||
selected() {
|
||||
if (this.isDisabled) return
|
||||
this.isIndeterminate = false
|
||||
this.isChecked = !this.isChecked
|
||||
this.$emit('checkboxSelected', {
|
||||
checked: this.isChecked,
|
||||
data: this.cellData
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$checked-color: $primary-color;
|
||||
$border-color: #DCDFE6;
|
||||
$disable:0.4;
|
||||
|
||||
.uni-table-checkbox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
margin: 5px 0;
|
||||
cursor: pointer;
|
||||
|
||||
// 多选样式
|
||||
.checkbox__inner {
|
||||
/* #ifndef APP-NVUE */
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
z-index: 1;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
/* #ifdef APP-NVUE */
|
||||
top: 2px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
top: 2px;
|
||||
/* #endif */
|
||||
left: 5px;
|
||||
height: 7px;
|
||||
width: 3px;
|
||||
border: 1px solid #fff;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
opacity: 0;
|
||||
transform-origin: center;
|
||||
transform: rotate(45deg);
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
&.checkbox--indeterminate {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
opacity: 1;
|
||||
height: 2px;
|
||||
top: 0;
|
||||
margin: auto;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0;
|
||||
width: auto;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
transform: scale(0.5);
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
border-color: $checked-color;
|
||||
}
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
/* #ifdef H5 */
|
||||
cursor: not-allowed;
|
||||
/* #endif */
|
||||
background-color: #F2F6FC;
|
||||
border-color: $border-color;
|
||||
}
|
||||
|
||||
// 选中
|
||||
&.is-checked {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
// 选中禁用
|
||||
&.is-disable {
|
||||
opacity: $disable;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user