mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-02-06 17:15:54 +08:00
commit message
This commit is contained in:
18
seller/src/views/my-components/lili/circle-loading.vue
Normal file
18
seller/src/views/my-components/lili/circle-loading.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div style="display: inline-block;">
|
||||
<Icon type="ios-loading" size="18" color="#2d8cf0" class="spin-icon-load"></Icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "circleLoading"
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.spin-icon-load {
|
||||
animation: ani-demo-spin 1s linear infinite;
|
||||
}
|
||||
</style>
|
||||
|
||||
247
seller/src/views/my-components/lili/editor.vue
Normal file
247
seller/src/views/my-components/lili/editor.vue
Normal file
@@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="position: relative">
|
||||
<div :id="id" style="text-align: left; min-width: 1080px"></div>
|
||||
<div v-if="showExpand">
|
||||
<div class="e-menu e-code" @click="editHTML">
|
||||
<Icon type="md-code-working" size="22" />
|
||||
</div>
|
||||
<div class="e-menu e-preview" @click="fullscreenModal = true">
|
||||
<Icon type="ios-eye" size="24" />
|
||||
</div>
|
||||
<div class="e-menu e-trash" @click="clear">
|
||||
<Icon type="md-trash" size="18" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
title="编辑html代码"
|
||||
v-model="showHTMLModal"
|
||||
:mask-closable="false"
|
||||
:width="900"
|
||||
:fullscreen="full"
|
||||
>
|
||||
<Input
|
||||
v-if="!full"
|
||||
v-model="dataEdit"
|
||||
:rows="15"
|
||||
type="textarea"
|
||||
style="max-height: 60vh; overflow: auto"
|
||||
/>
|
||||
<Input v-if="full" v-model="dataEdit" :rows="32" type="textarea" />
|
||||
<div slot="footer">
|
||||
<Button @click="full = !full" icon="md-expand">全屏开/关</Button>
|
||||
<Button
|
||||
@click="editHTMLOk"
|
||||
type="primary"
|
||||
icon="md-checkmark-circle-outline"
|
||||
>确定保存</Button
|
||||
>
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal title="预览" v-model="fullscreenModal" fullscreen>
|
||||
<div v-html="data">{{ data }}</div>
|
||||
<div slot="footer">
|
||||
<Button @click="fullscreenModal = false">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uploadFile } from "@/api/index";
|
||||
import E from "wangeditor";
|
||||
import xss from "xss";
|
||||
// 表情包配置 自定义表情可在该js文件中统一修改
|
||||
import { sina } from "@/libs/emoji";
|
||||
export default {
|
||||
name: "editor",
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: "editor",
|
||||
},
|
||||
value: String,
|
||||
base64: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showExpand: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
openXss: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null, // 初始化富文本编辑器
|
||||
data: this.value, // 富文本数据
|
||||
dataEdit: "", // 编辑数据
|
||||
showHTMLModal: false, // 显示html
|
||||
full: false, // html全屏开关
|
||||
fullscreenModal: false, // 显示全屏预览
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
initEditor() {
|
||||
let that = this;
|
||||
this.editor = new E(`#${this.id}`);
|
||||
|
||||
// 编辑内容绑定数据
|
||||
this.editor.config.onchange = (html) => {
|
||||
if (this.openXss) {
|
||||
this.data = xss(html);
|
||||
} else {
|
||||
this.data = html;
|
||||
}
|
||||
this.$emit("input", this.data);
|
||||
this.$emit("on-change", this.data);
|
||||
};
|
||||
this.editor.config.showFullScreen = false;
|
||||
// z-index
|
||||
this.editor.config.zIndex = 100;
|
||||
if (this.base64) {
|
||||
// 使用 base64 保存图片
|
||||
this.editor.config.uploadImgShowBase64 = true;
|
||||
} else {
|
||||
// 配置上传图片服务器端地址
|
||||
this.editor.config.uploadImgServer = uploadFile;
|
||||
// lili如要header中传入token鉴权
|
||||
this.editor.config.uploadImgHeaders = {
|
||||
accessToken: that.getStore("accessToken"),
|
||||
};
|
||||
this.editor.config.uploadFileName = "file";
|
||||
this.editor.config.uploadImgHooks = {
|
||||
before: function (xhr, editor, files) {
|
||||
// 图片上传之前触发
|
||||
},
|
||||
success: function (xhr, editor, result) {
|
||||
// 图片上传并返回结果,图片插入成功之后触发
|
||||
},
|
||||
fail: function (xhr, editor, result) {
|
||||
// 图片上传并返回结果,但图片插入错误时触发
|
||||
that.$Message.error("上传图片失败");
|
||||
},
|
||||
error: function (xhr, editor) {
|
||||
// 图片上传出错时触发
|
||||
that.$Message.error("上传图片出错");
|
||||
},
|
||||
timeout: function (xhr, editor) {
|
||||
// 图片上传超时时触发
|
||||
that.$Message.error("上传图片超时");
|
||||
},
|
||||
// 如果服务器端返回的不是 {errno:0, data: [...]} 这种格式,可使用该配置
|
||||
customInsert: function (insertImg, result, editor) {
|
||||
if (result.success == true) {
|
||||
let url = result.result;
|
||||
insertImg(url);
|
||||
that.$Message.success("上传图片成功");
|
||||
} else {
|
||||
that.$Message.error(result.message);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
this.editor.config.customAlert = function (info) {
|
||||
// info 是需要提示的内容
|
||||
// that.$Message.info(info);
|
||||
};
|
||||
// 字体
|
||||
this.editor.config.fontNames = ["微软雅黑", "宋体", "黑体", "Arial"];
|
||||
// 表情面板可以有多个 tab ,因此要配置成一个数组。数组每个元素代表一个 tab 的配置
|
||||
this.editor.config.emotions = [
|
||||
{
|
||||
// tab 的标题
|
||||
title: "新浪",
|
||||
// type -> 'emoji' / 'image'
|
||||
type: "image",
|
||||
// content -> 数组
|
||||
content: sina,
|
||||
},
|
||||
];
|
||||
if (this.value) {
|
||||
if (this.openXss) {
|
||||
this.editor.txt.html(xss(this.value));
|
||||
} else {
|
||||
this.editor.txt.html(this.value);
|
||||
}
|
||||
}
|
||||
this.editor.create();
|
||||
},
|
||||
editHTML() {
|
||||
this.dataEdit = this.data;
|
||||
this.showHTMLModal = true;
|
||||
},
|
||||
editHTMLOk() {
|
||||
this.editor.txt.html(this.dataEdit);
|
||||
this.$emit("input", this.data);
|
||||
this.$emit("on-change", this.data);
|
||||
this.showHTMLModal = false;
|
||||
},
|
||||
clear() {
|
||||
this.$Modal.confirm({
|
||||
title: "确认清空",
|
||||
content: "确认要清空编辑器内容?清空后不能撤回",
|
||||
onOk: () => {
|
||||
this.data = "";
|
||||
this.editor.txt.html(this.data);
|
||||
this.$emit("input", this.data);
|
||||
this.$emit("on-change", this.data);
|
||||
},
|
||||
});
|
||||
},
|
||||
setData(value) {
|
||||
if (!this.editor) {
|
||||
this.initEditor();
|
||||
}
|
||||
if (value && value != this.data) {
|
||||
this.data = value;
|
||||
this.editor.txt.html(this.data);
|
||||
this.$emit("input", this.data);
|
||||
this.$emit("on-change", this.data);
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler: function (val) {
|
||||
|
||||
this.setData(val);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initEditor();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.e-menu {
|
||||
z-index: 101;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #999;
|
||||
:hover {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
.e-code {
|
||||
top: 6px;
|
||||
left: 976px;
|
||||
}
|
||||
.e-preview {
|
||||
top: 6px;
|
||||
left: 1014px;
|
||||
}
|
||||
.e-trash {
|
||||
top: 4px;
|
||||
left: 1047px;
|
||||
}
|
||||
</style>
|
||||
|
||||
166
seller/src/views/my-components/lili/set-password.vue
Normal file
166
seller/src/views/my-components/lili/set-password.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="set-password">
|
||||
<Poptip transfer trigger="focus" placement="right" width="250">
|
||||
<Input
|
||||
type="password"
|
||||
password
|
||||
style="width:350px;"
|
||||
:maxlength="maxlength"
|
||||
v-model="currentValue"
|
||||
@on-change="handleChange"
|
||||
:size="size"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
/>
|
||||
<div :class="tipStyle" slot="content">
|
||||
<div class="words">强度 : {{strength}}</div>
|
||||
<Progress
|
||||
:percent="strengthValue"
|
||||
:status="progressStatus"
|
||||
hide-info
|
||||
style="margin: 13px 0;"
|
||||
/>
|
||||
<br />请至少输入 6 个字符。请不要使
|
||||
<br />用容易被猜到的密码。
|
||||
</div>
|
||||
</Poptip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "setPassword",
|
||||
props: {
|
||||
value: String,
|
||||
size: String,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请输入密码,长度为6-20个字符"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: 20
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentValue: this.value, // 当前密码
|
||||
tipStyle: "password-tip-none", // 提示样式
|
||||
strengthValue: 0, // 密码强度
|
||||
progressStatus: "normal", // 进度条状态
|
||||
strength: "无", // 密码长度
|
||||
grade: 0 // 强度等级
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
checkStrengthValue(v) {
|
||||
// 评级制判断密码强度 最高5
|
||||
let grade = 0;
|
||||
if (/\d/.test(v)) {
|
||||
grade++; //数字
|
||||
}
|
||||
if (/[a-z]/.test(v)) {
|
||||
grade++; //小写
|
||||
}
|
||||
if (/[A-Z]/.test(v)) {
|
||||
grade++; //大写
|
||||
}
|
||||
if (/\W/.test(v)) {
|
||||
grade++; //特殊字符
|
||||
}
|
||||
if (v.length >= 10) {
|
||||
grade++;
|
||||
}
|
||||
this.grade = grade;
|
||||
return grade;
|
||||
},
|
||||
strengthChange() {
|
||||
if (!this.currentValue) {
|
||||
this.tipStyle = "password-tip-none";
|
||||
this.strength = "无";
|
||||
this.strengthValue = 0;
|
||||
return;
|
||||
}
|
||||
let grade = this.checkStrengthValue(this.currentValue);
|
||||
if (grade <= 1) {
|
||||
this.progressStatus = "wrong";
|
||||
this.tipStyle = "password-tip-weak";
|
||||
this.strength = "弱";
|
||||
this.strengthValue = 33;
|
||||
} else if (grade >= 2 && grade <= 4) {
|
||||
this.progressStatus = "normal";
|
||||
this.tipStyle = "password-tip-middle";
|
||||
this.strength = "中";
|
||||
this.strengthValue = 66;
|
||||
} else {
|
||||
this.progressStatus = "success";
|
||||
this.tipStyle = "password-tip-strong";
|
||||
this.strength = "强";
|
||||
this.strengthValue = 100;
|
||||
}
|
||||
},
|
||||
handleChange(v) {
|
||||
this.strengthChange();
|
||||
this.$emit("input", this.currentValue);
|
||||
this.$emit("on-change", this.currentValue, this.grade, this.strength);
|
||||
},
|
||||
setCurrentValue(value) {
|
||||
if (value === this.currentValue) {
|
||||
return;
|
||||
}
|
||||
this.currentValue = value;
|
||||
this.strengthChange();
|
||||
this.$emit("on-change", this.currentValue, this.grade, this.strength);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.setCurrentValue(val);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.set-password .ivu-poptip,
|
||||
.set-password .ivu-poptip-rel {
|
||||
display: block;
|
||||
}
|
||||
.password-tip-none {
|
||||
padding: 1vh 0;
|
||||
}
|
||||
|
||||
.password-tip-weak {
|
||||
padding: 1vh 0;
|
||||
|
||||
.words {
|
||||
color: #ed3f14;
|
||||
}
|
||||
}
|
||||
|
||||
.password-tip-middle {
|
||||
padding: 1vh 0;
|
||||
|
||||
.words {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
}
|
||||
|
||||
.password-tip-strong {
|
||||
padding: 1vh 0;
|
||||
|
||||
.words {
|
||||
color: #52c41a;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
172
seller/src/views/my-components/lili/upload-pic-input.vue
Normal file
172
seller/src/views/my-components/lili/upload-pic-input.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<div>
|
||||
<div style="display:flex;">
|
||||
<Input
|
||||
v-model="currentValue"
|
||||
@on-change="handleChange"
|
||||
v-show="showInput"
|
||||
:placeholder="placeholder"
|
||||
:size="size"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:maxlength="maxlength"
|
||||
>
|
||||
<Button slot="append" icon="md-eye"></Button>
|
||||
</Input>
|
||||
<Poptip transfer trigger="hover" title="图片预览" placement="right" width="350">
|
||||
<Icon type="md-eye" class="see-icon" />
|
||||
<div slot="content">
|
||||
<img :src="currentValue" alt="该资源不存在" style="width: 100%;margin: 0 auto;display: block;" />
|
||||
<a @click="viewImage=true" style="margin-top:5px;text-align:right;display:block">查看大图</a>
|
||||
</div>
|
||||
</Poptip>
|
||||
<Upload
|
||||
:action="uploadFileUrl"
|
||||
:headers="accessToken"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:format="['jpg','jpeg','png','gif','bmp']"
|
||||
accept=".jpg, .jpeg, .png, .gif, .bmp"
|
||||
:max-size="maxSize*1024"
|
||||
:on-format-error="handleFormatError"
|
||||
:on-exceeded-size="handleMaxSize"
|
||||
:before-upload="beforeUpload"
|
||||
:show-upload-list="false"
|
||||
ref="up"
|
||||
class="upload"
|
||||
>
|
||||
<Button :loading="loading" :size="size" :disabled="disabled" :icon="icon">上传图片</Button>
|
||||
</Upload>
|
||||
</div>
|
||||
|
||||
<Modal title="图片预览" v-model="viewImage" :styles="{top: '30px'}" draggable>
|
||||
<img :src="currentValue" alt="该资源不存在" style="width: 100%;margin: 0 auto;display: block;" />
|
||||
<div slot="footer">
|
||||
<Button @click="viewImage=false">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uploadFile } from "@/api/index";
|
||||
export default {
|
||||
name: "uploadPicInput",
|
||||
props: {
|
||||
value: String,
|
||||
size: String,
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "图片链接"
|
||||
},
|
||||
showInput: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
maxlength: Number,
|
||||
icon: {
|
||||
type: String,
|
||||
default: "ios-cloud-upload-outline"
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accessToken: {}, // 验证token
|
||||
currentValue: this.value, // 当前值
|
||||
loading: false, // 加载状态
|
||||
viewImage: false, // 是否预览图片
|
||||
uploadFileUrl: uploadFile // 上传列表
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.accessToken = {
|
||||
accessToken: this.getStore("accessToken")
|
||||
};
|
||||
},
|
||||
handleFormatError(file) {
|
||||
this.loading = false;
|
||||
this.$Notice.warning({
|
||||
title: "不支持的文件格式",
|
||||
desc:
|
||||
"所选文件‘ " +
|
||||
file.name +
|
||||
" ’格式不正确, 请选择 .jpg .jpeg .png .gif .bmp格式文件"
|
||||
});
|
||||
},
|
||||
handleMaxSize(file) {
|
||||
this.loading = false;
|
||||
this.$Notice.warning({
|
||||
title: "文件大小过大",
|
||||
desc: "所选文件‘ " + file.name + " ’大小过大, 不得超过 " + this.maxSize + "M."
|
||||
});
|
||||
},
|
||||
beforeUpload() {
|
||||
this.loading = true;
|
||||
return true;
|
||||
},
|
||||
handleSuccess(res, file) {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
this.currentValue = res.result;
|
||||
this.$emit("input", this.currentValue);
|
||||
this.$emit("on-change", this.currentValue);
|
||||
} else {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
},
|
||||
handleError(error, file, fileList) {
|
||||
this.loading = false;
|
||||
this.$Message.error(error.toString());
|
||||
},
|
||||
handleChange(v) {
|
||||
this.$emit("input", this.currentValue);
|
||||
this.$emit("on-change", this.currentValue);
|
||||
this.$attrs.rollback && this.$attrs.rollback()
|
||||
},
|
||||
setCurrentValue(value) {
|
||||
if (value === this.currentValue) {
|
||||
return;
|
||||
}
|
||||
this.currentValue = value;
|
||||
this.$emit("on-change", this.currentValue);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.setCurrentValue(val);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.see-icon {
|
||||
font-size: 16px;
|
||||
margin-left: -32px;
|
||||
margin-top: 3px;
|
||||
padding: 7px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.upload {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
296
seller/src/views/my-components/lili/upload-pic-thumb.vue
Normal file
296
seller/src/views/my-components/lili/upload-pic-thumb.vue
Normal file
@@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<div>
|
||||
<vuedraggable
|
||||
:list="uploadList"
|
||||
:disabled="!draggable||!multiple"
|
||||
:animation="200"
|
||||
class="list-group"
|
||||
ghost-class="thumb-ghost"
|
||||
@end="onEnd"
|
||||
>
|
||||
<div class="upload-list" v-for="(item, index) in uploadList" :key="index">
|
||||
<div v-if="item.status == 'finished'">
|
||||
<img :src="item.url" />
|
||||
<div class="upload-list-cover">
|
||||
<Icon type="ios-eye-outline" @click="handleView(item.url)"></Icon>
|
||||
<Icon v-if="remove" type="ios-trash-outline" @click="handleRemove(item)"></Icon>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<Progress v-if="item.showProgress" :percent="item.percentage" hide-info></Progress>
|
||||
</div>
|
||||
</div>
|
||||
</vuedraggable>
|
||||
<Upload
|
||||
:disabled="disable"
|
||||
ref="upload"
|
||||
:multiple="multiple"
|
||||
:show-upload-list="false"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
:format="['jpg','jpeg','png','gif']"
|
||||
:max-size="maxSize*1024"
|
||||
:on-format-error="handleFormatError"
|
||||
:on-exceeded-size="handleMaxSize"
|
||||
:before-upload="handleBeforeUpload"
|
||||
type="drag"
|
||||
:action="uploadFileUrl"
|
||||
:headers="accessToken"
|
||||
style="display: inline-block;width:58px;"
|
||||
>
|
||||
<div style="width: 58px;height:58px;line-height: 58px;">
|
||||
<Icon type="md-camera" size="20"></Icon>
|
||||
</div>
|
||||
</Upload>
|
||||
|
||||
<Modal title="图片预览" v-model="viewImage" :styles="{top: '30px'}" draggable>
|
||||
<img :src="imgUrl" alt="无效的图片链接" style="width: 100%;margin: 0 auto;display: block;" />
|
||||
<div slot="footer">
|
||||
<Button @click="viewImage=false">关闭</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uploadFile } from "@/api/index";
|
||||
import vuedraggable from "vuedraggable";
|
||||
export default {
|
||||
name: "uploadPicThumb",
|
||||
components: {
|
||||
vuedraggable
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: Object
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
disable:{
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
remove:{
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 10
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accessToken: {}, // 验证token
|
||||
uploadFileUrl: uploadFile, // 上传文件
|
||||
uploadList: [], // 上传文件列表
|
||||
viewImage: false, // 是否预览图片
|
||||
imgUrl: "" // 图片地址
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onEnd() {
|
||||
this.returnValue();
|
||||
},
|
||||
init() {
|
||||
this.setData(this.value, true);
|
||||
this.accessToken = {
|
||||
accessToken: this.getStore("accessToken")
|
||||
};
|
||||
},
|
||||
handleView(imgUrl) {
|
||||
this.imgUrl = imgUrl;
|
||||
this.viewImage = true;
|
||||
},
|
||||
handleRemove(file) {
|
||||
const uploadList = this.uploadList;
|
||||
this.uploadList.splice(uploadList.indexOf(file), 1);
|
||||
this.returnValue();
|
||||
},
|
||||
handleSuccess(res, file) {
|
||||
if (res.success) {
|
||||
file.url = res.result;
|
||||
// 单张图片处理
|
||||
if (!this.multiple && this.uploadList.length > 0) {
|
||||
// 删除第一张
|
||||
this.uploadList.splice(0, 1);
|
||||
}
|
||||
this.uploadList.push(file);
|
||||
// 返回组件值
|
||||
this.returnValue();
|
||||
} else {
|
||||
this.$Message.error(res.message);
|
||||
}
|
||||
},
|
||||
handleError(error, file, fileList) {
|
||||
this.$Message.error(error.toString());
|
||||
},
|
||||
handleFormatError(file) {
|
||||
this.$Notice.warning({
|
||||
title: "不支持的文件格式",
|
||||
desc:
|
||||
"所选文件‘ " +
|
||||
file.name +
|
||||
" ’格式不正确, 请选择 .jpg .jpeg .png .gif图片格式文件"
|
||||
});
|
||||
},
|
||||
handleMaxSize(file) {
|
||||
this.$Notice.warning({
|
||||
title: "文件大小过大",
|
||||
desc:
|
||||
"所选文件‘ " +
|
||||
file.name +
|
||||
" ’大小过大, 不得超过 " +
|
||||
this.maxSize +
|
||||
"M."
|
||||
});
|
||||
},
|
||||
handleBeforeUpload() {
|
||||
if (this.multiple && this.uploadList.length >= this.limit) {
|
||||
this.$Message.warning("最多只能上传" + this.limit + "张图片");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
returnValue() {
|
||||
if (!this.uploadList || this.uploadList.length < 1) {
|
||||
if (!this.multiple) {
|
||||
this.$emit("input", "");
|
||||
this.$emit("on-change", "");
|
||||
} else {
|
||||
this.$emit("input", []);
|
||||
this.$emit("on-change", []);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.multiple) {
|
||||
// 单张
|
||||
let v = this.uploadList[0].url;
|
||||
this.$emit("input", v);
|
||||
this.$emit("on-change", v);
|
||||
} else {
|
||||
let v = [];
|
||||
this.uploadList.forEach(e => {
|
||||
v.push(e.url);
|
||||
});
|
||||
this.$emit("input", v);
|
||||
this.$emit("on-change", v);
|
||||
}
|
||||
},
|
||||
setData(v, init) {
|
||||
if (typeof v == "string") {
|
||||
// 单张
|
||||
if (this.multiple) {
|
||||
this.$Message.warning("多张上传仅支持数组数据类型");
|
||||
return;
|
||||
}
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
this.uploadList = [];
|
||||
let item = {
|
||||
url: v,
|
||||
status: "finished"
|
||||
};
|
||||
this.uploadList.push(item);
|
||||
this.$emit("on-change", v);
|
||||
} else if (typeof v == "object") {
|
||||
// 多张
|
||||
if (!this.multiple) {
|
||||
this.$Message.warning("单张上传仅支持字符串数据类型");
|
||||
return;
|
||||
}
|
||||
this.uploadList = [];
|
||||
if (v.length > this.limit) {
|
||||
for (let i = 0; i < this.limit; i++) {
|
||||
let item = {
|
||||
url: v[i],
|
||||
status: "finished"
|
||||
};
|
||||
this.uploadList.push(item);
|
||||
}
|
||||
this.$emit("on-change", v.slice(0, this.limit));
|
||||
if (init) {
|
||||
this.$emit("input", v.slice(0, this.limit));
|
||||
}
|
||||
this.$Message.warning("最多只能上传" + this.limit + "张图片");
|
||||
} else {
|
||||
v.forEach(e => {
|
||||
let item = {
|
||||
url: e,
|
||||
status: "finished"
|
||||
};
|
||||
this.uploadList.push(item);
|
||||
});
|
||||
this.$emit("on-change", v);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.setData(val);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.upload-list {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
text-align: center;
|
||||
line-height: 60px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
position: relative;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||
margin-right: 5px;
|
||||
}
|
||||
.upload-list img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.upload-list-cover {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
.upload-list:hover .upload-list-cover {
|
||||
display: block;
|
||||
}
|
||||
.upload-list-cover i {
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
margin: 0 2px;
|
||||
}
|
||||
.list-group {
|
||||
display: inline-block;
|
||||
}
|
||||
.thumb-ghost {
|
||||
opacity: 0.5;
|
||||
background: #c8ebfb;
|
||||
}
|
||||
</style>
|
||||
|
||||
183
seller/src/views/my-components/map/index.vue
Normal file
183
seller/src/views/my-components/map/index.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div class="map">
|
||||
<Modal
|
||||
v-model="showMap"
|
||||
title="选择地址"
|
||||
width="800"
|
||||
>
|
||||
<div class="address">{{addrContent.address}}</div>
|
||||
<div id="map-container"></div>
|
||||
|
||||
<div class="search-con">
|
||||
<Input placeholder="输入关键字搜索" id="input-map" v-model="mapSearch"/>
|
||||
<ul>
|
||||
<li v-for="(tip, index) in tips" :key="index" @click="selectAddr(tip.location)">
|
||||
<p>{{tip.name}}</p>
|
||||
<p>{{tip.district + tip.address}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<Button type="default" @click="showMap = false">取消</Button>
|
||||
<Button type="primary" :loading="loading" @click="ok">确定</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import AMapLoader from '@amap/amap-jsapi-loader';
|
||||
import {getRegion} from '@/api/common.js'
|
||||
export default {
|
||||
name:'map',
|
||||
data() {
|
||||
return {
|
||||
showMap:false, // 地图显隐
|
||||
mapSearch:'', // 地图搜索
|
||||
map:null, // 初始化地图
|
||||
autoComplete:null, // 初始化搜索方法
|
||||
geocoder:null, // 初始化地理、坐标转化
|
||||
positionPicker:null, // 地图拖拽选点
|
||||
tips:[], //搜索关键字列表
|
||||
addrContent:{}, // 回显地址信息
|
||||
loading:false, // 加载状态
|
||||
};
|
||||
},
|
||||
watch:{
|
||||
mapSearch:function(val){
|
||||
this.searchOfMap(val)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ok(){ // 确定选择
|
||||
|
||||
this.loading = true
|
||||
|
||||
const codeObj = {}
|
||||
const params = {
|
||||
cityCode: this.addrContent.regeocode.addressComponent.citycode,
|
||||
townName: this.addrContent.regeocode.addressComponent.township
|
||||
}
|
||||
getRegion(params).then(res=>{
|
||||
if(res.code == 200) {
|
||||
this.addrContent.addr = res.result.name.replace(/,/g," ")
|
||||
this.addrContent.addrId = res.result.id
|
||||
this.loading = false
|
||||
this.showMap = false;
|
||||
this.$emit('getAddress',this.addrContent);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
init() {
|
||||
AMapLoader.load({
|
||||
key: "b440952723253aa9fe483e698057bf7d", // 申请好的Web端开发者Key,首次调用 load 时必填
|
||||
version: "", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
|
||||
plugins: [
|
||||
"AMap.ToolBar",
|
||||
"AMap.Autocomplete",
|
||||
"AMap.PlaceSearch",
|
||||
"AMap.Geolocation",
|
||||
'AMap.Geocoder'
|
||||
], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
|
||||
"AMapUI": { // 是否加载 AMapUI,缺省不加载
|
||||
"version": '1.1', // AMapUI 缺省 1.1
|
||||
"plugins":['misc/PositionPicker'], // 需要加载的 AMapUI ui插件
|
||||
},
|
||||
})
|
||||
.then((AMap) => {
|
||||
let that = this;
|
||||
this.map = new AMap.Map("map-container",{
|
||||
zoom:12
|
||||
});
|
||||
that.map.addControl(new AMap.ToolBar());
|
||||
that.map.addControl(new AMap.Autocomplete());
|
||||
that.map.addControl(new AMap.PlaceSearch());
|
||||
that.map.addControl(new AMap.Geocoder());
|
||||
|
||||
// 实例化Autocomplete
|
||||
let autoOptions = {
|
||||
city: "全国"
|
||||
};
|
||||
that.autoComplete = new AMap.Autocomplete(autoOptions); // 搜索
|
||||
that.geocoder = new AMap.Geocoder(autoOptions)
|
||||
|
||||
|
||||
that.positionPicker = new AMapUI.PositionPicker({ // 拖拽选点
|
||||
mode: 'dragMap',
|
||||
map:that.map
|
||||
});
|
||||
that.positionPicker.start()
|
||||
/**
|
||||
*
|
||||
* 所有回显数据,都在positionResult里面
|
||||
* 需要字段可以查找
|
||||
*
|
||||
*/
|
||||
that.positionPicker.on('success', function(positionResult) {
|
||||
that.addrContent = positionResult;
|
||||
});
|
||||
|
||||
})
|
||||
.catch((e) => {});
|
||||
},
|
||||
searchOfMap(val) { // 地图搜索
|
||||
let that = this;
|
||||
this.autoComplete.search(val, function (status, result) {
|
||||
// 搜索成功时,result即是对应的匹配数据
|
||||
if(status == 'complete' && result.info == 'OK'){
|
||||
that.tips = result.tips;
|
||||
}else {
|
||||
that.tips = []
|
||||
}
|
||||
});
|
||||
},
|
||||
selectAddr(location) { // 选择坐标
|
||||
if(!location){
|
||||
this.$Message.warning('请选择正确点位')
|
||||
return false;
|
||||
}
|
||||
const lnglat = [location.lng,location.lat]
|
||||
this.positionPicker.start(lnglat)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
#map-container{
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.search-con{
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 64px;
|
||||
width: 260px;
|
||||
ul{
|
||||
width: 260px;
|
||||
height: 400px;
|
||||
overflow: scroll;
|
||||
li{
|
||||
padding: 5px;
|
||||
p:nth-child(2){
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
&:hover{
|
||||
background-color:#eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address{
|
||||
margin-bottom: 10px;
|
||||
// color: $theme_color;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
117
seller/src/views/my-components/tree-table/Checkbox/Checkbox.less
Normal file
117
seller/src/views/my-components/tree-table/Checkbox/Checkbox.less
Normal file
@@ -0,0 +1,117 @@
|
||||
// text
|
||||
@prefixCls: zk-checkbox;
|
||||
// color
|
||||
@border: #dddee1;
|
||||
@hoverBorder: #bcbcbc;
|
||||
@blue: #2d8cf0;
|
||||
|
||||
.@{prefixCls}-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.@{prefixCls} {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @hoverBorder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__inner {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 1px solid @border;
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
transition: border-color .2s ease-in-out,background-color .2s ease-in-out;
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 4px;
|
||||
border: 2px solid #fff;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
transform: rotate(45deg) scale(0);
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--indeterminate {
|
||||
.@{prefixCls}__inner {
|
||||
background-color: @blue;
|
||||
border-color: @blue;
|
||||
&::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 1px;
|
||||
transform: scale(1);
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--checked {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
background-color: @blue;
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 4px;
|
||||
border: 2px solid #ffffff;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
transform: rotate(45deg) scale(1);
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--disabled {
|
||||
cursor: not-allowed;
|
||||
.@{prefixCls}__inner {
|
||||
background-color: #f3f3f3;
|
||||
border-color: @border;
|
||||
&::after {
|
||||
animation-name: none;
|
||||
border-color: #ccc;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @border;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<template lang="html">
|
||||
<label :class="`${prefixCls}-wrapper`">
|
||||
<span :class="checkboxClass">
|
||||
<span
|
||||
:class="`${prefixCls}__inner`"
|
||||
@click="toggle"></span>
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'zk-checkbox',
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
prefixCls: 'zk-checkbox',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
checkboxClass() {
|
||||
return [
|
||||
`${this.prefixCls}`,
|
||||
{
|
||||
[`${this.prefixCls}--disabled`]: this.disabled,
|
||||
[`${this.prefixCls}--checked`]: this.value,
|
||||
[`${this.prefixCls}--indeterminate`]: this.indeterminate,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
if (this.disabled) {
|
||||
return false;
|
||||
}
|
||||
const value = !this.value;
|
||||
this.$emit('input', value);
|
||||
return this.$emit('on-change', value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" src="./Checkbox.less"></style>
|
||||
170
seller/src/views/my-components/tree-table/Table/Table.less
Normal file
170
seller/src/views/my-components/tree-table/Table/Table.less
Normal file
@@ -0,0 +1,170 @@
|
||||
@import "./font/iconfont";
|
||||
|
||||
// text
|
||||
@prefixCls: zk-table;
|
||||
// color
|
||||
@black: #515a6e;
|
||||
@white: #ffffff;
|
||||
@border: #e9eaec;
|
||||
@hoverRow: #ebf7ff;
|
||||
@backgroundRow: #f8f8f9;
|
||||
|
||||
.@{prefixCls} {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: @white;
|
||||
border: 1px solid @border;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
color: @black;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-cell {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.@{prefixCls}__cell-inner {
|
||||
padding: 0px 18px;
|
||||
}
|
||||
|
||||
.@{prefixCls}-default {
|
||||
font-size: 14px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 48px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}-small {
|
||||
font-size: 12px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 36px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}-large {
|
||||
font-size: 16px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 43px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 60px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-wrapper,
|
||||
.@{prefixCls}__footer-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header,
|
||||
.@{prefixCls}__body,
|
||||
.@{prefixCls}__footer {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
background-color: @backgroundRow;
|
||||
border-bottom: 1px solid @border;
|
||||
}
|
||||
|
||||
.@{prefixCls}__footer-row {
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
background-color: @white;
|
||||
border-top: 1px solid @border;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 48px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:not(:first-of-type) {
|
||||
border-top: 1px solid @border;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-cell,
|
||||
.@{prefixCls}__body-cell,
|
||||
.@{prefixCls}__footer-cell {
|
||||
box-sizing: border-box;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}--firstProp-header-inner {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.@{prefixCls}--empty-row {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.@{prefixCls}--empty-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.@{prefixCls}--center-cell {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.@{prefixCls}--right-cell {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.@{prefixCls}--stripe-row {
|
||||
background-color: @backgroundRow;
|
||||
}
|
||||
|
||||
.@{prefixCls}--row-hover {
|
||||
background-color: @hoverRow;
|
||||
}
|
||||
|
||||
.@{prefixCls}--border-cell {
|
||||
&:not(:last-of-type) {
|
||||
border-right: 1px solid @border;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--tree-icon {
|
||||
margin-right: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.@{prefixCls}--expand-inner {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: transform .2s ease-in-out;
|
||||
}
|
||||
|
||||
.@{prefixCls}--expanded-inner {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.@{prefixCls}--expand-content {
|
||||
padding: 20px;
|
||||
}
|
||||
396
seller/src/views/my-components/tree-table/Table/Table.vue
Normal file
396
seller/src/views/my-components/tree-table/Table/Table.vue
Normal file
@@ -0,0 +1,396 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
v-if="columns.length > 0"
|
||||
ref="table"
|
||||
:class="[prefixCls, `${prefixCls}-${size}`, tableClass]">
|
||||
<Spin fix v-if="loading"></Spin>
|
||||
<div
|
||||
v-show="showHeader"
|
||||
ref="header-wrapper"
|
||||
:class="`${prefixCls}__header-wrapper`"
|
||||
@mousewheel="handleEvent('header', $event)">
|
||||
<table-header
|
||||
ref="table-header">
|
||||
</table-header>
|
||||
</div>
|
||||
<div
|
||||
ref="body-wrapper"
|
||||
:style="bodyWrapperStyle"
|
||||
:class="`${prefixCls}__body-wrapper`"
|
||||
@scroll="handleEvent('body', $event)">
|
||||
<table-body
|
||||
ref="table-body"
|
||||
:class="bodyClass">
|
||||
</table-body>
|
||||
</div>
|
||||
<div
|
||||
v-show="showSummary && data.length > 0"
|
||||
ref="footer-wrapper"
|
||||
:class="`${prefixCls}__footer-wrapper`"
|
||||
@mousewheel="handleEvent('footer', $event)">
|
||||
<table-footer
|
||||
ref="table-footer">
|
||||
</table-footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TableHeader from "./TableHeader";
|
||||
import TableBody from "./TableBody";
|
||||
import TableFooter from "./TableFooter";
|
||||
import { mixins, scrollBarWidth as getSbw } from "./utils";
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
// function getBodyData(data, isTreeType, childrenProp, isFold, level = 1) {
|
||||
function getBodyData(
|
||||
primaryKey,
|
||||
oldBodyData,
|
||||
data,
|
||||
isTreeType,
|
||||
childrenProp,
|
||||
isFold,
|
||||
parentFold,
|
||||
level = 1
|
||||
) {
|
||||
let bodyData = [];
|
||||
data.forEach((row, index) => {
|
||||
const children = row[childrenProp];
|
||||
const childrenLen =
|
||||
Object.prototype.toString.call(children).slice(8, -1) === "Array"
|
||||
? children.length
|
||||
: 0;
|
||||
let curIsFold = isFold;
|
||||
if (
|
||||
isFold &&
|
||||
typeof primaryKey === "string" &&
|
||||
Array.isArray(oldBodyData)
|
||||
) {
|
||||
for (let i = 0; i < oldBodyData.length; i++) {
|
||||
const oldRow = oldBodyData[i];
|
||||
if (oldRow[primaryKey] === row[primaryKey]) {
|
||||
if ("_isFold" in oldRow) {
|
||||
curIsFold = oldRow._isFold;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bodyData.push({
|
||||
_isHover: false,
|
||||
_isExpanded: false,
|
||||
_isChecked: false,
|
||||
_level: level,
|
||||
// _isHide: isFold ? level !== 1 : false,
|
||||
// _isFold: isFold,
|
||||
_isHide: level !== 1 ? isFold && parentFold : false,
|
||||
_isFold: isFold && curIsFold,
|
||||
_childrenLen: childrenLen,
|
||||
_normalIndex: index + 1,
|
||||
...row
|
||||
});
|
||||
if (isTreeType) {
|
||||
if (childrenLen > 0) {
|
||||
// bodyData = bodyData.concat(getBodyData(children, true, childrenProp, isFold, level + 1));
|
||||
bodyData = bodyData.concat(
|
||||
getBodyData(
|
||||
primaryKey,
|
||||
oldBodyData,
|
||||
children,
|
||||
true,
|
||||
childrenProp,
|
||||
isFold,
|
||||
curIsFold,
|
||||
level + 1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return bodyData;
|
||||
}
|
||||
|
||||
function initialState(table, expandKey) {
|
||||
return {
|
||||
bodyHeight: "auto",
|
||||
firstProp: expandKey || (table.columns[0] && table.columns[0].key),
|
||||
// bodyData: getBodyData(table.data, table.treeType, table.childrenProp, table.isFold),
|
||||
bodyData: getBodyData(
|
||||
table.primaryKey,
|
||||
table.bodyData,
|
||||
table.data,
|
||||
table.treeType,
|
||||
table.childrenProp,
|
||||
table.isFold,
|
||||
false
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function initialColumns(table, clientWidth) {
|
||||
let columnsWidth = 0;
|
||||
const minWidthColumns = [];
|
||||
const otherColumns = [];
|
||||
const columns = table.columns.concat();
|
||||
if (table.expandType) {
|
||||
columns.unshift({
|
||||
width: "50"
|
||||
});
|
||||
}
|
||||
if (table.selectable) {
|
||||
columns.unshift({
|
||||
width: "50"
|
||||
});
|
||||
}
|
||||
if (table.showIndex) {
|
||||
columns.unshift({
|
||||
width: "50px",
|
||||
key: "_normalIndex",
|
||||
title: table.indexText
|
||||
});
|
||||
}
|
||||
columns.forEach((column, index) => {
|
||||
let width = "";
|
||||
let minWidth = "";
|
||||
if (!column.width) {
|
||||
if (column.minWidth) {
|
||||
minWidth =
|
||||
typeof column.minWidth === "number"
|
||||
? column.minWidth
|
||||
: parseInt(column.minWidth, 10);
|
||||
} else {
|
||||
minWidth = 80;
|
||||
}
|
||||
minWidthColumns.push({
|
||||
...column,
|
||||
minWidth,
|
||||
_index: index
|
||||
});
|
||||
} else {
|
||||
width =
|
||||
typeof column.width === "number"
|
||||
? column.width
|
||||
: parseInt(column.width, 10);
|
||||
otherColumns.push({
|
||||
...column,
|
||||
width,
|
||||
_index: index
|
||||
});
|
||||
}
|
||||
columnsWidth += minWidth || width;
|
||||
});
|
||||
const scrollBarWidth = getSbw();
|
||||
const totalWidth = columnsWidth + scrollBarWidth;
|
||||
const isScrollX = totalWidth > clientWidth;
|
||||
if (!isScrollX) {
|
||||
const extraWidth = clientWidth - totalWidth;
|
||||
const averageExtraWidth = Math.floor(extraWidth / minWidthColumns.length);
|
||||
minWidthColumns.forEach(column => {
|
||||
column.computedWidth = column.minWidth + averageExtraWidth;
|
||||
});
|
||||
}
|
||||
const tableColumns = otherColumns.concat(minWidthColumns);
|
||||
tableColumns.sort((a, b) => a._index - b._index);
|
||||
return tableColumns;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "TreeTable",
|
||||
mixins: [mixins],
|
||||
components: {
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
size: {
|
||||
default() {
|
||||
return !this.$IVIEW || this.$IVIEW.size === ""
|
||||
? "default"
|
||||
: this.$IVIEW.size;
|
||||
}
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxHeight: {
|
||||
type: [String, Number],
|
||||
default: "auto"
|
||||
},
|
||||
stripe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
treeType: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
childrenProp: {
|
||||
type: String,
|
||||
default: "children"
|
||||
},
|
||||
isFold: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
expandType: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selectable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: "checkbox"
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: "暂无数据"
|
||||
},
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showIndex: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
indexText: {
|
||||
type: String,
|
||||
default: "#"
|
||||
},
|
||||
showSummary: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sumText: {
|
||||
type: String,
|
||||
default: "合计"
|
||||
},
|
||||
primaryKey: String,
|
||||
summaryMethod: Function,
|
||||
showRowHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
rowKey: Function,
|
||||
rowClassName: [String, Function],
|
||||
cellClassName: [String, Function],
|
||||
rowStyle: [Object, Function],
|
||||
cellStyle: [Object, Function],
|
||||
expandKey: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedWidth: "",
|
||||
computedHeight: "",
|
||||
tableColumns: [],
|
||||
...initialState(this, this.expandKey)
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
bodyWrapperStyle() {
|
||||
return {
|
||||
height: this.bodyHeight
|
||||
};
|
||||
},
|
||||
tableClass() {
|
||||
return {
|
||||
[`${this.prefixCls}--border`]: this.border
|
||||
};
|
||||
},
|
||||
bodyClass() {
|
||||
return {
|
||||
[`${this.prefixCls}--stripe`]: this.stripe
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleEvent(type, $event) {
|
||||
this.validateType(type, ["header", "body", "footer"], "handleEvent");
|
||||
const eventType = $event.type;
|
||||
if (eventType === "scroll") {
|
||||
this.$refs["header-wrapper"].scrollLeft = $event.target.scrollLeft;
|
||||
this.$refs["footer-wrapper"].scrollLeft = $event.target.scrollLeft;
|
||||
}
|
||||
if (eventType === "mousewheel") {
|
||||
const deltaX = $event.deltaX;
|
||||
const $body = this.$refs["body-wrapper"];
|
||||
if (deltaX > 0) {
|
||||
$body.scrollLeft += 10;
|
||||
} else {
|
||||
$body.scrollLeft -= 10;
|
||||
}
|
||||
}
|
||||
return this.$emit(`${type}-${eventType}`, $event);
|
||||
},
|
||||
// computedWidth, computedHeight, tableColumns
|
||||
measure() {
|
||||
this.$nextTick(() => {
|
||||
const { clientWidth, clientHeight } = this.$el;
|
||||
this.computedWidth = clientWidth + 2;
|
||||
this.computedHeight = clientHeight + 2;
|
||||
|
||||
const maxHeight = parseInt(this.maxHeight, 10);
|
||||
if (this.maxHeight !== "auto" && this.computedHeight > maxHeight) {
|
||||
this.bodyHeight = `${maxHeight - 83}px`;
|
||||
}
|
||||
this.tableColumns = initialColumns(this, clientWidth);
|
||||
});
|
||||
},
|
||||
getCheckedProp(key = "index") {
|
||||
if (!this.selectable) {
|
||||
return [];
|
||||
}
|
||||
const checkedIndexs = [];
|
||||
this.bodyData.forEach((item, index) => {
|
||||
if (item._isChecked) {
|
||||
if (key === "index") {
|
||||
checkedIndexs.push(index);
|
||||
} else {
|
||||
checkedIndexs.push(item[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return checkedIndexs;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$props: {
|
||||
deep: true,
|
||||
handler() {
|
||||
Object.assign(this.$data, initialState(this, this.expandKey));
|
||||
}
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
this.measure();
|
||||
},
|
||||
mounted() {
|
||||
this.measure();
|
||||
window.addEventListener("resize", this.measure);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("resize", this.measure);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" src="./Table.less"></style>
|
||||
327
seller/src/views/my-components/tree-table/Table/TableBody.js
Normal file
327
seller/src/views/my-components/tree-table/Table/TableBody.js
Normal file
@@ -0,0 +1,327 @@
|
||||
import Checkbox from '../Checkbox/Checkbox'; // eslint-disable-line
|
||||
// import Radio from '../Radio/Radio'; // eslint-disable-line
|
||||
import { mixins } from './utils';
|
||||
import { Radio } from 'view-design'; // eslint-disable-line
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: 'TreeTable__body',
|
||||
mixins: [mixins],
|
||||
components: { Radio },
|
||||
data() {
|
||||
return {
|
||||
radioSelectedIndex: -1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleStatus(type, row, rowIndex, value) {
|
||||
this.validateType(type, ['Expanded', 'Checked', 'Hide', 'Fold'], 'toggleStatus', false);
|
||||
const target = this.table.bodyData[rowIndex];
|
||||
this.table.bodyData.splice(rowIndex, 1, {
|
||||
...target,
|
||||
[`_is${type}`]: typeof value === 'undefined' ? !row[`_is${type}`] : value,
|
||||
});
|
||||
},
|
||||
getChildrenIndex(parentLevel, parentIndex, careFold = true) {
|
||||
const data = this.table.bodyData;
|
||||
let childrenIndex = [];
|
||||
for (let i = parentIndex + 1; i < data.length; i++) {
|
||||
if (data[i]._level <= parentLevel) break;
|
||||
if (data[i]._level - 1 === parentLevel) {
|
||||
childrenIndex.push(i);
|
||||
}
|
||||
}
|
||||
const len = childrenIndex.length; // important!!!
|
||||
if (len > 0) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const childData = data[childrenIndex[i]];
|
||||
if (
|
||||
childData._childrenLen &&
|
||||
(!careFold || (careFold && !childData._isFold))
|
||||
) {
|
||||
childrenIndex = childrenIndex.concat(
|
||||
this.getChildrenIndex(childData._level, childrenIndex[i], careFold));
|
||||
}
|
||||
}
|
||||
}
|
||||
return childrenIndex;
|
||||
},
|
||||
handleEvent($event, type, data, others) {
|
||||
const certainType = this.validateType(type, ['cell', 'row', 'checkbox', 'icon', 'radio'], 'handleEvent');
|
||||
const eventType = $event ? $event.type : '';
|
||||
const { row, rowIndex, column, columnIndex } = data;
|
||||
const latestData = this.table.bodyData;
|
||||
// Checkbox
|
||||
if (certainType.checkbox) {
|
||||
const { isChecked } = others;
|
||||
this.toggleStatus('Checked', row, rowIndex, isChecked);
|
||||
if (row._childrenLen > 0) {
|
||||
const childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
this.toggleStatus('Checked', latestData[childrenIndex[i]], childrenIndex[i], isChecked);
|
||||
}
|
||||
}
|
||||
return this.table.$emit('checkbox-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
// Radio
|
||||
if (certainType.radio) {
|
||||
this.radioSelectedIndex = rowIndex;
|
||||
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
|
||||
}
|
||||
// Tree's icon
|
||||
if (certainType.icon) {
|
||||
$event.stopPropagation();
|
||||
this.toggleStatus('Fold', row, rowIndex);
|
||||
const childrenIndex = this.getChildrenIndex(row._level, rowIndex);
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
this.toggleStatus('Hide', latestData[childrenIndex[i]], childrenIndex[i]);
|
||||
}
|
||||
return this.table.$emit('tree-icon-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
if (certainType.cell && eventType === 'click') {
|
||||
// 点击扩展单元格
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
this.toggleStatus('Expanded', row, rowIndex);
|
||||
return this.table.$emit('expand-cell-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
}
|
||||
// 行:Hover
|
||||
if (certainType.row && (eventType === 'mouseenter' || eventType === 'mouseleave')) {
|
||||
const { hover } = others;
|
||||
const target = latestData[rowIndex];
|
||||
latestData.splice(rowIndex, 1, {
|
||||
...target,
|
||||
_isHover: hover,
|
||||
});
|
||||
}
|
||||
if (certainType.row && others && others.clickRow && certainType.radio) {
|
||||
this.radioSelectedIndex = rowIndex;
|
||||
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
|
||||
}
|
||||
if (certainType.cell) {
|
||||
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, column, columnIndex, $event);
|
||||
}
|
||||
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, $event);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
// key
|
||||
// function getKey(row, rowIndex) {
|
||||
// const rowKey = this.table.rowKey;
|
||||
// if (rowKey) {
|
||||
// return rowKey.call(null, row, rowIndex);
|
||||
// }
|
||||
// return rowIndex;
|
||||
// }
|
||||
|
||||
// style
|
||||
function getStyle(type, row, rowIndex, column, columnIndex) {
|
||||
const certainType = this.validateType(type, ['cell', 'row'], 'getStyle');
|
||||
const style = this.table[`${type}Style`];
|
||||
if (typeof style === 'function') {
|
||||
if (certainType.row) {
|
||||
return style.call(null, row, rowIndex);
|
||||
}
|
||||
if (certainType.cell) {
|
||||
return style.call(null, row, rowIndex, column, columnIndex);
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
// className
|
||||
function getClassName(type, row, rowIndex, column, columnIndex) {
|
||||
const certainType = this.validateType(type, ['cell', 'row', 'inner'], 'getClassName');
|
||||
const classList = [];
|
||||
if (column && column.key == "_normalIndex") {
|
||||
classList.push(`${this.prefixCls}--center-cell`);
|
||||
}
|
||||
if (certainType.row || certainType.cell) {
|
||||
const className = this.table[`${type}ClassName`];
|
||||
if (typeof className === 'string') {
|
||||
classList.push(className);
|
||||
} else if (typeof className === 'function') {
|
||||
if (certainType.row) {
|
||||
classList.push(className.call(null, row, rowIndex) || '');
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(className.call(null, row, rowIndex, column, columnIndex) || '');
|
||||
}
|
||||
}
|
||||
if (certainType.row) {
|
||||
classList.push(`${this.prefixCls}__body-row`);
|
||||
if (this.table.stripe && rowIndex % 2 !== 0) {
|
||||
classList.push(`${this.prefixCls}--stripe-row`);
|
||||
}
|
||||
if (this.table.showRowHover && row._isHover) {
|
||||
classList.push(`${this.prefixCls}--row-hover`);
|
||||
}
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(`${this.prefixCls}__body-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
const align = column.align;
|
||||
if (['center', 'right'].indexOf(align) > -1) {
|
||||
classList.push(`${this.prefixCls}--${align}-cell`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (certainType.inner) {
|
||||
classList.push(`${this.prefixCls}__cell-inner`);
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
classList.push(`${this.prefixCls}--expand-inner`);
|
||||
if (row._isExpanded) {
|
||||
classList.push(`${this.prefixCls}--expanded-inner`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classList.join(' ');
|
||||
}
|
||||
|
||||
// 根据type渲染单元格Cell
|
||||
function renderCell(row, rowIndex, column, columnIndex) {
|
||||
// ExpandType
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
return <i class='zk-icon zk-icon-angle-right'></i>;
|
||||
}
|
||||
// SelectionType's Checkbox
|
||||
if (this.isSelectionCell(this.table, columnIndex)) {
|
||||
let res = null;
|
||||
if (this.table.selectType === 'checkbox') {
|
||||
let allCheck;
|
||||
let childrenIndex;
|
||||
const hasChildren = row._childrenLen > 0;
|
||||
if (hasChildren) {
|
||||
childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
|
||||
allCheck = true;
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
if (!this.table.bodyData[childrenIndex[i]]._isChecked) {
|
||||
allCheck = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allCheck = row._isChecked;
|
||||
}
|
||||
let indeterminate = false;
|
||||
if (hasChildren && !allCheck) {
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
if (this.table.bodyData[childrenIndex[i]]._isChecked) {
|
||||
indeterminate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// res = <Checkbox
|
||||
// indeterminate={indeterminate}
|
||||
// value={allCheck}
|
||||
// onOn-change={isChecked => this.handleEvent(null, 'checkbox', { row, rowIndex, column, columnIndex }, { isChecked })}>
|
||||
// </Checkbox>;
|
||||
} else {
|
||||
res = <Radio value={this.radioSelectedIndex === rowIndex} on-on-change={() => this.handleEvent(null, 'radio', { row, rowIndex, column, columnIndex })}></Radio>;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Tree's firstProp
|
||||
if (this.table.treeType && this.table.firstProp === column.key) {
|
||||
return <span
|
||||
class={`${this.prefixCls}--level-${row._level}-cell`}
|
||||
style={{
|
||||
marginLeft: `${(row._level - 1) * 24}px`,
|
||||
paddingLeft: row._childrenLen === 0 ? '20px' : '',
|
||||
}}>
|
||||
{row._childrenLen > 0 &&
|
||||
<i
|
||||
class={`${this.prefixCls}--tree-icon zk-icon zk-icon-${row._isFold ? 'plus' : 'minus'}-square-o`}
|
||||
on-click={$event => this.handleEvent($event, 'icon', { row, rowIndex, column, columnIndex }, { isFold: row._isFold })}></i>
|
||||
}
|
||||
{row[column.key] ? row[column.key] : ''}
|
||||
</span>;
|
||||
}
|
||||
// TreeType children's index
|
||||
if (this.table.showIndex && this.table.treeType && column.key === '_normalIndex' && row._level > 1) {
|
||||
return '';
|
||||
}
|
||||
if (column.type === undefined || column.type === 'custom') {
|
||||
return row[column.key];
|
||||
} else if (column.type === 'template') {
|
||||
return this.table.$scopedSlots[column.template]
|
||||
? this.table.$scopedSlots[column.template]({ row, rowIndex, column, columnIndex })
|
||||
: '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table cellspacing="0" cellpadding="0" border="0" class={`${this.prefixCls}__body`}>
|
||||
{/* <colgroup>
|
||||
{this.table.tableColumns.map(column =>
|
||||
<col width={column.computedWidth || column.minWidth || column.width}></col>)
|
||||
}
|
||||
</colgroup> */}
|
||||
<tbody>
|
||||
{ this.table.bodyData.length > 0
|
||||
? this.table.bodyData.map((row, rowIndex) =>
|
||||
[
|
||||
<tr
|
||||
v-show={!row._isHide}
|
||||
key={`table_row_${rowIndex}`}
|
||||
style={getStyle.call(this, 'row', row, rowIndex)}
|
||||
class={getClassName.call(this, 'row', row, rowIndex)}
|
||||
on-click={$event => this.handleEvent($event, 'row', { row, rowIndex }, { clickRow: true })}
|
||||
on-dblclick={$event => this.handleEvent($event, 'row', { row, rowIndex })}
|
||||
on-contextmenu={$event => this.handleEvent($event, 'row', { row, rowIndex })}
|
||||
on-mouseenter={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: true })}
|
||||
on-mouseleave={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: false })}>
|
||||
{ this.table.tableColumns.map((column, columnIndex) =>
|
||||
column.key ? <td
|
||||
style={getStyle.call(this, 'cell', row, rowIndex, column, columnIndex)}
|
||||
class={getClassName.call(this, 'cell', row, rowIndex, column, columnIndex)}
|
||||
on-click={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-dblclick={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-contextmenu={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-mouseenter={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-mouseleave={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}>
|
||||
<div class={getClassName.call(this, 'inner', row, rowIndex, column, columnIndex)}>
|
||||
{renderCell.call(this, row, rowIndex, column, columnIndex)}
|
||||
</div>
|
||||
</td>:"")
|
||||
}
|
||||
</tr>,
|
||||
this.table.expandType && row._isExpanded &&
|
||||
<tr
|
||||
key={rowIndex}
|
||||
class={`${this.prefixCls}__body-row ${this.prefixCls}--expand-row`}>
|
||||
<td
|
||||
class={`${this.prefixCls}--expand-content`}
|
||||
colspan={this.table.tableColumns.length}>
|
||||
{this.table.$scopedSlots.expand
|
||||
? this.table.$scopedSlots.expand({ row, rowIndex })
|
||||
: ''
|
||||
}
|
||||
</td>
|
||||
</tr>,
|
||||
])
|
||||
: <tr
|
||||
class={`${this.prefixCls}--empty-row`}>
|
||||
<td
|
||||
class={`${this.prefixCls}__body-cell ${this.prefixCls}--empty-content`}
|
||||
colspan={this.table.tableColumns.length}>
|
||||
{this.table.emptyText}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
import { mixins } from './utils';
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: 'TreeTable__footer',
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
render() {
|
||||
// 计算各列总和
|
||||
function renderCell({ key }, columnIndex) {
|
||||
if (columnIndex === 0) {
|
||||
return this.table.sumText;
|
||||
}
|
||||
const rows = this.table.bodyData;
|
||||
const values = rows.map(row => Number(row[key]));
|
||||
const precisions = [];
|
||||
let notNumber = true;
|
||||
values.forEach((value) => {
|
||||
if (!isNaN(value)) {
|
||||
notNumber = false;
|
||||
const decimal = value.toString().split('.')[1];
|
||||
precisions.push(decimal ? decimal.length : 0);
|
||||
}
|
||||
});
|
||||
const precision = Math.max.apply(null, precisions);
|
||||
if (!notNumber) {
|
||||
return values.reduce((prev, curr) => {
|
||||
const value = Number(curr);
|
||||
if (!isNaN(value)) {
|
||||
return parseFloat((prev + curr).toFixed(precision));
|
||||
}
|
||||
return prev;
|
||||
}, 0);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// className
|
||||
function getClassName() {
|
||||
const classList = [];
|
||||
classList.push(`${this.prefixCls}__footer-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
return classList.join(' ');
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table cellspacing="0" cellpadding="0" border="0" class={ `${this.prefixCls}__footer` }>
|
||||
<colgroup>
|
||||
{ this.table.tableColumns.map(column =>
|
||||
<col width={ column.computedWidth || column.minWidth || column.width }></col>)
|
||||
}
|
||||
</colgroup>
|
||||
<tfoot>
|
||||
<tr class={ `${this.prefixCls}__footer-row` }>
|
||||
{ this.table.tableColumns.map((column, columnIndex) =>
|
||||
<td class={ getClassName.call(this) }>
|
||||
<div class={ `${this.prefixCls}__cell-inner` }>
|
||||
{ this.table.summaryMethod
|
||||
? this.table.summaryMethod(this.table.bodyData, column, columnIndex)
|
||||
: renderCell.call(this, column, columnIndex) }
|
||||
</div>
|
||||
</td>)
|
||||
}
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
};
|
||||
108
seller/src/views/my-components/tree-table/Table/TableHeader.js
Normal file
108
seller/src/views/my-components/tree-table/Table/TableHeader.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import Checkbox from "../Checkbox/Checkbox"; // eslint-disable-line
|
||||
import { mixins } from "./utils";
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: "TreeTable__header",
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleAllChecked(checked) {
|
||||
this.table.bodyData = this.table.bodyData.map(row => ({
|
||||
...row,
|
||||
_isChecked: checked
|
||||
}));
|
||||
}
|
||||
},
|
||||
render() {
|
||||
// className
|
||||
function getClassName(type, { headerAlign, key }) {
|
||||
const certainType = this.validateType(
|
||||
type,
|
||||
["cell", "inner"],
|
||||
"getClassName"
|
||||
);
|
||||
const classList = [];
|
||||
if (key == "_normalIndex") {
|
||||
classList.push(`${this.prefixCls}--center-cell`);
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(`${this.prefixCls}__header-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
if (["center", "right"].indexOf(headerAlign) > -1) {
|
||||
classList.push(`${this.prefixCls}--${headerAlign}-cell`);
|
||||
}
|
||||
}
|
||||
if (certainType.inner) {
|
||||
classList.push(`${this.prefixCls}__cell-inner`);
|
||||
if (this.table.treeType && this.table.firstProp === key) {
|
||||
classList.push(`${this.prefixCls}--firstProp-header-inner`);
|
||||
}
|
||||
}
|
||||
return classList.join(" ");
|
||||
}
|
||||
|
||||
// 根据type渲染单元格Label
|
||||
function renderLabel(column, columnIndex) {
|
||||
if (
|
||||
this.isSelectionCell(this.table, columnIndex) &&
|
||||
this.selectType === "checkbox"
|
||||
) {
|
||||
const allCheck = this.table.bodyData.every(row => row._isChecked);
|
||||
const indeterminate =
|
||||
!allCheck && this.table.bodyData.some(row => row._isChecked);
|
||||
return (
|
||||
<Checkbox
|
||||
indeterminate={indeterminate}
|
||||
value={allCheck}
|
||||
onOn-change={checked => this.toggleAllChecked(checked)}
|
||||
></Checkbox>
|
||||
);
|
||||
}
|
||||
return column.title ? column.title : "";
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
class={`${this.prefixCls}__header`}
|
||||
>
|
||||
{/* <colgroup>
|
||||
{this.table.tableColumns.map(column => (
|
||||
<col
|
||||
width={column.computedWidth || column.minWidth || column.width}
|
||||
></col>
|
||||
))}
|
||||
</colgroup> */}
|
||||
<thead>
|
||||
<tr class={`${this.prefixCls}__header-row`}>
|
||||
{
|
||||
this.table.tableColumns.map((column, columnIndex) =>
|
||||
column.key ? (
|
||||
<th class={getClassName.call(this, "cell", column)}>
|
||||
<div class={getClassName.call(this, "inner", column)}>
|
||||
{renderLabel.call(this, column, columnIndex)}
|
||||
</div>
|
||||
</th>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
};
|
||||
Binary file not shown.
@@ -0,0 +1,22 @@
|
||||
// icon
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('iconfont.eot?t=1505310522875'); /* IE9*/
|
||||
src: url('iconfont.eot?t=1505310522875#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAW0AAsAAAAACOQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kggY21hcAAAAYAAAABuAAABojLtBtFnbHlmAAAB8AAAAa8AAAKA73SzT2hlYWQAAAOgAAAALwAAADYO3fRqaGhlYQAAA9AAAAAcAAAAJAfeA4ZobXR4AAAD7AAAABMAAAAUE+kAAGxvY2EAAAQAAAAADAAAAAwBbAHYbWF4cAAABAwAAAAeAAAAIAEUAF1uYW1lAAAELAAAAUUAAAJtPlT+fXBvc3QAAAV0AAAAQAAAAFryy5h0eJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/s04gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDwzZm7438AQw9zA0AAUZgTJAQAoHgyieJzFkcENwyAUQ98HyqHKKDmEZoEOklOnYOK/RmI+uXSCWDLG/pZAALyALK5iAfthDBxKLfLMO/LCJl+lRqL7fp7y3VuoKprV0KxO0qbyGOy5o/+xxPq9nV6YflNX9DY5fsA/k6Pj+yTpAn3jEO8AAHiclVDNitNQFD7n3slNE9vE5N7kpOn0J0mbKB3DGDMZRGw3bhQXA2LB5TyAbmfjohvBhQvfYEAEoc8wr+EDiK4KPkITU0EcXDmHw3fOgfN9fHygATTf+BUPQMIduA9P4AwAxRxjiw0xysqczdGLNI+UxbMki/QkzvljpFgov6jKlIQubLRwhA+iospyluFJuWCPsPCHiP1B+MKdHbr8I5pBNnpXP2Of0Bsnh/biXv30aKmKiexcdF2377ofOkLTOowd2Ba+Jt/QDFPUnzU79K7Gd9kYu/0sfP6qNxm45+/LN8MZGYjrNcrBxPqydEKn7behL92+frvXCcJeMlV48eNWILvD9Du0hXtgl+wSHIBZnJZLzNKyKgh9paPAdVca260hAxPBMBowz9t1uzUDuT8CswEDDtq8Gr7mADaM4QgetrKRhbozQooWeOrkKJVIojg9ccqqjcT3uBJ6lGNZnUYjnBU+ORbGaeYskM93m+kx4vGUrX5PQXK3kUSSrSS9JFWvFJHCjaIGJCFSugcOLeM6c7f6wyFZf/37+PO6AgD/x/vNnN/A7H8bhF86tmcbAHicY2BkYGAAYl/p/jnx/DZfGbhZGEDg6v0IKwT9/yELA7MEkMvBwAQSBQAZYgnZAHicY2BkYGBu+N/AEMPCAAJAkpEBFbACAEcLAm54nGNhYGBgfsnAwMKAwAAOmwD9AAAAAAAAdgCYAPYBQHicY2BkYGBgZQgEYhBgAmIuIGRg+A/mMwAAES0BcgAAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicY2BigAAuBuyAlZGJkZmRhZGVkY2BsYI7MS89J1W3KDM9o4S3IKe0WLe4sDSxKFU3ny83Mw+Jy8AAAHSWD8A=') format('woff'),
|
||||
url('iconfont.ttf?t=1505310522875') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url('iconfont.svg?t=1505310522875#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.zk-icon {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.zk-icon-plus-square-o:before { content: "\e631"; }
|
||||
|
||||
.zk-icon-minus-square-o:before { content: "\e632"; }
|
||||
|
||||
.zk-icon-angle-right:before { content: "\e633"; }
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<!--
|
||||
2013-9-30: Created.
|
||||
-->
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by iconfont
|
||||
</metadata>
|
||||
<defs>
|
||||
|
||||
<font id="iconfont" horiz-adv-x="1024" >
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="500"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
|
||||
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
|
||||
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
|
||||
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
|
||||
|
||||
|
||||
|
||||
<glyph glyph-name="angle-right" unicode="" d="M384.087 97.474c-7.857 0-15.713 2.997-21.707 8.992-11.989 11.989-11.989 31.426 0 43.415l234.118 234.12-234.118 234.118c-11.988 11.989-11.988 31.427 0 43.416 11.989 11.988 31.426 11.988 43.416 0l255.826-255.827c11.989-11.989 11.989-31.427 0-43.416l-255.826-255.827c-5.995-5.995-13.851-8.992-21.708-8.992z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="plus-square-o" unicode="" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667zM512 640c25.6 0 42.666667-17.066667 42.666667-42.666667v-426.666666c0-25.6-17.066667-42.666667-42.666667-42.666667s-42.666667 17.066667-42.666667 42.666667V597.333333c0 25.6 17.066667 42.666667 42.666667 42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="minus-square-o" unicode="" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
||||
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
import mixins from './mixins';
|
||||
import scrollBarWidth from './scrollBarWidth';
|
||||
export {
|
||||
mixins,
|
||||
scrollBarWidth
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
prefixCls: 'zk-table',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
validateType(type, validTypes, funcName, isReturn = true) {
|
||||
if (validTypes.indexOf(type) < 0) throw new Error(`${funcName}'s type must is ${validTypes.join(' or ')}.`);
|
||||
if (isReturn) {
|
||||
const certainType = {};
|
||||
validTypes.forEach((item) => {
|
||||
certainType[item] = item === type;
|
||||
});
|
||||
return certainType;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
isExpandCell(table, columnIndex) {
|
||||
return table.expandType && (
|
||||
(table.showIndex && columnIndex === 1) ||
|
||||
(!table.showIndex && columnIndex === 0)
|
||||
);
|
||||
},
|
||||
isSelectionCell(table, columnIndex) {
|
||||
return table.selectable && (
|
||||
(table.showIndex && table.expandType && columnIndex === 2) ||
|
||||
(!table.showIndex && table.expandType && columnIndex === 1) ||
|
||||
(table.showIndex && !table.expandType && columnIndex === 1) ||
|
||||
(!table.showIndex && !table.expandType && columnIndex === 0)
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import Vue from 'vue';
|
||||
|
||||
let scrollBarWidth;
|
||||
|
||||
export default function () {
|
||||
if (Vue.prototype.$isServer) return 0;
|
||||
if (scrollBarWidth !== undefined) return scrollBarWidth;
|
||||
|
||||
const outer = document.createElement('div');
|
||||
outer.style.visibility = 'hidden';
|
||||
outer.style.width = '100px';
|
||||
outer.style.position = 'absolute';
|
||||
outer.style.top = '-9999px';
|
||||
document.body.appendChild(outer);
|
||||
|
||||
const widthNoScroll = outer.offsetWidth;
|
||||
outer.style.overflow = 'scroll';
|
||||
|
||||
const inner = document.createElement('div');
|
||||
inner.style.width = '100%';
|
||||
outer.appendChild(inner);
|
||||
|
||||
const widthWithScroll = inner.offsetWidth;
|
||||
outer.parentNode.removeChild(outer);
|
||||
scrollBarWidth = widthNoScroll - widthWithScroll;
|
||||
|
||||
return scrollBarWidth;
|
||||
}
|
||||
Reference in New Issue
Block a user