Initial commit
This commit is contained in:
124
components/ba-tree-picker/README.md
Normal file
124
components/ba-tree-picker/README.md
Normal file
@@ -0,0 +1,124 @@
|
||||
## 树形层级选择器
|
||||
### 简介
|
||||
为统一样式而生,树形层级选择器,picker弹窗形式的,样式和比例参照uniapp的picker和uni-data-picker组件
|
||||
* 支持单选、多选、父级选择,当然也支持单层选择
|
||||
* 支持Object对象属性自定义映射
|
||||
* 支持显示全部选中、部分选中、未选中三种状态
|
||||
* 支持快速自定义简单样式(分割线、按钮、标题、对齐等),深入样式可复写css
|
||||
|
||||
### 使用方法
|
||||
在 `script` 中引入组件
|
||||
``` javascript
|
||||
import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue"
|
||||
export default {
|
||||
components: {
|
||||
baTreePicker
|
||||
}
|
||||
```
|
||||
在 `template` 中使用组件
|
||||
``` javascript
|
||||
<ba-tree-picker ref="treePicker" :multiple='false' @select-change="selectChange" title="选择城市"
|
||||
:localdata="listData" valueKey="value" textKey="label" childrenKey="children" />
|
||||
```
|
||||
在 `script` 中定义打开方法,和选择监听
|
||||
``` javascript
|
||||
methods: {
|
||||
// 显示选择器
|
||||
showPicker() {
|
||||
this.$refs.treePicker._show();
|
||||
},
|
||||
//监听选择(ids为数组)
|
||||
selectChange(ids, names) {
|
||||
console.log(ids, names)
|
||||
}
|
||||
}
|
||||
```
|
||||
在 `template` 中调用打开
|
||||
``` javascript
|
||||
<view @click="showPicker">调用选择器</view>
|
||||
```
|
||||
|
||||
### 属性
|
||||
|属性名|类型|默认值|说明|
|
||||
|:-|:-:|:--:|-:|
|
||||
|localdata|Array|[]|源数据,目前支持tree结构,后续会考虑支持扁平化结构|
|
||||
|valueKey|String|id|指定 Object 中 key 的值作为节点数据id|
|
||||
|textKey|String|name|指定 Object 中 key 的值作为节点显示内容|
|
||||
|childrenKey|String|children|指定 Object 中 key 的值作为节点子集|
|
||||
|multiple|Boolean|false|是否多选,默认单选|
|
||||
|selectParent|Boolean|true|是否可以选父级,默认可以|
|
||||
|title|String| |标题|
|
||||
|titleColor|String||标题颜色|
|
||||
|confirmColor|String|#0055ff|确定按钮颜色|
|
||||
|cancelColor|String|#757575|取消按钮颜色|
|
||||
|switchColor|String|#666|节点切换图标颜色|
|
||||
|border|Boolean|false|是否有分割线,默认无|
|
||||
|
||||
|
||||
|
||||
### 数据格式
|
||||
|
||||
注意:必须有id、name(id可通过valueKey来配置为其它键值,如value)字段,且唯一
|
||||
|
||||
``` json
|
||||
[
|
||||
{
|
||||
id: 1,
|
||||
name: '公司1',
|
||||
children: [{
|
||||
id: 11,
|
||||
name: '研发部',
|
||||
children: [{
|
||||
id: 111,
|
||||
name: '张三',
|
||||
|
||||
},{
|
||||
id: 112,
|
||||
name: '李四',
|
||||
|
||||
}]
|
||||
},{
|
||||
id: 12,
|
||||
name: '综合部',
|
||||
|
||||
} ]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '公司2',
|
||||
children: [{
|
||||
id: 21,
|
||||
name: '研发部',
|
||||
|
||||
},{
|
||||
id: 22,
|
||||
name: '综合部',
|
||||
|
||||
},{
|
||||
id: 23,
|
||||
name: '财务部',
|
||||
|
||||
}, ]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '公司3'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '公司4',
|
||||
children: [{
|
||||
id: 41,
|
||||
name: '研发部',
|
||||
|
||||
}]
|
||||
}
|
||||
]
|
||||
```
|
||||
</details>
|
||||
|
||||
### 方法
|
||||
|方法名|参数|默认值|说明|
|
||||
|:-|:-:|:--:|-:|
|
||||
|_show()| | |显示选择器|
|
||||
|_hide()| | |隐藏选择器|
|
||||
775
components/ba-tree-picker/ba-tree-picker.vue
Normal file
775
components/ba-tree-picker/ba-tree-picker.vue
Normal file
@@ -0,0 +1,775 @@
|
||||
<!-- 树形层级选择器-->
|
||||
<!-- 1、支持单选、多选 -->
|
||||
<template>
|
||||
<view>
|
||||
<view
|
||||
class="tree-cover"
|
||||
:class="{ show: showDialog }"
|
||||
@tap="_cancel"
|
||||
></view>
|
||||
<view class="tree-dialog" :class="{ show: showDialog }">
|
||||
<view class="tree-bar">
|
||||
<view
|
||||
class="tree-bar-cancel"
|
||||
:style="{ color: cancelColor }"
|
||||
hover-class="hover-c"
|
||||
@tap="_cancel"
|
||||
>取消
|
||||
</view>
|
||||
<view class="tree-bar-title" :style="{ color: titleColor }">{{
|
||||
title
|
||||
}}</view>
|
||||
<view
|
||||
class="tree-bar-confirm"
|
||||
:style="{ color: confirmColor }"
|
||||
hover-class="hover-c"
|
||||
@tap="_confirm"
|
||||
>
|
||||
{{ multiple ? "确定" : "" }}
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="item u-border"
|
||||
style="margin: 0 16px; border-radius: 4px"
|
||||
v-if="isShowOrgPicker"
|
||||
>
|
||||
<u-picker
|
||||
:show="showOrgPicker"
|
||||
:columns="[orgList]"
|
||||
keyName="orgName"
|
||||
@confirm="confirmOrg"
|
||||
:immediateChange="true"
|
||||
@cancel="showOrgPicker = false"
|
||||
>
|
||||
</u-picker>
|
||||
<u-input
|
||||
v-model="orgName"
|
||||
border="surround"
|
||||
:disabledColor="'#ffffff'"
|
||||
disabled
|
||||
placeholder="请选择车辆主体"
|
||||
@tap="showOrgPicker = true"
|
||||
>
|
||||
<template slot="suffix">
|
||||
<u-icon
|
||||
v-if="orgName"
|
||||
name="close"
|
||||
color="#bfc7d6"
|
||||
size="50"
|
||||
@tap.stop="clearClick"
|
||||
></u-icon>
|
||||
</template>
|
||||
</u-input>
|
||||
</view>
|
||||
<view class="tree-view">
|
||||
<scroll-view class="tree-list" :scroll-y="true">
|
||||
<block v-for="(item, index) in treeList" :key="index">
|
||||
<view
|
||||
class="tree-item"
|
||||
:style="[
|
||||
{
|
||||
paddingLeft: item.level * 30 + 'rpx',
|
||||
},
|
||||
]"
|
||||
:class="{
|
||||
itemBorder: border === true,
|
||||
show: item.isShow,
|
||||
}"
|
||||
>
|
||||
<view class="item-label">
|
||||
<view
|
||||
class="item-icon uni-inline-item"
|
||||
@tap.stop="_onItemSwitch(item, index)"
|
||||
>
|
||||
<view
|
||||
v-if="!item.isLastLevel && item.isShowChild"
|
||||
class="switch-on"
|
||||
:style="{ 'border-left-color': switchColor }"
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
v-else-if="!item.isLastLevel && !item.isShowChild"
|
||||
class="switch-off"
|
||||
:style="{ 'border-top-color': switchColor }"
|
||||
>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="item-last-dot"
|
||||
:style="{ 'border-top-color': switchColor }"
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="uni-flex-item uni-inline-item"
|
||||
style="display: flex; align-items: center; flex: 1"
|
||||
@tap.stop="_onItemSelect(item, index)"
|
||||
>
|
||||
<view class="item-name">
|
||||
{{ item.name + (item.num ? "(" + item.num + ")" : "") }}
|
||||
</view>
|
||||
<view
|
||||
class="item-check"
|
||||
v-if="selectParent ? true : item.isLastLevel"
|
||||
>
|
||||
<view
|
||||
class="item-check-yes"
|
||||
v-if="item.checkStatus == 1"
|
||||
:class="{ radio: !multiple }"
|
||||
:style="{ 'border-color': confirmColor }"
|
||||
>
|
||||
<view
|
||||
class="item-check-yes-part"
|
||||
:style="{ 'background-color': confirmColor }"
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="item-check-yes"
|
||||
v-else-if="item.checkStatus == 2"
|
||||
:class="{ radio: !multiple }"
|
||||
:style="{ 'border-color': confirmColor }"
|
||||
>
|
||||
<view
|
||||
class="item-check-yes-all"
|
||||
:style="{ 'background-color': confirmColor }"
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="item-check-no"
|
||||
v-else
|
||||
:class="{ radio: !multiple }"
|
||||
:style="{ 'border-color': confirmColor }"
|
||||
></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
emits: ["select-change"],
|
||||
name: "ba-tree-picker",
|
||||
props: {
|
||||
valueKey: {
|
||||
type: String,
|
||||
default: "id",
|
||||
},
|
||||
textKey: {
|
||||
type: String,
|
||||
default: "name",
|
||||
},
|
||||
childrenKey: {
|
||||
type: String,
|
||||
default: "children",
|
||||
},
|
||||
localdata: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
localTreeList: {
|
||||
//在已经格式化好的数据
|
||||
type: Array,
|
||||
default: function () {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
selectedData: {
|
||||
type: Array,
|
||||
default: function () {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
multiple: {
|
||||
// 是否可以多选
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
selectParent: {
|
||||
//是否可以选父级
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
confirmColor: {
|
||||
// 确定按钮颜色
|
||||
type: String,
|
||||
default: "", // #0055ff
|
||||
},
|
||||
cancelColor: {
|
||||
// 取消按钮颜色
|
||||
type: String,
|
||||
default: "", // #757575
|
||||
},
|
||||
titleColor: {
|
||||
// 标题颜色
|
||||
type: String,
|
||||
default: "", //
|
||||
},
|
||||
switchColor: {
|
||||
// 节点切换图标颜色
|
||||
type: String,
|
||||
default: "", // #666
|
||||
},
|
||||
border: {
|
||||
// 是否有分割线
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isShowOrgPicker: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
treeList: [],
|
||||
showOrgPicker: false,
|
||||
orgList: [],
|
||||
orgName: "",
|
||||
orgId: "",
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
clearClick() {
|
||||
this.orgName = ""; // 重置组织名称
|
||||
this.orgId = ""; // 重置组织id
|
||||
this.$emit("emitOrgId"); //重新获取区域
|
||||
},
|
||||
getOrgList() {
|
||||
this.orgName = ""; // 重置组织名称
|
||||
this.orgId = ""; // 重置组织id
|
||||
this.$api.map.getOrgsList().then((res) => {
|
||||
console.log("res:\n", res);
|
||||
const errList = ["羚牛总部", "嘉兴羚牛汽车服务有限公司"];
|
||||
this.orgList =
|
||||
res?.filter((item) => !errList.includes(item.orgName)) || [];
|
||||
});
|
||||
},
|
||||
confirmOrg(e) {
|
||||
console.log("confirmOrg:\n", e.value[0]);
|
||||
this.orgName = e.value[0].orgName;
|
||||
this.orgId = e.value[0].id;
|
||||
this.$emit("emitOrgId", e.value[0].id);
|
||||
this.showOrgPicker = false;
|
||||
},
|
||||
_show() {
|
||||
this.showDialog = true;
|
||||
},
|
||||
_hide() {
|
||||
this.showDialog = false;
|
||||
},
|
||||
_cancel() {
|
||||
this._hide();
|
||||
this.$emit("cancel", "");
|
||||
},
|
||||
_confirm() {
|
||||
//多选
|
||||
let selectedList = []; //如果子集全部选中,只返回父级 id
|
||||
//let selectedNames;
|
||||
let currentLevel = -1;
|
||||
this.treeList.forEach((item, index) => {
|
||||
if (currentLevel >= 0 && item.level > currentLevel) {
|
||||
} else {
|
||||
if (item.checkStatus === 2) {
|
||||
currentLevel = item.level;
|
||||
selectedList.push({ id: item.id, type: item.type });
|
||||
// selectedNames = selectedNames
|
||||
// ? selectedNames + " / " + item.name
|
||||
// : item.name;
|
||||
} else {
|
||||
currentLevel = -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
//console.log('_confirm', selectedList);
|
||||
this._hide();
|
||||
const obj = this.orgId
|
||||
? { cityFilter: selectedList, orgId: this.orgId }
|
||||
: { cityFilter: selectedList };
|
||||
this.$emit("select-change", obj);
|
||||
},
|
||||
//格式化原数据(原数据为tree结构)
|
||||
_formatTreeData(list = [], level = 0, parentItem, isShowChild = true) {
|
||||
let nextIndex = 0;
|
||||
let parentId = -1;
|
||||
let initCheckStatus = 0;
|
||||
if (parentItem) {
|
||||
nextIndex =
|
||||
this.treeList.findIndex((item) => item.id === parentItem.id) + 1;
|
||||
parentId = parentItem.id;
|
||||
if (!this.multiple) {
|
||||
//单选
|
||||
initCheckStatus = 0;
|
||||
} else initCheckStatus = parentItem.checkStatus == 2 ? 2 : 0;
|
||||
}
|
||||
list.forEach((item) => {
|
||||
let isLastLevel = true;
|
||||
if (item && item[this.childrenKey]) {
|
||||
let children = item[this.childrenKey];
|
||||
if (Array.isArray(children) && children.length > 0) {
|
||||
isLastLevel = false;
|
||||
}
|
||||
}
|
||||
|
||||
let itemT = {
|
||||
id: item[this.valueKey],
|
||||
name: item[this.textKey],
|
||||
level,
|
||||
isLastLevel,
|
||||
isShow: isShowChild,
|
||||
isShowChild: false,
|
||||
checkStatus: initCheckStatus,
|
||||
orCheckStatus: 0,
|
||||
parentId,
|
||||
children: item[this.childrenKey],
|
||||
childCount: item[this.childrenKey]
|
||||
? item[this.childrenKey].length
|
||||
: 0,
|
||||
childCheckCount: 0,
|
||||
childCheckPCount: 0,
|
||||
type: item.type, //新增type字段 后端接收数据需要这个type
|
||||
num: item.num, //新增num字段 只显示车辆数量 不显示行政区数量 用后退返回数据
|
||||
};
|
||||
|
||||
if (this.selectedData.indexOf(itemT.id) >= 0) {
|
||||
itemT.checkStatus = 2;
|
||||
itemT.orCheckStatus = 2;
|
||||
itemT.childCheckCount = itemT.children ? itemT.children.length : 0;
|
||||
this._onItemParentSelect(itemT, nextIndex);
|
||||
}
|
||||
|
||||
this.treeList.splice(nextIndex, 0, itemT);
|
||||
nextIndex++;
|
||||
});
|
||||
//console.log(this.treeList);
|
||||
},
|
||||
// 节点打开、关闭切换
|
||||
_onItemSwitch(item, index) {
|
||||
// console.log(item)
|
||||
//console.log('_itemSwitch')
|
||||
if (item.isLastLevel === true) {
|
||||
return;
|
||||
}
|
||||
item.isShowChild = !item.isShowChild;
|
||||
if (item.children) {
|
||||
this._formatTreeData(item.children, item.level + 1, item);
|
||||
item.children = undefined;
|
||||
} else {
|
||||
this._onItemChildSwitch(item, index);
|
||||
}
|
||||
},
|
||||
_onItemChildSwitch(item, index) {
|
||||
//console.log('_onItemChildSwitch')
|
||||
const firstChildIndex = index + 1;
|
||||
if (firstChildIndex > 0)
|
||||
for (var i = firstChildIndex; i < this.treeList.length; i++) {
|
||||
let itemChild = this.treeList[i];
|
||||
if (itemChild.level > item.level) {
|
||||
if (item.isShowChild) {
|
||||
if (itemChild.parentId === item.id) {
|
||||
itemChild.isShow = item.isShowChild;
|
||||
if (!itemChild.isShow) {
|
||||
itemChild.isShowChild = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
itemChild.isShow = item.isShowChild;
|
||||
itemChild.isShowChild = false;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 节点选中、取消选中
|
||||
_onItemSelect(item, index) {
|
||||
//console.log('_onItemSelect')
|
||||
//console.log(item)
|
||||
if (!this.multiple) {
|
||||
//单选
|
||||
item.checkStatus = item.checkStatus == 0 ? 2 : 0;
|
||||
|
||||
this.treeList.forEach((v, i) => {
|
||||
if (i != index) {
|
||||
this.treeList[i].checkStatus = 0;
|
||||
} else {
|
||||
this.treeList[i].checkStatus = 2;
|
||||
}
|
||||
});
|
||||
|
||||
let selectedList = [];
|
||||
let selectedNames;
|
||||
selectedList.push(item);
|
||||
selectedNames = item.name;
|
||||
this._hide();
|
||||
this.$emit("select-change", selectedList, selectedNames);
|
||||
return;
|
||||
}
|
||||
|
||||
let oldCheckStatus = item.checkStatus;
|
||||
switch (oldCheckStatus) {
|
||||
case 0:
|
||||
item.checkStatus = 2;
|
||||
item.childCheckCount = item.childCount;
|
||||
item.childCheckPCount = 0;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
item.checkStatus = 0;
|
||||
item.childCheckCount = 0;
|
||||
item.childCheckPCount = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//子节点 全部选中
|
||||
this._onItemChildSelect(item, index);
|
||||
//父节点 选中状态变化
|
||||
this._onItemParentSelect(item, index, oldCheckStatus);
|
||||
},
|
||||
_onItemChildSelect(item, index) {
|
||||
//console.log('_onItemChildSelect')
|
||||
let allChildCount = 0;
|
||||
if (item.childCount && item.childCount > 0) {
|
||||
index++;
|
||||
while (
|
||||
index < this.treeList.length &&
|
||||
this.treeList[index].level > item.level
|
||||
) {
|
||||
let itemChild = this.treeList[index];
|
||||
itemChild.checkStatus = item.checkStatus;
|
||||
if (itemChild.checkStatus == 2) {
|
||||
itemChild.childCheckCount = itemChild.childCount;
|
||||
itemChild.childCheckPCount = 0;
|
||||
} else if (itemChild.checkStatus == 0) {
|
||||
itemChild.childCheckCount = 0;
|
||||
itemChild.childCheckPCount = 0;
|
||||
}
|
||||
// console.log('>>>>index:', index, 'item:', itemChild.name, ' status:', itemChild
|
||||
// .checkStatus)
|
||||
index++;
|
||||
}
|
||||
}
|
||||
},
|
||||
_onItemParentSelect(item, index, oldCheckStatus) {
|
||||
//console.log('_onItemParentSelect')
|
||||
//console.log(item)
|
||||
const parentIndex = this.treeList.findIndex(
|
||||
(itemP) => itemP.id == item.parentId
|
||||
);
|
||||
//console.log('parentIndex:' + parentIndex)
|
||||
if (parentIndex >= 0) {
|
||||
let itemParent = this.treeList[parentIndex];
|
||||
let count = itemParent.childCheckCount;
|
||||
let oldCheckStatusParent = itemParent.checkStatus;
|
||||
|
||||
if (oldCheckStatus == 1) {
|
||||
itemParent.childCheckPCount -= 1;
|
||||
} else if (oldCheckStatus == 2) {
|
||||
itemParent.childCheckCount -= 1;
|
||||
}
|
||||
if (item.checkStatus == 1) {
|
||||
itemParent.childCheckPCount += 1;
|
||||
} else if (item.checkStatus == 2) {
|
||||
itemParent.childCheckCount += 1;
|
||||
}
|
||||
|
||||
if (
|
||||
itemParent.childCheckCount <= 0 &&
|
||||
itemParent.childCheckPCount <= 0
|
||||
) {
|
||||
itemParent.childCheckCount = 0;
|
||||
itemParent.childCheckPCount = 0;
|
||||
itemParent.checkStatus = 0;
|
||||
} else if (itemParent.childCheckCount >= itemParent.childCount) {
|
||||
itemParent.childCheckCount = itemParent.childCount;
|
||||
itemParent.childCheckPCount = 0;
|
||||
itemParent.checkStatus = 2;
|
||||
} else {
|
||||
itemParent.checkStatus = 1;
|
||||
}
|
||||
//console.log('itemParent:', itemParent)
|
||||
this._onItemParentSelect(itemParent, parentIndex, oldCheckStatusParent);
|
||||
}
|
||||
},
|
||||
// 重置数据
|
||||
_reTreeList() {
|
||||
this.treeList.forEach((v, i) => {
|
||||
this.treeList[i].checkStatus = v.orCheckStatus;
|
||||
});
|
||||
},
|
||||
_initTree() {
|
||||
this.treeList = [];
|
||||
this._formatTreeData(this.localdata);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
localdata() {
|
||||
this._initTree();
|
||||
},
|
||||
localTreeList() {
|
||||
this.treeList = this.localTreeList;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this._initTree();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
/deep/ .u-border {
|
||||
border-width: 1rpx !important;
|
||||
border-color: #d4c7c7 !important;
|
||||
border-style: solid !important;
|
||||
}
|
||||
.tree-cover {
|
||||
position: fixed;
|
||||
top: 0rpx;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
z-index: 100;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
opacity: 0;
|
||||
transition: all 0.3s ease;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tree-cover.show {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tree-dialog {
|
||||
position: fixed;
|
||||
top: 0rpx;
|
||||
right: 0rpx;
|
||||
bottom: 0rpx;
|
||||
left: 0rpx;
|
||||
background-color: #fff;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
z-index: 102;
|
||||
top: 20%;
|
||||
transition: all 0.3s ease;
|
||||
transform: translateY(100%);
|
||||
}
|
||||
|
||||
.tree-dialog.show {
|
||||
transform: translateY(0);
|
||||
padding-bottom: 65px;
|
||||
}
|
||||
|
||||
.tree-bar {
|
||||
/* background-color: #fff; */
|
||||
height: 90rpx;
|
||||
padding-left: 25rpx;
|
||||
padding-right: 25rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-bottom-width: 1rpx !important;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: #f5f5f5;
|
||||
font-size: 32rpx;
|
||||
color: #757575;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tree-bar-confirm {
|
||||
color: #0055ff;
|
||||
padding: 15rpx;
|
||||
}
|
||||
|
||||
.tree-bar-title {
|
||||
}
|
||||
|
||||
.tree-bar-cancel {
|
||||
color: #757575;
|
||||
padding: 15rpx;
|
||||
}
|
||||
|
||||
.tree-view {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tree-list {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tree-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
transition: 0.2s;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tree-item.show {
|
||||
height: 90rpx;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tree-item.showchild:before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.tree-item.last:before {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.switch-on {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 10rpx solid transparent;
|
||||
border-right: 10rpx solid transparent;
|
||||
border-top: 15rpx solid #666;
|
||||
}
|
||||
|
||||
.switch-off {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 10rpx solid transparent;
|
||||
border-top: 10rpx solid transparent;
|
||||
border-left: 15rpx solid #666;
|
||||
}
|
||||
|
||||
.item-last-dot {
|
||||
position: absolute;
|
||||
width: 10rpx;
|
||||
height: 10rpx;
|
||||
border-radius: 100%;
|
||||
background: #666;
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
margin-right: 8rpx;
|
||||
padding-right: 20rpx;
|
||||
padding-left: 20rpx;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 450rpx;
|
||||
}
|
||||
|
||||
.item-check {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-check-yes,
|
||||
.item-check-no {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-top-left-radius: 20%;
|
||||
border-top-right-radius: 20%;
|
||||
border-bottom-right-radius: 20%;
|
||||
border-bottom-left-radius: 20%;
|
||||
border-top-width: 1rpx;
|
||||
border-left-width: 1rpx;
|
||||
border-bottom-width: 1rpx;
|
||||
border-right-width: 1rpx;
|
||||
border-style: solid;
|
||||
border-color: #0055ff;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.item-check-yes-part {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-top-left-radius: 20%;
|
||||
border-top-right-radius: 20%;
|
||||
border-bottom-right-radius: 20%;
|
||||
border-bottom-left-radius: 20%;
|
||||
background-color: #0055ff;
|
||||
}
|
||||
|
||||
.item-check-yes-all {
|
||||
margin-bottom: 5px;
|
||||
border: 2px solid #007aff;
|
||||
border-left: 0;
|
||||
border-top: 0;
|
||||
height: 12px;
|
||||
width: 6px;
|
||||
transform-origin: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
transition: all 0.3s;
|
||||
/* #endif */
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.item-check .radio {
|
||||
border-top-left-radius: 50%;
|
||||
border-top-right-radius: 50%;
|
||||
border-bottom-right-radius: 50%;
|
||||
border-bottom-left-radius: 50%;
|
||||
}
|
||||
|
||||
.item-check .radio .item-check-yes-b {
|
||||
border-top-left-radius: 50%;
|
||||
border-top-right-radius: 50%;
|
||||
border-bottom-right-radius: 50%;
|
||||
border-bottom-left-radius: 50%;
|
||||
}
|
||||
|
||||
.hover-c {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.itemBorder {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
</style>
|
||||
88
components/dic-select/dic-select.vue
Normal file
88
components/dic-select/dic-select.vue
Normal file
@@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<view>
|
||||
<u--input :value="select" disabled disabledColor="#ffffff" :placeholder="placeholder" border="none"></u--input>
|
||||
|
||||
|
||||
<u-picker :show="show" :loading="loading" ref="uPicker" :columns="columns" @confirm="confirm" keyName="dicName"
|
||||
@cancel="show = false"></u-picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "@/utils/request";
|
||||
export default {
|
||||
name: "dic-select",
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
require: true
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
select() {
|
||||
if (this.value == undefined || this.value == "") {
|
||||
return '';
|
||||
}
|
||||
for (var i = 0; i < (this.columns[0] || []).length; i++) {
|
||||
const item=this.columns[0][i]
|
||||
if(item.dicCode==this.value){
|
||||
return item.dicName;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getDic();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [
|
||||
[
|
||||
|
||||
]
|
||||
],
|
||||
loading: false,
|
||||
value:undefined,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getDic() {
|
||||
const that = this;
|
||||
this.loading = true;
|
||||
axios.get("/dic/queryByDicType", {
|
||||
"dicType": this.code
|
||||
}).then(res => {
|
||||
that.columns[0]=res;
|
||||
that.$refs.uPicker.setColumnValues(0, res);
|
||||
that.loading = false;
|
||||
}).catch(error => {
|
||||
that.loading = false;
|
||||
this.closeShow();
|
||||
});
|
||||
},
|
||||
confirm(e) {
|
||||
this.value = e.value[0].dicCode;
|
||||
this.$emit("selectChangeValue",e.value[0].dicCode)
|
||||
this.$emit("selectChange",e.value[0])
|
||||
this.closeShow();
|
||||
},
|
||||
closeShow(){
|
||||
this.$emit("closeShow",false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
70
components/dic-select/select-show.vue
Normal file
70
components/dic-select/select-show.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-picker :show="show" :loading="loading" ref="uPicker" :columns="columns" @confirm="confirm" keyName="dicName"
|
||||
@cancel="show = false"></u-picker>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default{
|
||||
name:"select-show"
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
code: {
|
||||
type: String,
|
||||
require: true
|
||||
},
|
||||
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getDic();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [
|
||||
[
|
||||
|
||||
]
|
||||
],
|
||||
loading: false,
|
||||
value:undefined,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getDic() {
|
||||
const that = this;
|
||||
this.loading = true;
|
||||
axios.get("/dic/queryByDicType", {
|
||||
"dicType": this.code
|
||||
}).then(res => {
|
||||
that.columns[0]=res;
|
||||
that.$refs.uPicker.setColumnValues(0, res);
|
||||
that.loading = false;
|
||||
}).catch(error => {
|
||||
that.loading = false;
|
||||
this.closeShow();
|
||||
});
|
||||
},
|
||||
confirm(e) {
|
||||
this.value = e.value[0].dicCode;
|
||||
this.$emit("selectChangeValue",e.value[0].dicCode)
|
||||
this.$emit("selectChange",e.value[0])
|
||||
this.closeShow();
|
||||
},
|
||||
closeShow(){
|
||||
this.$emit("closeShow",false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
262
components/multiple-picker/multiple-picker.vue
Normal file
262
components/multiple-picker/multiple-picker.vue
Normal file
@@ -0,0 +1,262 @@
|
||||
<template>
|
||||
<view class="popup" v-show="show">
|
||||
<view class="bg" @tap="cancelMultiple"></view>
|
||||
<view class="selectMultiple" :animation="animationData">
|
||||
<view class="multipleBody">
|
||||
<view class="title">
|
||||
<view class="close" @tap="cancelMultiple">
|
||||
取消
|
||||
</view>
|
||||
<view class="name">
|
||||
{{title}}
|
||||
</view>
|
||||
<view class="confirm" @tap="confirmMultiple">
|
||||
确认
|
||||
</view>
|
||||
</view>
|
||||
<view class="list">
|
||||
<view class="mask mask-top"></view>
|
||||
<view class="mask mask-bottom"></view>
|
||||
<scroll-view class="diet-list" scroll-y="true">
|
||||
<view v-for="(item, index) in list" :class="['item', item.selected ? 'checked' : '']" @tap="onChange(index, item)">
|
||||
<span>{{item.label}}</span>
|
||||
<view class="icon" v-show="item.selected">
|
||||
<icon type="success_no_circle" size="16" color="#2D8DFF"/>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name:"multiple-picker",
|
||||
data() {
|
||||
return {
|
||||
// 选中值
|
||||
value: [],
|
||||
// 选中列表
|
||||
selected: [],
|
||||
// 列表数据
|
||||
list: [],
|
||||
// 出场动画
|
||||
animationData: {},
|
||||
};
|
||||
},
|
||||
props: {
|
||||
// 是否显示
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 标题
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
//数据列表
|
||||
columns: {
|
||||
type: Array,
|
||||
default: [
|
||||
{
|
||||
label: '测试1',
|
||||
value: '1',
|
||||
}
|
||||
]
|
||||
},
|
||||
// 默认选中
|
||||
defaultIndex: {
|
||||
type: Array,
|
||||
default: [],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 监听是否显示
|
||||
show(val) {
|
||||
if(val) {
|
||||
this.openMultiple();
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 列点击事件
|
||||
onChange(index, item) {
|
||||
// 是否已选中
|
||||
if(this.value.indexOf(item.value.toString()) >= 0) {
|
||||
this.list[index].selected = false;
|
||||
}
|
||||
else {
|
||||
this.list[index].selected = true;
|
||||
}
|
||||
|
||||
// 筛选已勾选数据
|
||||
this.value = [];
|
||||
this.selected = [];
|
||||
this.list.forEach((col_item, col_index) => {
|
||||
if(col_item.selected) {
|
||||
this.value.push(col_item.value.toString());
|
||||
this.selected.push({
|
||||
label: col_item.label,
|
||||
value: col_item.value,
|
||||
});
|
||||
}
|
||||
});
|
||||
this.$emit("change", {selected: this.selected, value: this.value});
|
||||
},
|
||||
// 弹出框开启触发事件
|
||||
openMultiple() {
|
||||
// 初始化列表数据,默认勾选数据
|
||||
this.value = this.defaultIndex;
|
||||
this.columns.forEach((item, index) => {
|
||||
this.$set(item, "selected", false);
|
||||
if(this.value.indexOf(item.value.toString()) >= 0) {
|
||||
item.selected = true;
|
||||
}
|
||||
});
|
||||
this.list = Object.assign([], this.columns);
|
||||
// 弹出动画
|
||||
this.openAnimation();
|
||||
},
|
||||
// 确认
|
||||
confirmMultiple() {
|
||||
this.$emit("confirm", {selected: this.selected, value: this.value});
|
||||
},
|
||||
// 关闭/取消
|
||||
cancelMultiple() {
|
||||
this.$emit("cancel");
|
||||
},
|
||||
// 展开动画
|
||||
openAnimation() {
|
||||
var animation = uni.createAnimation()
|
||||
animation.translate(0, 300).step({ duration: 0 });
|
||||
this.animationData = animation.export();
|
||||
this.$nextTick(() => {
|
||||
animation.translate(0, 0).step({ duration: 300, timingFunction: 'ease' });
|
||||
this.animationData = animation.export()
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.popup {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
.bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(black, .5);
|
||||
}
|
||||
}
|
||||
.selectMultiple {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background-color: white;
|
||||
|
||||
.multipleBody {
|
||||
width: 100%;
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 80rpx;
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.close {
|
||||
width: 80rpx;
|
||||
opacity: .5;
|
||||
}
|
||||
.name {
|
||||
width: 530rpx;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient:vertical;
|
||||
-webkit-line-clamp:1;
|
||||
}
|
||||
.confirm {
|
||||
width: 80rpx;
|
||||
text-align: right;
|
||||
color: #2D8DFF;
|
||||
}
|
||||
}
|
||||
.list {
|
||||
width: 100%;
|
||||
padding-top: 30rpx;
|
||||
position: relative;
|
||||
|
||||
.mask {
|
||||
width: 100%;
|
||||
height: 120rpx;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
|
||||
&.mask-top {
|
||||
top: 30rpx;
|
||||
background-image: linear-gradient(to bottom, #fff, rgba(#fff, 0));
|
||||
}
|
||||
&.mask-bottom {
|
||||
bottom: 0;
|
||||
background-image: linear-gradient(to bottom, rgba(#fff, 0), #fff);
|
||||
}
|
||||
}
|
||||
|
||||
.diet-list {
|
||||
max-height: 400rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
line-height: 40rpx;
|
||||
border-bottom: 1px solid rgba($color: #000000, $alpha: .05);
|
||||
padding: 20rpx 0;
|
||||
font-size: 30rpx;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient:vertical;
|
||||
-webkit-line-clamp:1;
|
||||
padding: 0 40rpx;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
right: 10rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
height: 16px;
|
||||
}
|
||||
&.checked {
|
||||
color: #2D8DFF;
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
&:first-child {
|
||||
margin-top: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
73
components/no-bad-table/loading.vue
Normal file
73
components/no-bad-table/loading.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<view class="mask">
|
||||
<view class="three-bounce">
|
||||
<view class="bounce1"></view>
|
||||
<view class="bounce2"></view>
|
||||
<view class="bounce3"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.mask{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left:0;
|
||||
top:0;
|
||||
z-index:600;
|
||||
background:rgba(0,0,0,.75);
|
||||
}
|
||||
.three-bounce {
|
||||
min-width: 60px;
|
||||
min-height: 30px;
|
||||
position: absolute;
|
||||
left:50%;
|
||||
top:50%;
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
z-index:100;
|
||||
}
|
||||
|
||||
.three-bounce view {
|
||||
width: 12%;
|
||||
height: 12%;
|
||||
min-height: 10px;
|
||||
min-width: 10px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
animation: bouncedelay 1.4s infinite ease-in-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.three-bounce .bounce1 {
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.three-bounce .bounce2 {
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
|
||||
@keyframes bouncedelay {
|
||||
|
||||
0%,
|
||||
80%,
|
||||
100% {
|
||||
transform: scale(0.0);
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
293
components/no-bad-table/table.scss
Normal file
293
components/no-bad-table/table.scss
Normal file
@@ -0,0 +1,293 @@
|
||||
$div-table-border-color: #666;
|
||||
$div-table-border-width: 1upx;
|
||||
@mixin fixBorderWidth($dir:none) {
|
||||
@if $dir==none{
|
||||
|
||||
@media screen and (-webkit-device-pixel-ratio: 1) {
|
||||
border-width: 1px;
|
||||
}
|
||||
@media screen and (-webkit-device-pixel-ratio: 2) {
|
||||
border-width: .5px;
|
||||
}
|
||||
@media screen and (-webkit-device-pixel-ratio: 3) {
|
||||
border-width: .5px;
|
||||
}
|
||||
}
|
||||
@else{
|
||||
@media screen and (-webkit-device-pixel-ratio: 1) {
|
||||
border-#{$dir}-width: 1px;
|
||||
}
|
||||
@media screen and (-webkit-device-pixel-ratio: 2) {
|
||||
border-#{$dir}-width: .5px;
|
||||
}
|
||||
@media screen and (-webkit-device-pixel-ratio: 3) {
|
||||
border-#{$dir}-width: .5px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.no-bad-table-wrap {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
//外层容器
|
||||
.table_box_big {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
// height: 350px;
|
||||
}
|
||||
//工具类
|
||||
.verticalV{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
left:50%;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.table_box {
|
||||
overflow: auto;
|
||||
// position: absolute;
|
||||
}
|
||||
|
||||
.table_tbody_box {
|
||||
// height: 300px;
|
||||
// overflow: scroll;
|
||||
}
|
||||
|
||||
//没有任何数据
|
||||
.empty-data-body-box {
|
||||
min-height: 100px;
|
||||
line-height: 100px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
border: 1px solid $div-table-border-color;
|
||||
@include fixBorderWidth;
|
||||
border-top: 0;
|
||||
|
||||
}
|
||||
|
||||
&.fix-height {
|
||||
|
||||
.table_box_big {
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
position: relative;
|
||||
|
||||
// height: 350px;
|
||||
}
|
||||
|
||||
.table_box {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.table_tbody_box {
|
||||
// height: 300px;
|
||||
overflow: scroll;
|
||||
border-bottom: 1px solid $div-table-border-color;
|
||||
@include fixBorderWidth(bottom);
|
||||
}
|
||||
|
||||
//固定高低里面的内容表格底部不要边框
|
||||
.div-table-body {
|
||||
border-top: 0;
|
||||
border-bottom:0;
|
||||
//固定高度,数据为空
|
||||
&.empty-data-body-box{
|
||||
border-bottom: $div-table-border-width solid $div-table-border-color;
|
||||
@include fixBorderWidth(bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//头部表格
|
||||
.th,
|
||||
.thead .tr,
|
||||
.fixed-thead-tr {
|
||||
.td {
|
||||
background-color: #e0e0ea;
|
||||
|
||||
.td_wrap {
|
||||
background-color: #e0e0ea;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//固定右边一列
|
||||
.fixed-right {
|
||||
position: absolute;
|
||||
top: 0upx;
|
||||
right: 0px;
|
||||
z-index: 100;
|
||||
// border-right: $div-table-border-width solid $div-table-border-color;
|
||||
// border-left: $div-table-border-width solid $div-table-border-color;
|
||||
box-shadow: -2px 0 5px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
//固定左边一列
|
||||
.fixed-left {
|
||||
position: absolute;
|
||||
top: 0upx;
|
||||
left: -1px;
|
||||
z-index: 100;
|
||||
border-right: $div-table-border-width solid $div-table-border-color;
|
||||
border-left: $div-table-border-width solid $div-table-border-color;
|
||||
@include fixBorderWidth(right);
|
||||
@include fixBorderWidth(left);
|
||||
box-shadow: 2px 0 5px rgba(0, 0, 0, .5);
|
||||
}
|
||||
|
||||
.tr,
|
||||
.th {
|
||||
display: table-row;
|
||||
|
||||
&+.tr,
|
||||
&+.th {
|
||||
|
||||
.td,
|
||||
.th {
|
||||
border-top: $div-table-border-width solid $div-table-border-color;
|
||||
@include fixBorderWidth(top);
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
//外层容器控制td左右居中
|
||||
&.td-center{
|
||||
.td {
|
||||
.td_wrap{
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.td {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.td_wrap {
|
||||
position: relative;
|
||||
padding: 10upx;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&.colspan {
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
.td_wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
&.rowspan {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&.empty-cells-for-celspan {
|
||||
border-left: none !important;
|
||||
|
||||
.td_wrap {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-cells-for-rowspan {
|
||||
border-top: none !important;
|
||||
|
||||
.td_wrap {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.noPadding {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&+.td {
|
||||
border-left: $div-table-border-width solid $div-table-border-color;
|
||||
@include fixBorderWidth(left);
|
||||
}
|
||||
}
|
||||
|
||||
.th .td {
|
||||
font-weight: bold;
|
||||
}
|
||||
//单选样式========》选中
|
||||
.selected {
|
||||
.td {
|
||||
background-color: #d3e3ef;
|
||||
|
||||
.td_wrap {
|
||||
background-color: #d3e3ef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//单选样式===》禁用
|
||||
.disabled {
|
||||
.td {
|
||||
background-color: #f8f8f9;
|
||||
opacity: .6;
|
||||
}
|
||||
}
|
||||
|
||||
.div-table {
|
||||
display: table;
|
||||
border: $div-table-border-width solid $div-table-border-color;
|
||||
@include fixBorderWidth;
|
||||
box-sizing: border-box;
|
||||
table-layout: fixed;
|
||||
position: relative;
|
||||
|
||||
&.div-table-body {
|
||||
border-top: 0;
|
||||
}
|
||||
.tbody {
|
||||
display: table-row-group;
|
||||
}
|
||||
|
||||
.thead {
|
||||
display: table-header-group;
|
||||
|
||||
// .tr,
|
||||
// .th {
|
||||
//
|
||||
// .td,
|
||||
// .th {
|
||||
// width: 120upx;
|
||||
// height: 75px;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.colgroup {
|
||||
display: table-column-group;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: table-column;
|
||||
}
|
||||
|
||||
.caption {
|
||||
display: table-caption;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
841
components/no-bad-table/table.vue
Normal file
841
components/no-bad-table/table.vue
Normal file
@@ -0,0 +1,841 @@
|
||||
<template>
|
||||
<view
|
||||
class="no-bad-table-wrap"
|
||||
:class="[
|
||||
tableHeight != 'auto' ? 'fix-height' : '',
|
||||
celCenter ? 'td-center' : '',
|
||||
]"
|
||||
>
|
||||
<view class="table_box_big" :style="{ height: tableHeight }">
|
||||
<view class="table_box">
|
||||
<!-- 头部内容 【-->
|
||||
<view class="div-table div-table-head">
|
||||
<view class="thead">
|
||||
<view class="tr">
|
||||
<view
|
||||
class="td selection"
|
||||
v-if="selection == 'mulit'"
|
||||
:style="{ width: selectionTdWidth, height: thTdHeight + 'px' }"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{
|
||||
width: selectionTdWidth,
|
||||
height: thTdHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<checkbox-group @change="checkboxChangeAll">
|
||||
<checkbox
|
||||
value="all"
|
||||
color="#999"
|
||||
:checked="switchAllCheckBox"
|
||||
style="transform: scale(0.7)"
|
||||
/>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="td"
|
||||
:style="{
|
||||
width: countHeadColspanWidth(item, index),
|
||||
height: thTdHeight + 'px',
|
||||
}"
|
||||
v-for="(item, index) in columns"
|
||||
:key="item.key"
|
||||
>
|
||||
<view
|
||||
class="td_wrap"
|
||||
:style="{
|
||||
width: countHeadColspanWidth(item, index, true),
|
||||
height: thTdHeight + 'px',
|
||||
}"
|
||||
>{{ item.title }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 头部内容 】-->
|
||||
<!-- 有数据情况 -->
|
||||
<template v-if="list.length">
|
||||
<view class="table_tbody_box" :style="{ height: talbeBodyHeight }">
|
||||
<view class="div-table div-table-body">
|
||||
<checkbox-group @change="checkboxChange">
|
||||
<template v-for="(item, index) in list">
|
||||
<view
|
||||
:class="[
|
||||
'tr',
|
||||
rowClassNamePlus(item, index),
|
||||
selection == 'single' && checkBoxList[index].$checked
|
||||
? 'selected'
|
||||
: '',
|
||||
selection == 'single' && checkBoxList[index].$disabled
|
||||
? 'disabled'
|
||||
: '',
|
||||
]"
|
||||
@click="selectRow(item, index)"
|
||||
:key="item.id"
|
||||
>
|
||||
<!-- 多选操作 -->
|
||||
<view
|
||||
class="td selection"
|
||||
v-if="selection == 'mulit'"
|
||||
:style="{
|
||||
width: selectionTdWidth,
|
||||
height: tdHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{
|
||||
width: selectionTdWidth,
|
||||
height: tdHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<checkbox
|
||||
:value="checkBoxList[index].id"
|
||||
color="#999"
|
||||
:disabled="checkBoxList[index].$disabled"
|
||||
:checked="checkBoxList[index].$checked"
|
||||
style="transform: scale(0.7)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<template v-for="(tdItem, tdItemIndex) in columns">
|
||||
<view
|
||||
class="td"
|
||||
:class="[
|
||||
item.cellClassName && item.cellClassName[tdItem.key]
|
||||
? item.cellClassName[tdItem.key]
|
||||
: '',
|
||||
spanMethod(item, tdItem, index, tdItemIndex)[
|
||||
'rowspan'
|
||||
] == 0
|
||||
? 'empty-cells-for-rowspan'
|
||||
: '',
|
||||
spanMethod(item, tdItem, index, tdItemIndex)[
|
||||
'colspan'
|
||||
] == 0
|
||||
? 'empty-cells-for-celspan'
|
||||
: '',
|
||||
spanMethod(item, tdItem, index, tdItemIndex)[
|
||||
'rowspan'
|
||||
] > 1
|
||||
? 'rowspan'
|
||||
: '',
|
||||
spanMethod(item, tdItem, index, tdItemIndex)[
|
||||
'colspan'
|
||||
] > 1
|
||||
? 'colspan'
|
||||
: '',
|
||||
]"
|
||||
:style="{
|
||||
height: countRowspanHeight(
|
||||
item,
|
||||
tdItem,
|
||||
index,
|
||||
tdItemIndex
|
||||
),
|
||||
width: countColspanWidth(
|
||||
item,
|
||||
tdItem,
|
||||
index,
|
||||
tdItemIndex
|
||||
),
|
||||
}"
|
||||
:key="tdItem.key"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{
|
||||
height: countRowspanHeight(
|
||||
item,
|
||||
tdItem,
|
||||
index,
|
||||
tdItemIndex
|
||||
),
|
||||
width: countColspanWidth(
|
||||
item,
|
||||
tdItem,
|
||||
index,
|
||||
tdItemIndex,
|
||||
true
|
||||
),
|
||||
}"
|
||||
>
|
||||
<slot
|
||||
:row="item"
|
||||
:index="index"
|
||||
:col="tdItem"
|
||||
:isRead="isRead"
|
||||
v-if="slotCols.indexOf(tdItem.key) > -1"
|
||||
></slot>
|
||||
<template v-else-if="tdItem.$operateList">
|
||||
<template v-for="btn in tdItem.$operateList">
|
||||
<button
|
||||
:class="[btn.styles ? btn.styles : '']"
|
||||
v-bind:style="{
|
||||
padding: '2px 5px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '1.2',
|
||||
display: 'inline-block',
|
||||
}"
|
||||
@click="
|
||||
pullEvent(btn.event, {
|
||||
row: item,
|
||||
index: index,
|
||||
})
|
||||
"
|
||||
type="primary"
|
||||
size="min"
|
||||
:key="btn.id"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>{{ item[tdItem.key] }} </template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else>
|
||||
<view
|
||||
class="table_tbody_box empty-data-body-box div-table-body"
|
||||
:style="{ height: emptyColHeight, width: emptyColWidth }"
|
||||
>
|
||||
<view
|
||||
class="tr"
|
||||
:style="{ height: emptyColHeight, width: emptyColWidth }"
|
||||
>
|
||||
<view
|
||||
class="td"
|
||||
:style="{ height: emptyColHeight, width: emptyColWidth }"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{
|
||||
height: parseInt(emptyColHeight - 2) + 'px',
|
||||
width: emptyColWidth,
|
||||
lineHeight: parseInt(emptyColHeight - 2) + 'px',
|
||||
}"
|
||||
>
|
||||
<text @click="emptyClickCallBack">{{ emptyText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-if="list.length">
|
||||
<!-- 固定左边一列 【-->
|
||||
<view
|
||||
class="fixed-left"
|
||||
v-if="
|
||||
columnsFixedLeft[0] || (selection == 'mulit' && fixedCheckbox)
|
||||
"
|
||||
>
|
||||
<view class="tr fixed-thead-tr">
|
||||
<!-- 多选且固定左边 【-->
|
||||
<view
|
||||
class="td selection"
|
||||
v-if="selection == 'mulit' && fixedCheckbox"
|
||||
:style="{ width: selectionTdWidth, height: thTdHeight + 'px' }"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{
|
||||
width: selectionTdWidth,
|
||||
height: thTdHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<checkbox-group @change="checkboxChangeAll">
|
||||
<checkbox
|
||||
value="all"
|
||||
color="#999"
|
||||
:checked="switchAllCheckBox"
|
||||
style="transform: scale(0.7)"
|
||||
/>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 多选且固定左边 】-->
|
||||
<!-- 普通固定左边 【-->
|
||||
<view
|
||||
class="td"
|
||||
v-if="columnsFixedLeft[0]"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft),
|
||||
}"
|
||||
>
|
||||
<view
|
||||
class="td_wrap"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft),
|
||||
}"
|
||||
>
|
||||
{{ columnsFixedLeft[0].title }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 普通固定左边 】-->
|
||||
</view>
|
||||
<view
|
||||
v-for="(item, index) in list"
|
||||
:key="item.id"
|
||||
:class="[
|
||||
'tr',
|
||||
selection == 'single' && checkBoxList[index].$checked
|
||||
? 'selected'
|
||||
: '',
|
||||
selection == 'single' && checkBoxList[index].$disabled
|
||||
? 'disabled'
|
||||
: '',
|
||||
]"
|
||||
@click="selectRow(item, index)"
|
||||
>
|
||||
<!-- 多选且固定左边 】-->
|
||||
<view
|
||||
class="td selection fixed-td"
|
||||
v-if="selection == 'mulit' && fixedCheckbox"
|
||||
:style="{ width: selectionTdWidth, height: tdHeight + 'px' }"
|
||||
>
|
||||
<view
|
||||
:class="['td_wrap']"
|
||||
:style="{ width: selectionTdWidth, height: tdHeight + 'px' }"
|
||||
>
|
||||
<checkbox
|
||||
:value="checkBoxList[index].id"
|
||||
color="#999"
|
||||
:disabled="checkBoxList[index].$disabled"
|
||||
:checked="checkBoxList[index].$checked"
|
||||
style="transform: scale(0.7)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 普通固定左边 【-->
|
||||
<view
|
||||
class="td fixed-td"
|
||||
v-if="columnsFixedLeft[0]"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft),
|
||||
}"
|
||||
>
|
||||
<view
|
||||
class="td_wrap fixed-wrap"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft[0]),
|
||||
}"
|
||||
>
|
||||
<!-- td内容 【-->
|
||||
<slot
|
||||
:row="item"
|
||||
v-if="
|
||||
slotCols.indexOf(
|
||||
columnsFixedLeft[0] && columnsFixedLeft[0].key
|
||||
) > -1
|
||||
"
|
||||
></slot>
|
||||
<template v-if="columnsFixedLeft[0].$operateList">
|
||||
<template v-for="btn in columnsFixedLeft[0].$operateList">
|
||||
<button
|
||||
:class="[btn.styles ? btn.styles : '']"
|
||||
v-bind:style="{
|
||||
padding: '2px 5px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '1.2',
|
||||
display: 'inline-block',
|
||||
}"
|
||||
@click="
|
||||
pullEvent(btn.event, { row: item, index: index })
|
||||
"
|
||||
type="primary"
|
||||
size="min"
|
||||
:key="btn.id"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else
|
||||
>{{ item[columnsFixedLeft[0].key] }}
|
||||
</template>
|
||||
<!-- td内容 】-->
|
||||
</view>
|
||||
</view>
|
||||
<!-- 普通固定左边 】-->
|
||||
</view>
|
||||
</view>
|
||||
<!-- 固定左边一列 】-->
|
||||
<!-- 固定右边一列 【-->
|
||||
<view class="fixed-right" v-if="columnsFixedRight[0]">
|
||||
<view class="tr fixed-thead-tr">
|
||||
<view
|
||||
class="td"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft),
|
||||
}"
|
||||
>
|
||||
<view
|
||||
class="td_wrap"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedLeft[0]),
|
||||
width: fixedWidth(columnsFixedLeft),
|
||||
}"
|
||||
>
|
||||
{{ columnsFixedRight[0].title }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-for="(item, index) in list"
|
||||
:key="item.id"
|
||||
:class="[
|
||||
'tr',
|
||||
selection == 'single' && checkBoxList[index].$checked
|
||||
? 'selected'
|
||||
: '',
|
||||
selection == 'single' && checkBoxList[index].$disabled
|
||||
? 'disabled'
|
||||
: '',
|
||||
]"
|
||||
@click="selectRow(item, index)"
|
||||
>
|
||||
<view
|
||||
class="td fixed-td"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedRight[0]),
|
||||
width: fixedWidth(columnsFixedRight[0]),
|
||||
}"
|
||||
>
|
||||
<view
|
||||
class="td_wrap fixed-wrap"
|
||||
:style="{
|
||||
height: fixedHeight(columnsFixedRight[0]),
|
||||
width: fixedWidth(columnsFixedRight[0]),
|
||||
}"
|
||||
>
|
||||
<!-- td内容 【-->
|
||||
<slot
|
||||
:row="item"
|
||||
v-if="
|
||||
slotCols.indexOf(
|
||||
columnsFixedRight[0] && columnsFixedRight[0].key
|
||||
) > -1
|
||||
"
|
||||
></slot>
|
||||
<template
|
||||
v-if="
|
||||
columnsFixedRight[0] && columnsFixedRight[0].$operateList
|
||||
"
|
||||
>
|
||||
<template v-for="btn in columnsFixedRight[0].$operateList">
|
||||
<button
|
||||
:class="[btn.styles ? btn.styles : '']"
|
||||
v-bind:style="{
|
||||
padding: '2px 5px',
|
||||
fontSize: '12px',
|
||||
lineHeight: '1.2',
|
||||
display: 'inline-block',
|
||||
}"
|
||||
@click="
|
||||
pullEvent(btn.event, { row: item, index: index })
|
||||
"
|
||||
type="primary"
|
||||
size="min"
|
||||
:key="btn.id"
|
||||
>
|
||||
{{ btn.label }}
|
||||
</button>
|
||||
</template>
|
||||
</template>
|
||||
<template v-else
|
||||
>{{ item[columnsFixedRight[0].key] }}
|
||||
</template>
|
||||
<!-- td内容 】-->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 固定右边一列 】-->
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
<loading-component v-if="loading" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import loadingComponent from "./loading.vue";
|
||||
export default {
|
||||
components: { loadingComponent },
|
||||
props: {
|
||||
//显示列
|
||||
columns: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
//数据
|
||||
list: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
//单元格样式居中
|
||||
"cel-center": {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
//自定义行和列样式
|
||||
rowClassName: {
|
||||
type: [String, Function],
|
||||
default: "",
|
||||
},
|
||||
//自定义列元素
|
||||
"slot-cols": {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
//行列合并函数
|
||||
"span-method": {
|
||||
type: Function,
|
||||
default: () => {
|
||||
return () => {
|
||||
return {
|
||||
rowspan: 1,
|
||||
colspan: 1,
|
||||
};
|
||||
};
|
||||
},
|
||||
},
|
||||
spanArr: {
|
||||
type: Array,
|
||||
default: [],
|
||||
},
|
||||
isRead: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
//是否可选 mulit=>多选 single=》单选
|
||||
selection: {
|
||||
type: String,
|
||||
default: "none",
|
||||
},
|
||||
"fixed-checkbox": {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: undefined,
|
||||
},
|
||||
"td-width": {
|
||||
type: Number,
|
||||
default: 110,
|
||||
},
|
||||
"td-height": {
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
"th-td-height": {
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
"td-padding": {
|
||||
type: Number,
|
||||
default: 10,
|
||||
},
|
||||
"border-color": {
|
||||
type: String,
|
||||
default: "#666",
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: "数据为空",
|
||||
},
|
||||
//空提示点击事件
|
||||
emptyClickFn: {
|
||||
type: Function,
|
||||
default() {
|
||||
return () => {};
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
columnsFixedRight() {
|
||||
let t = this.columns.filter((item) => item.$fixed == "right");
|
||||
return t.length ? [t[0]] : [];
|
||||
},
|
||||
columnsFixedLeft() {
|
||||
let t = this.columns.filter((item) => item.$fixed == "left");
|
||||
return t.length ? [t[0]] : [];
|
||||
},
|
||||
//表格高度
|
||||
tableHeight() {
|
||||
return Number(this.height) && Number(this.height) > this.tdHeight * 3
|
||||
? this.height + "px"
|
||||
: "auto";
|
||||
},
|
||||
//表格主体高度
|
||||
talbeBodyHeight() {
|
||||
let t =
|
||||
this.tableHeight !== "auto"
|
||||
? parseInt(this.tableHeight) - this.tdHeight - 3 + "px"
|
||||
: "auto";
|
||||
return t;
|
||||
},
|
||||
//可选的列表长度
|
||||
allCheckBoxAbledLen() {
|
||||
return this.checkBoxList.filter((item) => !item.$disabled).length;
|
||||
},
|
||||
//没数据时候主体高度
|
||||
emptyColHeight() {
|
||||
let t = this.height ? this.height - this.thTdHeight - 30 + "px" : "100px";
|
||||
// console.log("emptyColHeight",this.height, this.thTdHeight,t)
|
||||
return t;
|
||||
},
|
||||
//没数据时候,主体的宽度
|
||||
emptyColWidth() {
|
||||
let t = this.tdWidth * this.columns.length;
|
||||
if (this.selection == "mulit") {
|
||||
t = parseInt(this.selectionTdWidth) + t;
|
||||
}
|
||||
return t + "px";
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
checkBoxList: [], //多选=》选中列表
|
||||
switchAllCheckBox: false, //多选=》全选
|
||||
selectionTdWidth: "750rpx", //多选列宽
|
||||
singleSelect: {}, //单选,选中行
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
list() {
|
||||
this.asyncCheckBoxList();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.asyncCheckBoxList();
|
||||
},
|
||||
methods: {
|
||||
//获取数据副本,轻拷贝
|
||||
asyncCheckBoxList() {
|
||||
this.checkBoxList = this.list.map((item) => {
|
||||
return { ...item };
|
||||
});
|
||||
},
|
||||
//自定义行样式
|
||||
rowClassNamePlus(row, index) {
|
||||
if (typeof this.rowClassName === "string") {
|
||||
return this.rowClassName;
|
||||
} else if (typeof this.rowClassName === "function") {
|
||||
return this.rowClassName(row, index);
|
||||
}
|
||||
},
|
||||
//事件触发
|
||||
pullEvent(event, data) {
|
||||
this.$emit(event, data);
|
||||
},
|
||||
/**
|
||||
* 计算单列宽
|
||||
* iswrap 是否是内容容器
|
||||
*/
|
||||
countColspanWidth(item, tdItem, index, tdItemIndex, iswrap = false) {
|
||||
let borderLeft = iswrap && tdItemIndex > 0 ? 1 : 0;
|
||||
//是否跨列,返回跨列个数,1为不跨列
|
||||
let moreThanOne =
|
||||
this.spanMethod(item, tdItem, index, tdItemIndex) &&
|
||||
this.spanMethod(item, tdItem, index, tdItemIndex)["colspan"];
|
||||
//console.log(`第${index}行,第${tdItemIndex}列 是跨列么?${moreThanOne}`);
|
||||
let t =
|
||||
moreThanOne > 1
|
||||
? moreThanOne * this.tdWidth - borderLeft + "px"
|
||||
: this.tdWidth - borderLeft + "px";
|
||||
//跨列
|
||||
if (moreThanOne > 1) {
|
||||
let countWidth = 0;
|
||||
for (let i = tdItemIndex; i < tdItemIndex + (moreThanOne - 1); i++) {
|
||||
countWidth +=
|
||||
this.columns[i].$width && parseInt(this.columns[i].$width)
|
||||
? parseInt(moreThanOne * this.columns[i].$width) - borderLeft
|
||||
: this.tdWidth * moreThanOne;
|
||||
}
|
||||
return countWidth + "px";
|
||||
} else {
|
||||
//不跨列
|
||||
let tmp =
|
||||
this.columns[tdItemIndex].width &&
|
||||
parseInt(this.columns[tdItemIndex].width)
|
||||
? parseInt(this.columns[tdItemIndex].width)
|
||||
: this.tdWidth;
|
||||
return tmp + "rpx";
|
||||
}
|
||||
return t;
|
||||
},
|
||||
/**
|
||||
* 固定列宽
|
||||
*/
|
||||
fixedWidth(fixedWidth) {
|
||||
return fixedWidth && fixedWidth.$width
|
||||
? fixedWidth + "px"
|
||||
: this.tdWidth + "px";
|
||||
},
|
||||
/*
|
||||
* 固定列-》列高
|
||||
*/
|
||||
fixedHeight(fixedHeight) {
|
||||
return fixedHeight && fixedHeight.$height
|
||||
? fixedHeight + "px"
|
||||
: this.tdHeight + "px";
|
||||
},
|
||||
|
||||
/**
|
||||
* 计算头部td的宽度
|
||||
* */
|
||||
countHeadColspanWidth(item, index, iswrap = false) {
|
||||
let borderLeft = iswrap && index > 0 ? 1 : 0;
|
||||
let tmp = item.width ? parseInt(item.width) : this.tdWidth;
|
||||
return tmp + "rpx";
|
||||
},
|
||||
/**
|
||||
* 计算单列高
|
||||
* */
|
||||
countRowspanHeight(item, tdItem, index, tdItemIndex) {
|
||||
//是否跨行
|
||||
let moreThanOne =
|
||||
this.spanMethod(item, tdItem, index, tdItemIndex) &&
|
||||
this.spanMethod(item, tdItem, index, tdItemIndex)["rowspan"] > 1;
|
||||
let t = moreThanOne
|
||||
? this.spanMethod(item, tdItem, index, tdItemIndex)["rowspan"] *
|
||||
this.tdHeight +
|
||||
"px"
|
||||
: this.tdHeight + "px";
|
||||
return t;
|
||||
},
|
||||
/*
|
||||
* 单选行
|
||||
* */
|
||||
selectRow(item, index) {
|
||||
if (item.$disabled) {
|
||||
return;
|
||||
}
|
||||
//非单选方式
|
||||
if (this.selection != "single") {
|
||||
return;
|
||||
}
|
||||
this.checkBoxList = this.checkBoxList.map((sitem, sindex) => {
|
||||
if (index === sindex) {
|
||||
sitem.$checked = true;
|
||||
} else {
|
||||
sitem.$checked = false;
|
||||
}
|
||||
return sitem;
|
||||
});
|
||||
if (this.selection) {
|
||||
this.$emit("on-selection-change", {
|
||||
old: this.singleSelect,
|
||||
new: {
|
||||
index,
|
||||
item,
|
||||
},
|
||||
});
|
||||
}
|
||||
this.singleSelect = {
|
||||
index,
|
||||
item,
|
||||
};
|
||||
},
|
||||
/*
|
||||
* 多选
|
||||
* */
|
||||
checkboxChange(e) {
|
||||
let val = e.detail.value;
|
||||
let before = [];
|
||||
for (let v = 0; v < this.allCheckBoxAbledLen; v++) {
|
||||
if (this.checkBoxList[v].$checked === true) {
|
||||
before.push({ ...this.checkBoxList[v] });
|
||||
}
|
||||
}
|
||||
if (val.length == this.allCheckBoxAbledLen) {
|
||||
this.switchAllCheckBox = true;
|
||||
this.checkBoxList = this.checkBoxList.map((item) => {
|
||||
if (!item.$disabled) {
|
||||
item.$checked = true;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
this.switchAllCheckBox = false;
|
||||
this.checkBoxList = this.checkBoxList.map((item) => {
|
||||
if (val.indexOf(item.id) > -1) {
|
||||
item.$checked = true;
|
||||
} else {
|
||||
item.$checked = false;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
this.$emit("on-selection-change", {
|
||||
old: before,
|
||||
new: this.checkBoxList.filter((item) => item.$checked === true),
|
||||
});
|
||||
},
|
||||
/*
|
||||
* 全选
|
||||
* */
|
||||
checkboxChangeAll(e) {
|
||||
let val = e.detail.value;
|
||||
let before = [];
|
||||
for (let v = 0; v < this.allCheckBoxAbledLen; v++) {
|
||||
if (this.checkBoxList[v].$checked === true) {
|
||||
before.push({ ...this.checkBoxList[v] });
|
||||
}
|
||||
}
|
||||
if (val && val[0] == "all") {
|
||||
this.switchAllCheckBox = true;
|
||||
this.checkBoxList = this.checkBoxList.map((item) => {
|
||||
if (!item.$disabled) {
|
||||
item.$checked = true;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
} else {
|
||||
this.switchAllCheckBox = false;
|
||||
this.checkBoxList = this.checkBoxList.map((item) => {
|
||||
item.$checked = false;
|
||||
return item;
|
||||
});
|
||||
}
|
||||
this.$emit("on-selection-change", {
|
||||
old: before,
|
||||
new: this.checkBoxList.filter((item) => item.$checked === true),
|
||||
});
|
||||
},
|
||||
/*
|
||||
* 空提示点击事件
|
||||
* */
|
||||
emptyClickCallBack() {
|
||||
typeof this.emptyClickFn == "function" ? this.emptyClickFn() : "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "components/no-bad-table/table.scss";
|
||||
</style>
|
||||
163
components/tabBar/tabBar.vue
Normal file
163
components/tabBar/tabBar.vue
Normal file
@@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-tabbar
|
||||
:value="current"
|
||||
@change="tabbarChange"
|
||||
z-index="999"
|
||||
activeColor="#2F6D47"
|
||||
inactiveColor="#687379"
|
||||
:fixed="true"
|
||||
:placeholder="true"
|
||||
:safeAreaInsetBottom="true"
|
||||
>
|
||||
<u-tabbar-item name="index" text="首页" v-if="!_isGjt">
|
||||
<u-icon
|
||||
name="home-fill"
|
||||
size="45"
|
||||
slot="active-icon"
|
||||
color="#2F6D47"
|
||||
></u-icon>
|
||||
<u-icon
|
||||
name="home-fill"
|
||||
size="45"
|
||||
slot="inactive-icon"
|
||||
color="#687379"
|
||||
></u-icon>
|
||||
</u-tabbar-item>
|
||||
<u-tabbar-item name="map" text="地图" v-if="_isShowMap">
|
||||
<u-icon
|
||||
name="map-fill"
|
||||
size="45"
|
||||
slot="active-icon"
|
||||
color="#2F6D47"
|
||||
></u-icon>
|
||||
<u-icon
|
||||
name="map-fill"
|
||||
size="45"
|
||||
slot="inactive-icon"
|
||||
color="#687379"
|
||||
></u-icon>
|
||||
</u-tabbar-item>
|
||||
<u-tabbar-item name="my" text="我的">
|
||||
<u-icon
|
||||
name="account-fill"
|
||||
size="45"
|
||||
slot="active-icon"
|
||||
color="#2F6D47"
|
||||
></u-icon>
|
||||
<u-icon
|
||||
name="account-fill"
|
||||
size="45"
|
||||
slot="inactive-icon"
|
||||
color="#687379"
|
||||
></u-icon>
|
||||
</u-tabbar-item>
|
||||
</u-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUser } from "@/utils/auth.js";
|
||||
import { checkButtonPermission } from "@/utils/permission.js";
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: "shared", // 解除样式隔离
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// userInfo: {}, // 用户信息
|
||||
// list: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
current() {
|
||||
return this.$store.state.current || "index";
|
||||
},
|
||||
_userInfo() {
|
||||
console.log("---------------------");
|
||||
console.log(getUser());
|
||||
return getUser() || {};
|
||||
},
|
||||
_isGjt() {
|
||||
console.log(123123123);
|
||||
console.log(this._userInfo.id);
|
||||
return this._userInfo.id == "1131365259079106560";
|
||||
},
|
||||
_isShowMap() {
|
||||
return checkButtonPermission(
|
||||
"weappMap",
|
||||
"vehicle" //按钮在基础信息菜单的车辆信息下面
|
||||
);
|
||||
// const ids = this._userInfo?.roles?.map((item) => item.roleName) || [];
|
||||
// if (ids.includes("地图查看")) {
|
||||
// // if (ids.includes("1120244873740435456")) ID切库会变 改成中文吧
|
||||
// return true; //统一改成地图查看权限配置
|
||||
// } else {
|
||||
// return false; //其他
|
||||
// }
|
||||
},
|
||||
// _list() {
|
||||
// return this._isShowMap
|
||||
// ? [
|
||||
// {
|
||||
// path: "pages/index/index",
|
||||
// },
|
||||
// {
|
||||
// path: "pages/map/index",
|
||||
// },
|
||||
// {
|
||||
// path: "pages/my/my",
|
||||
// },
|
||||
// ]
|
||||
// : [
|
||||
// {
|
||||
// path: "pages/index/index",
|
||||
// },
|
||||
// {
|
||||
// path: "pages/my/my",
|
||||
// },
|
||||
// ];
|
||||
// },
|
||||
},
|
||||
// watch: {
|
||||
// _userInfo: {
|
||||
// handler(newVal) {
|
||||
// this.userInfo = newVal;
|
||||
// },
|
||||
// immediate: true,
|
||||
// deep: true,
|
||||
// },
|
||||
// },
|
||||
mounted() {
|
||||
console.log("tabBar mounted");
|
||||
console.log(this._userInfo);
|
||||
},
|
||||
methods: {
|
||||
tabbarChange(e) {
|
||||
console.log(e);
|
||||
this.$store.state.current = e;
|
||||
let arr = [
|
||||
{
|
||||
name: "index",
|
||||
path: "pages/index/index",
|
||||
},
|
||||
{
|
||||
name: "map",
|
||||
path: "pages/map/index",
|
||||
},
|
||||
{
|
||||
name: "my",
|
||||
path: "pages/my/my",
|
||||
},
|
||||
];
|
||||
let path =
|
||||
arr.find((item) => item.name == e)?.path || "pages/index/index";
|
||||
uni.switchTab({
|
||||
url: "/" + path,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
153
components/upload_img_video.vue
Normal file
153
components/upload_img_video.vue
Normal file
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-upload :accept="accept" :fileList="imgList" @afterRead="afterRead" @delete="deletePic" :name="paramsName"
|
||||
:multiple="isMultiple" :maxCount="limit" ref="upload">
|
||||
<u-button v-if="isBtn" plain type="primary" text="上传" size="mini" icon="arrow-upward" class="btn-icon"
|
||||
style="border: 1px solid #c2d10a;" iconColor="#c2d10a" color="#c2d10a"></u-button>
|
||||
<view v-else class="u-upload__button" :hover-class="!disabled ? 'u-upload__button--hover' : ''"
|
||||
hover-stay-time="150" :class="[disabled && 'u-upload__button--disabled']" :style="[{
|
||||
width: $u.addUnit(80),
|
||||
height: $u.addUnit(80)
|
||||
}]" style="background-color: aliceblue;display: flex;align-items: center;justify-content: center;">
|
||||
<u-icon name="camera-fill" size="26" color="#D3D4D6"></u-icon>
|
||||
</view>
|
||||
</u-upload>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: 'shared', // 解除样式隔离
|
||||
},
|
||||
name: "upload_img_video",
|
||||
props: {
|
||||
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
isMultiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
isBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
accept: {
|
||||
type: String,
|
||||
default: "image"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
paramsName: {
|
||||
type: String,
|
||||
default: "file"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imgList: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 删除图片
|
||||
deletePic(event) {
|
||||
this.imgList.splice(event.index, 1)
|
||||
this.$emit('successFile', this.imgList);
|
||||
},
|
||||
// 新增图片
|
||||
async afterRead(event) {
|
||||
const that = this;
|
||||
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = this.imgList.length
|
||||
lists.map((item) => {
|
||||
that.imgList.push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中'
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await this.uploadFilePromise(lists[i].url)
|
||||
let item = this.imgList[fileListLen]
|
||||
that.imgList.splice(fileListLen, 1, Object.assign(item, {
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result.data.url,
|
||||
name: result.data.fileName
|
||||
}))
|
||||
fileListLen++
|
||||
}
|
||||
this.$emit('successFile', this.imgList);
|
||||
},
|
||||
uploadFilePromise(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let a = uni.uploadFile({
|
||||
url: '/attachment/upload', // 仅为示例,非真实的接口地址
|
||||
filePath: url,
|
||||
name: this.paramsName,
|
||||
success: (res) => {
|
||||
resolve(JSON.parse(res.data || {}))
|
||||
},
|
||||
fail: (e) => {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
/deep/.btn-icon {
|
||||
font-size: 10rpx !important;
|
||||
height: 58rpx !important;
|
||||
|
||||
/deep/.u-icon {
|
||||
/deep/.u-icon__icon--primary {
|
||||
font-size: 20rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/deep/.u-button--mini {
|
||||
width: 120rpx !important;
|
||||
|
||||
.u-icon {
|
||||
font-size: 20rpx !important;
|
||||
|
||||
.u-icon__icon {
|
||||
font-size: 20rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
height: 58rpx !important;
|
||||
}
|
||||
|
||||
/deep/.u-upload__deletable {
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
|
||||
.uicon-close {
|
||||
font-size: 14px !important;
|
||||
line-height: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/deep/.u-upload__success {
|
||||
border-bottom-color: #c2d10a !important;
|
||||
border-right-color: #c2d10a !important;
|
||||
|
||||
.uicon-checkmark {
|
||||
font-size: 14px !important;
|
||||
line-height: 14px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user