Commit 3eef17d6 by 曾经

Merge branch 'feature/7月基础一异常冻结会员'

* feature/7月基础一异常冻结会员: (79 commits)
  图片更换
  距离调整
  会员卡券核销
  table-sticky
  表单滚动到 报错的位置
  UI 变更  交互优化
  分页器距离列表距离修改
  异常规则配置 保存交互
  会员信息 增加鼠标移上去的小手
  异常规则配置  提示优化
  其他页面 影响到了 组件里subtitle标签 问题
  搜索结果导出 icon
  样式兼容
  兼容测试
  尝试解决
  部分浏览器版本 deep 不生效问题
  no message
  多选
  no message
  冻结弹窗 自动撑开 样式优先级
  ...

# Conflicts:
#	src/components/allCustomers/index.js
#	src/components/axios/url.js
#	src/components/wechatmembers/cardvoucher.vue
parents 56b8c910 02803e40
......@@ -6,7 +6,8 @@
<style href="//at.alicdn.com/t/font_2996579_ubjq74uy5wj.css"></style><!--GIC3.0 客户 -->
<!-- 3.0 组件库 -->
<script src="//at.alicdn.com/t/font_2859043_ckil7xvsqi.js"></script>
<!-- <style href="//at.alicdn.com/t/font_688955_2dxzdzrb3a7.css"></style>GIC后台3.0 -->
<!-- <link rel="stylesheet" href="//web-1251519181.file.myqcloud.com/simple-style.1.0.2.css"></link> -->
<!-- <link href="//at.alicdn.com/t/font_688955_2dxzdzrb3a7.css"></link>GIC后台3.0 -->
<!-- <script src="//at.alicdn.com/t/font_688955_2dxzdzrb3a7.js"></script> -->
<script src="//web-1251519181.file.myqcloud.com/lib/lodash.min.js"></script>
<title></title>
......
......@@ -123,21 +123,30 @@
}
}
}
.customer-info-cell {
display: flex;
align-items: center;
img {
display: block;
width: 60px;
height: 60px;
margin-right: 10px;
// border-radius: 100%;
}
.memberName {
overflow: hidden;
.basic-info-table {
color: #303133;
font-size: 14px;
cursor: pointer;
.member-name{
width: 140px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.nick-name {
color: #909399;
font-size: 14px;
}
.basic-img {
display: inline-block;
vertical-align: middle;
height: 40px;
width: 40px;
min-width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
.status-icon {
font-size: 20px;
......
......@@ -153,18 +153,35 @@
:label="memberFieldsName[colum]"
:prop="colum"
show-overflow-tooltip
:min-width="colum==='name' ?200 : colum == 'status' ? 170 : 150"
:min-width="colum==='name' ? 210 : colum == 'status' ? 170 : 150"
:fixed="colum==='name'"
:sortable="['name','grade','status','channel','createCardStoreName','cardNo','forzenStatus','mainStoreName'].includes(colum)?false:isExist[colum]?'custom':false"
>
<template slot-scope="{row}">
<!-- 基本信息 -->
<div v-if="colum == 'name'" :class="['customer-info-cell', getCodeAuth('memberIntoCustomDetail') && 'pointer']" @click="linkDetail(row.memberId)">
<img :src="row.thirdImgUrl||defaultImg" alt="">
<p class="memberName">
{{ row.memberName || '--' }}
</p>
</div>
<el-row
v-if="colum == 'name'"
type="flex"
align="middle"
class="basic-info-table"
@click.native="linkDetail(row.memberId)"
>
<img :src="row.thirdImgUrl || defaultImg" class="basic-img" />
<div>
<div class="member-name">
<span v-if="row.memberName">{{
row.memberName
}}</span>
<span class="nick-name" v-if="row.nickName"
>({{ row.nickName }})</span
>
</div>
<div v-if="row.phoneNumber" class="phone-number">
{{ row.phoneNumber }}
</div>
</div>
</el-row>
<!-- 等级 -->
<span v-else-if="colum == 'grade'">{{ row.gradeName }}</span>
<!-- 状态 -->
......@@ -342,7 +359,9 @@
@successImport="successImport"
/>
<!-- 批量导入 -->
<import-dialog :dialogVisible.sync="dialogImportVisible" @successImport="taskId => successImport(taskId, true)"/>
<import-dialog :dialogVisible.sync="dialogImportVisible"
:pageType="1"
:importList="importList" @successImport="taskId => successImport(taskId, true)"/>
</div>
</template>
<script>
......
......@@ -5,8 +5,8 @@ import gradeDailog from "./components/batchgradeDialog.vue";
import mainstoreDailog from "./components/mainstoreDialog.vue";
import substoreDailog from "./components/substoreDialog.vue";
import batchList from "./components/batchList.vue";
import importDialog from "./components/importDialog.vue";
import { doFetch, doFetchGet } from "../../components/axios/api";
import importDialog from "@/components/allCustomers/components/importDialog.vue";
import { doFetch,doFetchGet } from "../../components/axios/api";
import url from "../../components/axios/url";
import { mapState } from "vuex";
import { formatLongTime, paddingBorth } from "@/utils/utils";
......@@ -46,6 +46,32 @@ export default {
searchAble: false,
multipleAble: true
},
importList:[
{
importType: 11,
importValue: "积分增加",
},
{
importType: 12,
importValue: "积分扣除",
},
{
importType: 13,
importValue: "等级调整",
},
{
importType: 14,
importValue: "服务门店/专属导购调整",
},
{
importType: 15,
importValue: "批量冻结会员",
},
{
importType: 16,
importValue: "批量解冻会员",
},
],
sceneValue: "member", // 人群筛选器场景值
navpath: [
{ name: "首页", path: "" },
......@@ -222,6 +248,9 @@ export default {
this.getAjaxMembers();
this.getEnterpriseInfo();
},
activated(){
this.getAjaxMembers();
},
beforUpdate() {},
methods: {
onSelectTreeChange(data) {
......@@ -487,7 +516,7 @@ export default {
cancelButtonText: "取消",
closeOnClickModal: false,
customClass: "import-link-confirm-content",
type: "warning"
type: "success"
}
)
.then(() => {
......
......@@ -8,6 +8,7 @@ export function doFetchqs(url,option) {
}
export function doFetchGet(url, option) {
option = option || {};
option.requestProject = 'member';
return fetchGet(url, option);
}
......@@ -106,7 +106,19 @@ const urlConfig = {
batchUpdateFrozen: "/api-member/members-batch-update-frozen",
getExceptionList: '/api-member/list-exception-member',
getErpIntegral: '/api-member/member-erp-integral'
getErpIntegral: '/api-member/member-erp-integral',
getExceptionMemberList: '/api-member/exception-member-list',// 获取异常列表
exceptionMemberExportExcel: '/api-admin/exception-member-export-excel',// 异常会员数据导出
exceptionMemberBatchFrozen: '/api-member/exception-batch-frozen',// 异常会员批量冻结
getAbnormalSetting: '/api-member/exception-config-view',// 异常配置详情
saveAbnormalSetting: '/api-member/exception-config-save',// 保存异常配置
getUnfreezeCount: '/api-member/no_froze_member_count',// 获取当前选中的异常会员的未冻结数量
getEnableDownload:'/api-auth/get-enable-download-data-config-by-user',
updateFrozen: '/api-member/exception-frozen',// 异常更新冻结状态
getMembersForFrozen:'/api-member/ajax-members-do-frozen',
getFrozenWhiteList: '/api-member/white-member-list',//获取冻结白名单列表
removeFrozenWhiteMember:'/api-member//white-member-remove',// 移出白名单
frozenMemberExportExcel: '/api-admin/frozen-member-export-excel',// 异常会员搜索结果导出
}
const defaultUrl = Object.assign({}, urlConfig);
......
.abnormal-member-list-page {
height: 100%;
position: relative;
.forzen-container {
padding: 20px;
background-color: #fff;
height: 100%;
box-sizing: border-box;
.search {
margin-bottom: 24px;
.top-header {
display: flex;
align-items: center;
margin-bottom: 20px;
h2 {
margin-right: 20px;
font-size: 16px;
font-weight: bold;
color: #303133;
line-height: 22px;
}
}
.search-item {
display: flex;
justify-content: space-between;
}
}
.basic-info-table {
color: #303133;
font-size: 14px;
cursor: pointer;
.member-name {
width: 140px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.nick-name {
color: #909399;
font-size: 14px;
}
.basic-img {
display: inline-block;
vertical-align: middle;
height: 40px;
width: 40px;
min-width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
}
.frozen-table {
.pager {
text-align: right;
padding: 20px 0;
}
.el-table {
.setting-cell.el-table__cell {
display: flex;
align-items: center;
height: 50px;
padding: 0;
.cell.setting-cell {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
padding-right: 0;
.el-icon-setting {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 100%;
font-size: 20px;
color: #303133;
cursor: pointer;
background: #e5e6eb;
&:hover {
color: #000;
}
}
}
}
.el-table__empty-block {
z-index: 1;
position: relative;
background: white;
}
.cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 10px;
}
.el-table__header .cell {
padding-left: 10px;
}
.el-table-column--selection {
.cell {
padding-left: 16px;
padding-right: 0px;
}
}
.table-select-page .cell {
padding-left: 0px;
padding-right: 0;
display: flex;
align-items: center;
.el-dropdown {
padding: 0;
}
}
.el-table__header .el-table__cell {
padding: 0;
}
}
}
.no-setting-page {
height: 100%;
position: relative;
.no-setting-box {
position: absolute;
left: 50%;
top: 45%;
transform: translate(-50%, -50%);
.tips-box {
height: auto;
margin-right: 150px;
.label {
color: #0a1c2b;
font-size: 20px;
font-weight: 500;
margin-bottom: 40px;
min-width: 200px;
}
}
}
}
.no-update-page {
position: relative;
text-align: center;
padding: 0 30px;
box-sizing: border-box;
.icon {
width: 96px;
height: 96px;
margin: 150px auto 12px;
}
.label {
color: #606266;
font-size: 14px;
margin-bottom: 15px;
}
.no-update-alert {
width: auto;
/deep/.el-icon-info {
color: #2f54eb;
}
}
}
.data-abnormal-page {
position: absolute;
left: 0;
top: 0;
width: 100%;
text-align: center;
padding: 0 30px;
box-sizing: border-box;
img {
margin: 216px auto 12px;
width: 96px;
}
.title {
color: #303133;
font-size: 14px;
line-height: 20px;
}
.subtitle {
color: #606266;
font-size: 14px;
line-height: 20px;
}
.el-button--primary {
margin: 30px auto;
}
}
.channel-box {
display: inline-block;
+ .channel-box {
margin-left: 6px;
}
.channel-icon {
width: 20px;
height: 20px;
vertical-align: middle;
}
}
}
.abnormal-setting-page-box{
position: relative;
.abnormal-setting-page{
padding: 20px;
.el-alert--info{
align-items: baseline;
&.is-light{
background: #F7F8FA;
color: #303133;
}
/deep/.el-alert__icon{
color: #2F54EB;
}
/deep/.el-alert__title{
white-space: pre-wrap;
}
}
.el-form{
margin-top: 11px;
/deep/.el-form-item__label{
}
}
.tips{
color: #606266;
font-size: 12px;
margin-top: 6px;
&.light{
color: #2F54EB;
}
&.points{
position: relative;
&::before{
content: " ";
position: absolute;
width: 4px;
height: 4px;
border-radius: 50%;
background: #909399;
top: 50%;
transform: translateY(-50%);
left: -8px;
}
}
}
.dashed-line{
margin: 24px 0 20px;
border-bottom: 1px dashed #DCDFE6;
}
.input-form-item{
margin: 0 10px;
}
.count-input{
width: 140px;
}
.amount-input{
width: 140px;
}
.el-input-number{
text-align: left;
/deep/.el-input{
text-align: left;
/deep/.el-input__inner{
text-align: left;
}
}
}
.cell-item{
margin-top: 20px;
padding: 20px;
border-radius: 4px;
border: 1px solid #E4E7ED;
.label{
color: #303133;
font-size: 14px;
}
}
.form-item-cell{
padding: 10px 0;
&:first-child{
padding-top: 0;
}
&:last-child{
padding-bottom: 0;
}
}
}
.page-bottom{
position: sticky;
z-index: 10;
bottom: 0;
left: 0;
width: 100%;
height: 56px;
background: white;
box-shadow: 1px -2px 8px 0px rgba(220,223,230,0.6000);
}
}
<template>
<el-input-number
v-model="value"
:min="min"
:max="max"
:step="step"
:precision="precision"
:controls="false"
step-strictly
:placeholder="min + '-' + max"
@change="change"
></el-input-number>
</template>
<script>
export default {
name: 'FreezeInput',
components: {},
props: {
value:'',
min: '',
max: '',
step: '',
precision: '',
},
data() {
return {
};
},
methods: {
change(value){
console.log("value---->",value);
this.$emit('update:value', value);
}
},
watch: {
}
};
</script>
<style lang="scss" scoped>
</style>
......@@ -309,7 +309,7 @@
</div>
<div
class="pager"
style="float: right; margin: 10px 0;"
style="margin: 10px 0;"
v-if="model.total > 0"
>
<dm-pagination
......@@ -317,9 +317,9 @@
@size-change="handleModelSizeChange"
@current-change="handleModelCurrentChange"
:current-page="model.currentPage"
:page-sizes="[20, 50, 75, 100]"
:page-sizes="[20]"
:page-size="model.pageSize"
layout="total, sizes, prev, pager, next, jumper"
layout="total, prev, pager, next"
:total="model.total"
>
</dm-pagination>
......@@ -673,4 +673,10 @@ export default {
height: 100%;
overflow: auto;
}
.pager{
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>
<template>
<div>
<el-dialog
title="设置显示字段"
custom-class="table-colum-dailog"
:visible.sync="visible"
@close="cancel"
width="600px"
>
<div class="checkwtip mBottom10">
请选择您想显示的列表字段,最多勾选{{ max }}个选项,已经勾选了 <span
class="curcheck"
>{{ checkedFieldsCopy.length }}</span>
</div>
<el-checkbox-group
v-model="checkedFieldsCopy"
class="table-colum-wrap"
:min="min"
:max="max"
>
<el-checkbox
v-for="(item, index) in fields"
class="table-colum-item"
:key="index"
:label="item"
:disabled="item.code==='name' || item.code==='memberName'"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
<span slot="footer" class="dialog-footer">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="submitFields">确定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'ExportFieldsDialog',
props: {
min: 0,
max: 8,
fields: {
type: Array,
default: () => {
return [];
},
},
dialogVisible: {
type: Boolean,
default: false,
},
},
data () {
return {
visible: false,
checkedFieldsCopy: [],
};
},
watch: {
dialogVisible (n, o) {
this.visible = n;
if(!(this.fields && this.fields.length)){
this.$message({
message: "设置异常",
type: "error"
});
return this.visible = false;
}
if (n) {
this.checkedFieldsCopy = this.fields.filter((item)=>{
return item.check
});
}
},
},
methods: {
submitFields () {
this.$emit('update:dialogVisible', false);
this.$emit('submit', this.checkedFieldsCopy.map((item)=>{
return item.code;
}).join(','));
},
cancel () {
this.$emit('update:dialogVisible', false);
},
},
};
</script>
<style lang="less" scoped>
.table-colum-wrap {
display: flex;
flex-wrap: wrap;
width: 100%;
.table-colum-item {
flex: 25%;
line-height: 35px;
}
.table-colum-item + .table-colum-item {
margin-left: 0;
}
}
</style>
<style lang="less">
// 去除dailog-footer上边框
.table-colum-dailog .el-dialog__footer {
border-top: none !important;
}
.table-colum-dailog .el-checkbox:last-of-type {
margin-right: 30px;
}
</style>
<template>
<div>
<el-dialog :title="title || (isBatchFreeze ? '批量冻结会员' : '冻结会员')"
:visible.sync="visible" width="600px" @close="onClose"
:close-on-click-modal="false" :close-on-press-escape="false">
<div v-if="isBatchFreeze" class="freeze-tips">
<span>当前已选择</span>
<span class="count"> {{ count }} </span>
<span>位未冻结的会员</span>
</div>
<el-form :model="submitData" ref="submitForm" :rules="rules">
<el-form-item label="冻结原因" prop="frozenType" required>
<el-select v-model="submitData.frozenType" placeholder="" :disabled="isAbnormalFreeze"
style="width: 550px;">
<el-option label="异常冻结" :value="1"></el-option>
<el-option label="会员主动冻结" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="原因备注" prop="remark" required>
<el-input v-model="submitData.remark" placeholder="请输入原因备注" maxlength='20'
show-word-limit></el-input>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="onClose">取消</el-button>
<el-button type="primary" @click="sure('submitForm')" :loading="load">确定</el-button>
</el-row>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'FreezeDialog',
components: {},
props: {
submit: {
type: Function
},
visible: false,
count: 0,
isBatchFreeze: false,// 是否批量冻结
title: '',
isAbnormalFreeze: false,
},
data() {
return {
load: false,
rules:{
remark:{ required: true, message: '请输入原因备注' }
},
submitData:{
frozenType: 1,
remark: '',
},
};
},
methods: {
onClose() {
this.$emit('update:visible', false);
},
sure(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
this.load = true;
this.submit && this.submit(this.submitData,()=>{
this.load = false;
});
this.$emit('submit', this.submitData);
} else {
return false;
}
});
// console.log(this.dateValue,getTime(this.dateValue[0]));
}
},
watch: {
visible(){
this.load = false;
}
}
};
</script>
<style lang="scss" scoped>
/deep/.el-dialog__body{
padding-top: 14px;
}
.freeze-tips{
margin-bottom: 20px;
color: #6B6D71;
font-size: 14px;
.count{
font-size:16px;
color: #37383A;
font-weight: 500;
}
}
</style>
import { doFetch, doFetchGet } from "@/components/axios/api";
import url from "@/components/axios/url";
import {
checkFalse,
checkSuccess
} from "../../../../../static/js/checkStatus";
import authMethods from "@/mixins/auth";
import defaultImg from "../../../../../static/img/default.png";
import { formatLongTime,paddingBorth } from "@/utils/utils";
import FreezeDialog from "../../components/dialog/freeze.vue";
import MemberFieldsDialog from "../../components/dialog/fieldsSettingDialog.vue";
import ExportFieldsDialog from "../../components/dialog/fieldsSettingDialog.vue";
export default {
name: "forzenlist",
components: {
ExportFieldsDialog,
MemberFieldsDialog,
FreezeDialog
},
mixins: [authMethods],
filters: {
formatBirth(value){
return paddingBorth(value) || '--'
},
formatDate(val, format) {
if (!val || val == -1) return format == "hms" ? "" : "--";
let str = formatLongTime(val, 1);
let arr = str.split(" ");
if (format == "ymd") {
return arr[0];
} else if (format == "hms") {
return arr[1] || "";
}
return str;
}
},
data() {
return {
freezeDialogOptions: {
count: 1,
isBatchFreeze: 0,
visible: false
},
exportData: {
projectName: "member", // 当前项目名
dialogVisible: false,
type: 1,
excelUrl: url.frozenMemberExportExcel, // 下载数据的地址
params: {} // 传递的参数
},
dialogMemberFieldVisible: false,
dialogExportFieldVisible: false,
defaultImg,
settingType: 0, // 0未查询 1已设置 2未设置
selectPage: {
type: 0,
dataReady: true
},
searchData: {
frozenType: '', //会员状态
phoneNameCard: "", // 搜索字段
pageName: "wxOpenCarMember",
pageSize: 20,
currentPage: 1,
sortColName: "", // 排序字段
sortType: "", // 排序方式
},
load: false,
total: 0,
memberFields: [], // 顶部标题配置
exportFields: [], // 导出顶部配置
list: [],
multipleList: [],
abnormalSettingSave: 0
};
},
beforeMount() {
this.init();
},
activated(){
this.init();
},
methods: {
init() {
this.load = true;
this.getFindMemberFields(this.searchData.pageName)
.then(list => {
this.memberFields = list;
this.getList();
})
.catch(() => {
this.getList();
});
},
getFindMemberFields(pageName) {
return new Promise((resolve, reject) => {
if (!pageName) {
reject();
}
doFetch(url.findMemberFields, {
pageName
})
.then(res => {
let { errorCode, result } = res.data;
if (errorCode === 0 && Array.isArray(result)) {
resolve(result || []);
} else {
checkFalse(res.data.message);
reject(res);
}
})
.catch(err => {
reject(err);
});
});
},
getList() {
this.load = true;
this.selectPage.dataReady = false;
doFetch(url.getFrozenList, this.searchData)
.then(res => {
this.selectPage.dataReady = true;
this.load = false;
let { errorCode, result } = res.data || {};
if (errorCode === 0) {
let { result: list, totalCount } = result || {};
this.list = list || [];
this.total = totalCount || 0;
}
})
.catch(() => {
this.load = false;
this.selectPage.dataReady = true;
});
},
sortChange(column) {
let { prop, order } = column;
this.searchData.sortColName = prop;
if (order === "descending") {
this.searchData.sortType = "desc";
}
if (order === "ascending") {
this.searchData.sortType = "asc";
}
this.getList();
},
// 搜索选项改变时
onSearchDataChange() {
this.searchData.currentPage = 1;
this.getList();
},
handleCurrentChange(val) {
this.searchData.currentPage = val;
this.getList();
},
handleSizeChange(pageSize){
this.searchData.pageSize = pageSize;
if((this.searchData.currentPage - 1) * this.searchData.pageSize > this.total){
this.searchData.currentPage = 1;
}
this.getList();
},
submitMemberFields(fields) {
doFetch(url.updateFields, {
pageName: this.searchData.pageName,
fields
}).then(res => {
if (res.data.errorCode === 0) {
checkSuccess();
// 需要对选中字段排序
this.init();
} else {
checkFalse(res.data.message);
}
});
},
// 导出选项选择完毕 点击确定
submitExportFields(fields) {
doFetch(url.updateFields, {
pageName: "memberTag",
fields
});
doFetch(url.getEnableDownload).then(res => {
let { errorCode, result } = res.data;
if (errorCode === 0 && result == 1) {
this.exportData.type = 2;
} else {
this.exportData.type = 1;
}
});
let { phoneNameCard, frozenType } = this.searchData || {};
this.exportData.params = {
frozenType,
phoneNameCard,
exportFields: fields
};
this.exportData.dialogVisible = true;
},
freezeConfim(options){
options = options || {};
this.freezeDialogOptions = options;
},
freezeDialogHidden(){
this.freezeDialogOptions = {
visible: false
}
},
// 解冻
unfreezeItem(item) {
doFetchGet(url.updateFrozen,{
status: 0,
pageType: 1,
memberId: item.memberId
}).then(res => {
if (res.data.errorCode === 0) {
this.$message({
message: "解冻成功",
type: "success"
});
this.$nextTick(_ => {
this.getList();
});
}
});
},
// 批量解冻
async clickBatchUnfreeze() {
let { multipleList,list } = this;
if(!(list && list.length)){
this.$message({
message: "暂无数据,无法解冻",
type: "warning"
});
return;
}
if (!(multipleList && multipleList.length)) {
return this.$message.warning("请勾选要修改的会员");
}
this.$confirm("确定解冻?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.batchUnfreeze();
});
},
batchUnfreeze(){
let ids = [];
let { selectPage, multipleList, searchData } = this;
let { phoneNameCard } = searchData;
multipleList.forEach(ele => {
ids.push(ele.memberId);
});
const datas = {
memberIds: ids.join(","), // 会员id
remark: "", // 备注暂留
//所有会员是2 当前是1 其他是0
isCurrent: selectPage.type == 2 ? 2 : 1,
status: 0, // 1 冻结 0 解冻
phoneNameCard,
};
doFetch(url.batchUpdateFrozen, datas).then(async res => {
let {errorCode,result} = res.data;
if (errorCode === 0) {
this.$message({
message: "解冻成功",
type: "success"
});
this.freezeStatusChangeSuccess(result);
}
});
},
freezeStatusChangeSuccess(taskId) {
this.$confirm(
"任务发起成功,请去【企业管理】-【任务中心】查看处理结果和执行进度",
"任务发起成功",
{
confirmButtonText: "去任务中心",
cancelButtonText: "取消",
closeOnClickModal: false,
customClass: "import-link-confirm-content",
type: "success"
}
)
.then(() => {
this.getList();
window.open(`/gic-web/#/taskDetail/${taskId}`);
})
.catch(() => {
this.getList();
});
},
// 搜索结果导出
download() {
if(this.total > 50000){
this.$message.warning("单次导出数量最多5万条");
return;
}else
if (this.total) {
this.getFindMemberFields("memberTag").then(list => {
this.exportFields = list;
this.dialogExportFieldVisible = true;
});
} else {
this.$message.warning("无数据");
}
},
linkDetail(memberId) {
this.$router.push({
path: "/customerDetail",
query: { memberId }
});
},
// 去冻结会员页
toFrozenMember(){
this.$router.push({
path: "/frozenList/frozenMember",
});
},
toWhiteList(){
this.$router.push({
path: "/frozenWhiteList",
});
},
}
};
.frozen-list-page {
height: 100%;
position: relative;
.forzen-container {
padding: 20px;
background-color: #fff;
.search {
margin-bottom: 24px;
.top-header {
display: flex;
align-items: center;
margin-bottom: 20px;
h2 {
margin-right: 20px;
font-size: 16px;
font-weight: bold;
color: #303133;
line-height: 22px;
}
}
.search-item {
display: flex;
justify-content: space-between;
}
}
.basic-info-table {
color: #303133;
font-size: 14px;
cursor: pointer;
.member-name {
width: 140px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.nick-name {
color: #909399;
font-size: 14px;
}
.basic-img {
display: inline-block;
vertical-align: middle;
height: 40px;
width: 40px;
min-width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
.reason-icon-box {
width: 24px;
height: 24px;
line-height: 24px;
text-align: center;
border-radius: 2px;
&:hover {
background: #e5e6eb;
}
}
.icon-yuanyin {
font-size: 14px;
color: #303030;
}
}
.frozen-table {
.pager {
text-align: right;
padding: 20px 0 0;
}
.el-table {
.setting-cell.el-table__cell {
display: flex;
align-items: center;
height: 50px;
padding: 0;
.cell.setting-cell {
display: flex;
justify-content: space-between;
align-items: center;
height: 50px;
padding-right: 0;
.el-icon-setting {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 100%;
font-size: 20px;
color: #303133;
cursor: pointer;
background: #e5e6eb;
&:hover {
color: #000;
}
}
}
}
.el-table__empty-block {
z-index: 1;
position: relative;
background: white;
}
.cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-left: 10px;
}
.el-table__header .cell {
padding-left: 10px;
}
.el-table-column--selection {
.cell {
padding-left: 16px;
padding-right: 0px;
}
}
.table-select-page .cell {
padding-left: 0px;
padding-right: 0;
display: flex;
align-items: center;
.el-dropdown {
padding: 0;
}
}
.el-table__header .el-table__cell {
padding: 0;
}
}
}
.no-setting-page {
height: 100%;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.tips-box {
height: auto;
margin-right: 150px;
.label {
color: #0a1c2b;
font-size: 20px;
font-weight: 500;
}
.el-button--primary {
margin-top: 40px;
border-radius: 2px;
}
}
}
.no-update-page {
position: relative;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100%;
.icon {
width: 120px;
height: 120px;
margin: 0 auto 16px;
}
.label {
color: #606266;
font-size: 14px;
}
.no-update-alert {
margin-top: 15px;
.el-icon-info {
color: #2f54eb;
}
}
}
.data-abnormal-page {
position: relative;
text-align: center;
height: calc(100% - 100px);
padding: 0 30px;
.icon {
margin: 116px auto 30px;
color: #fa8c16;
width: 72px;
height: 72px;
font-size: 72px;
}
.title {
color: #303133;
font-size: 14px;
line-height: 20px;
}
.subtitle {
color: #606266;
font-size: 14px;
line-height: 20px;
}
.el-button--primary {
margin: 30px auto;
}
}
.channel-box {
display: inline-block;
+ .channel-box {
margin-left: 6px;
}
.channel-icon {
width: 20px;
height: 20px;
vertical-align: middle;
}
}
}
import { doFetch, doFetchGet } from "@/components/axios/api";
import url from "@/components/axios/url";
import {
checkFalse,
checkSuccess
} from "../../../../../static/js/checkStatus";
import authMethods from "@/mixins/auth";
import defaultImg from "../../../../../static/img/default.png";
import ImportDialog from "@/components/allCustomers/components/importDialog.vue";
import { formatLongTime } from "@/utils/utils";
export default {
name: "frozen-member",
components: {
ImportDialog
},
mixins: [authMethods],
filters: {
formateTime(val){
if (!val || val == -1) return "--";
return formatLongTime(val, 1);
},
},
data() {
return {
dialogImportVisible: false,
defaultImg,
searchData: {
pageSize: 20,
currentPage: 1,
frozenType: -1,
phoneNameCard: '',
wxOrPos: -1,
fieldNames:
"name,nickName,photoUrl,cardNo,crateCardDateString,wxMember,posMember,phoneNumber",
},
total: 0,
list: [],
multipleList: [],
formData:{
frozenType: '',
remark: ''
}
};
},
created() {
this.loadData();
},
activated(){
this.loadData();
},
methods: {
loadData(){
doFetch(url.getMembersForFrozen, this.searchData).then((res) => {
let {errorCode,result} = res.data;
if (errorCode === 0) {
let {result:list,totalCount} = result;
this.list = list || [];
this.total = totalCount || 0;
} else {
checkFalse(res.data.message);
}
});
},
clearSelectedAll(){
this.$refs.multipleTable.clearSelection();
},
delSelectedItem(item){
this.$refs.multipleTable.toggleRowSelection(item,false);
},
handleSizeChange(pageSize){
this.searchData.pageSize = pageSize;
if((this.searchData.currentPage - 1) * this.searchData.pageSize > this.total){
this.searchData.currentPage = 1;
}
this.loadData();
},
handleCurrentChange(currentPage){
this.searchData.currentPage = currentPage;
this.loadData();
},
handleSelectionChange(selectionList){
this.multipleList = selectionList || [];
},
resetSelected(){
this.$refs.selectedForm.resetFields();
this.$refs.multipleTable.clearSelection();
},
submitForm() {
if(!this.multipleList.length){
this.$message({
message: "请选择要冻结的会员",
type: "warning"
});
return;
}
this.$refs.selectedForm.validate(valid => {
if (valid) {
this.$confirm("是否冻结所选会员?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
this.frozenMethod();
});
} else {
return false;
}
});
},
frozenMethod() {
let memberIds = this.multipleList.map((item)=>{
return item.memberId
}).join(',')
const datas = {
memberIds: memberIds, // 会员id 多个拼接起来, 隔开
remark: this.formData.remark, // 备注暂留
isCurrent: 0, // 所有会员是2 当前是1 其他是0
status: 1, // 1 冻结 0 解冻
frozenType: this.formData.frozenType, // 101.异常冻结、102.会员主动冻结
};
this.loading = true;
doFetch(url.batchUpdateFrozen, datas)
.then((res) => {
if (res.data.errorCode === 0) {
this.resetSelected();
this.handleToTaskCenter(res.data.result);
} else {
checkFalse(res.data.message);
}
})
.catch((err) => {
this.loading = false;
checkFalse(err);
});
},
handleToTaskCenter(id) {
this.$confirm(
`请去【系统】-【操作任务】-【任务中心】查看处理结果和执行进度`,
`任务发起成功`,
{
confirmButtonText: "去任务中心",
cancelButtonText: "取消",
closeOnClickModal: false,
customClass: "import-link-confirm-content",
type: "success"
}
).then(()=>{
this.loadData();
window.open(`/gic-web/#/taskDetail/${id}`);
}).catch(()=>{
this.loadData();
});
},
batchUpload(){
this.dialogImportVisible = true;
},
linkDetail(memberId) {
this.$router.push({
path: "/customerDetail",
query: { memberId }
});
},
}
};
.container.frozen-member {
background-color: #fff;
position: relative;
box-sizing: border-box;
width: 100%;
display: flex;
height: 100%;
.table-box{
padding: 20px;
border-right: 1px solid #DCDFE6;
.search-box{
margin-bottom: 20px;
}
.basic-info-table {
color: #303133;
font-size: 14px;
cursor: pointer;
.member-name{
width: 140px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.nick-name {
color: #909399;
font-size: 14px;
}
.basic-img {
display: inline-block;
vertical-align: middle;
height: 40px;
width: 40px;
min-width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
.pager{
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 20px;
}
}
.page-right{
padding: 20px;
box-sizing: border-box;
width: 420px;
position: relative;
height: calc(100% - 56px);
.selected-result-box{
min-height: 322px;
height: calc(100% - 220px);
overflow-y: scroll;
position: relative;
border: 1px solid #DCDFE6;
border-radius: 4px;
margin-bottom: 22px;
box-sizing: border-box;
.selected-top{
background: white;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 1;
width: 100%;
height: 60px;
padding: 0 16px;
.selected-count{
color: #37383A;
font-size: 14px;
}
}
.selected-list .selected-item{
display: flex;
align-items: center;
height: 40px;
margin-bottom: 4px;
&:last-child{
margin-bottom: 0;
}
&:hover{
background: #F7F8FA;
.icon-close{
background: #E5E6EB;
}
}
.user-header{
width: 30px;
height: 30px;
border-radius: 50%;
margin-left: 17px;
}
.user-name{
color: #47494C;
font-size: 14px;
margin: 0 10px;
flex: 1;
}
.icon-close{
color: #606266;
font-size: 14px;
padding: 3px;
border-radius: 50%;
margin-right: 12px;
}
}
}
}
.selected-bottom-box{
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 56px;
width: 420px;
z-index: 1;
box-shadow: 0px -2px 8px 0px rgba(220,223,230,0.6000);
background: white;
}
.frozen-table {
.pager {
text-align: right;
padding: 20px 0 0;
}
}
.el-table {
.cell {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
th>.cell:first-child{
padding-left: 10px;
}
.el-table-column--selection {
.cell:first-child {
padding-left: 16px;
padding-right: 0px;
}
}
.el-table__empty-block {
z-index: 1;
position: relative;
background: white;
}
}
}
<template>
<el-contaniner class="container frozen-member">
<el-main class="table-box">
<el-row
type="flex"
align="middle"
justify="space-between"
class="search-box"
>
<el-input
v-model="searchData.phoneNameCard"
placeholder="输入姓名/昵称/手机号/会员卡号"
style="width: 260px"
@change="loadData"
clearable
>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<el-button plain @click="batchUpload"
><i class="iconfont icon-shangchuan"></i> 批量导入</el-button
>
</el-row>
<el-table
:data="list"
tooltip-effect="dark"
ref="multipleTable"
class="member-table"
@selection-change="handleSelectionChange"
v-loading="load"
row-key="memberId"
>
<el-table-column
type="selection"
min-width="30"
fixed="left"
reserve-selection
></el-table-column>
<el-table-column label="会员信息" :min-width="210" show-overflow-tooltip>
<template slot-scope="{ row }">
<!-- 基本信息 -->
<el-row type="flex" align="middle" class="basic-info-table"
@click.native="linkDetail(row.memberId)">
<img :src="row.thirdImgUrl || defaultImg" class="basic-img" />
<div>
<div class="member-name">
<span v-if="row.memberName">{{ row.memberName }}</span>
<span class="nick-name" v-if="row.nickName"
>({{ row.nickName }})</span
>
</div>
<div v-if="row.phoneNumber">
{{ row.phoneNumber }}
</div>
</div>
</el-row>
</template>
</el-table-column>
<el-table-column label="会员卡号" prop="cardNum" :min-width="160"></el-table-column>
<el-table-column label="开卡时间" :min-width="160">
<template slot-scope="{ row }">
{{ row.crateCardDateString | formateTime }}
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="total > 0">
<dm-pagination
background
:page-size="searchData.pageSize"
:currentPage="searchData.currentPage"
:page-sizes="[20, 50, 75, 100]"
layout="total,sizes,prev, pager, next"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
:total="total"
>
</dm-pagination>
</div>
<import-dialog
:dialogVisible.sync="dialogImportVisible"
:pageType="2"
@successImport="(taskId) => handleToTaskCenter(taskId)"
/>
</el-main>
<el-contaniner>
<el-aside width="420px" class="page-right">
<div class="selected-result-box">
<el-row
class="selected-top"
type="flex"
align="middle"
justify="space-between"
>
<div class="selected-count">
已选:{{ multipleList.length }} 位会员
</div>
<el-button type="text" @click="clearSelectedAll">全部清除</el-button>
</el-row>
<div class="selected-list">
<div class="selected-item" v-for="item in multipleList" :key="item">
<img :src="item.thirdImgUrl || defaultImg" class="user-header" />
<div class="user-name">
<span v-if="item.memberName">{{ item.memberName }}</span>
<span class="nick-name" v-if="item.nickName"
>({{ item.nickName }})</span
>
</div>
<div
class="el-icon-close icon-close"
@click="delSelectedItem(item)"
></div>
</div>
</div>
</div>
<el-form
:model="formData"
label-position="top"
label-width="80px"
ref="selectedForm"
>
<el-form-item
label="冻结原因"
prop="frozenType"
required
:rules="{
required: true,
message: '请选择冻结原因',
}"
>
<el-select
v-model="formData.frozenType"
placeholder="请选择冻结原因"
style="width: 380px"
>
<el-option label="异常冻结" :value="1"></el-option>
<el-option label="会员主动冻结" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item
label="原因备注"
prop="remark"
required
:rules="{
required: true,
message: '请输入原因备注',
}"
>
<el-input
v-model="formData.remark"
:maxlength="20"
show-word-limit
placeholder="请输入原因备注"
></el-input>
</el-form-item>
</el-form>
</el-aside>
<div class="selected-bottom-box">
<el-button plain @click="$router.go(-1)">取消</el-button>
<el-button
type="primary"
@click="submitForm('selectedForm')"
>冻结选中会员</el-button
>
</div>
</el-contaniner>
</el-contaniner>
</template>
<script src="./frozen-member.js"></script>
<!-- <script>
import action from './abnormal-member.js';
export default { ...action };
</script> -->
<style lang="less">
</style>
<style lang="less" src="./frozen-member.less"></style>
import { doFetch, doFetchGet } from "@/components/axios/api";
import url from "@/components/axios/url";
import {
checkFalse,
checkSuccess
} from "../../../../../static/js/checkStatus";
import authMethods from "@/mixins/auth";
import defaultImg from "../../../../../static/img/default.png";
import ImportDialog from "@/components/allCustomers/components/importDialog.vue";
import { formatLongTime } from "@/utils/utils";
import {dateformat} from '@/utils/formatTime';
import FreezeDialog from '../../components/dialog/freeze.vue';
export default {
name: "frozenMemberWhiteList",
components: {
FreezeDialog,
ImportDialog
},
mixins: [authMethods],
filters: {
formatLongTimeDate(val, format) {
if (!val || val == -1) return format == "hms" ? "" : "--";
let str = formatLongTime(val, 1);
let arr = str.split(" ");
if (format == "ymd") {
return arr[0];
} else if (format == "hms") {
return arr[1] || "";
}
return str;
},
formatDate(val, format) {
if (!val || val == -1) return format == "hms" ? "" : "--";
if (format == "ymd") {
return dateformat(new Date(val), 'yyyy-MM-dd');
} else if (format == "hms") {
return dateformat(new Date(val), 'hh:mm:ss');
}
return dateformat(new Date(val), 'yyyy-MM-dd hh:mm:ss');
},
formateTime(val){
if (!val || val == -1) return "--";
return dateformat(val, 'yyyy-MM-dd hh:mm:ss');
},
},
data() {
return {
load: false,
freezeDialogOptions: {
count: 1,
isBatchFreeze: 0,
visible: false
},
whiteImportList:[
{
importType: 17,
importValue: "移入白名单",
}
],
dialogImportVisible: false,
defaultImg,
searchData: {
pageSize: 20,
currentPage: 1,
cardNo: '',
},
total: 0,
list: [],
multipleList: [],
formData:{
frozenType: '',
remark: ''
}
};
},
created() {
this.loadData();
},
activated(){
this.loadData();
},
methods: {
loadData(){
this.load = true;
doFetchGet(url.getFrozenWhiteList, this.searchData).then((res) => {
let {errorCode,result} = res.data;
if (errorCode === 0) {
let {result:list,totalCount} = result;
this.list = list || [];
this.total = totalCount || 0;
} else {
checkFalse(res.data.message);
}
}).finally(()=>this.load = false)
},
handleSizeChange(pageSize){
this.searchData.pageSize = pageSize;
if((this.searchData.currentPage - 1) * this.searchData.pageSize > this.total){
this.searchData.currentPage = 1;
}
this.loadData();
},
handleCurrentChange(currentPage){
this.searchData.currentPage = currentPage;
this.loadData();
},
batchUpload(){
this.dialogImportVisible = true;
},
// 移出白名单
clickRemoveItem(item){
this.load = true;
doFetchGet(url.removeFrozenWhiteMember,{
removeType: 1,
memberId: item.memberId,
}).then(res=>{
if(res.data.errorCode == 0) {
this.$message({
message: "移出成功",
type: "success"
});
this.loadData();
}
}).finally(()=>this.load = false)
},
// 点击删除并冻结
clickRemoveAndFreeze(item){
this.freezeDialogOptions= {
count: 1,
isBatchFreeze: 0,
visible: true,
title: '移出并冻结会员',
submit:async (options,callBack)=>{
doFetchGet(url.removeFrozenWhiteMember,{
removeType: 2,
status: 1,
memberId: item.memberId,
frozenType: options.frozenType,
remark: options.remark || ""
}).then((res)=>{
if (res.data.errorCode === 0){
checkSuccess();
this.freezeDialogOptions = {
visible: false
};
this.loadData();
}
}).finally(()=>callBack && callBack())
}
}
},
linkDetail(memberId){
this.$router.push({
path: "/customerDetail",
query: { memberId }
});
},
handleToTaskCenter(id) {
this.$confirm(
`请去【系统】-【操作任务】-【任务中心】查看处理结果和执行进度`,
`任务发起成功`,
{
type: "success",
customClass: "import-link-confirm-content",
confirmButtonText: "去任务中心",
cancelButtonText: "取消",
showClose: false,
}
).then(()=>{
this.loadData();
window.open(`/gic-web/#/taskDetail/${id}`);
}).catch(()=>{
this.loadData();
});
},
}
};
.container .frozen-white-list{
padding: 20px;
background: white;
.top-header {
display: flex;
align-items: center;
margin-bottom: 20px;
h2 {
margin-right: 20px;
font-size: 16px;
font-weight: bold;
color: #303133;
line-height: 22px;
}
}
.search-box {
margin-bottom: 20px;
.tips-box{
margin: 0 16px;
i{
color: #2F54EB;
font-size: 14px;
}
span{
color: #606266;
font-size: 14px;
margin-left: 5px;
}
}
}
.member-table {
.basic-info-table {
color: #303133;
font-size: 14px;
cursor: pointer;
.member-name{
width: 140px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.nick-name {
color: #909399;
font-size: 14px;
}
.basic-img {
display: inline-block;
vertical-align: middle;
height: 40px;
width: 40px;
min-width: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 10px;
}
}
.reason-label {
word-break: break-all;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
.el-dialog__footer{
border-top: none;
padding: 10px 30px;
}
.el-dialog__body{
padding: 6px 30px 16px;
}
.el-dialog__header{
padding: 20px 30px 10px;
}
.pager {
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 20px;
}
.el-table {
th>.cell:first-child{
padding-left: 10px;
}
.el-table__empty-block {
z-index: 1;
position: relative;
background: white;
}
}
}
<template>
<div class="container frozen-white-list">
<div class="top-header">
<h2>白名单会员 {{ total }}</h2>
</div>
<el-row
type="flex"
align="middle"
justify="space-between"
class="search-box"
>
<el-row type="flex" align="middle">
<el-input
v-model="searchData.cardNo"
placeholder="输入会员卡号"
style="width: 260px"
@change="loadData"
clearable
>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<div class="tips-box">
<i class="el-icon-info"></i>
<span>处于白名单列表中的会员不会被冻结(外部接口冻结除外)</span>
</div>
</el-row>
<el-button plain @click="batchUpload"
:limit-code="getCode('memberFrozenWhiteListImport')"
v-if="getCodeAuth('memberFrozenWhiteListImport')"
><i class="icon iconfont icon-shangchuan"></i> 批量导入</el-button
>
</el-row>
<el-table
:data="list"
tooltip-effect="dark"
ref="multipleTable"
class="member-table"
v-loading="load"
>
<el-table-column label="会员信息" :min-width="210" fixed="left" show-overflow-tooltip>
<template slot-scope="{ row }">
<!-- 基本信息 -->
<el-row
type="flex"
align="middle"
class="basic-info-table"
@click.native="linkDetail(row.memberId)"
>
<img :src="row.thirdImgUrl || defaultImg" class="basic-img" />
<div>
<div class="member-name">
<span v-if="row.memberName">{{ row.memberName }}</span>
<span class="nick-name" v-if="row.nickName"
>({{ row.nickName }})</span
>
</div>
<div v-if="row.phoneNumber">
{{ row.phoneNumber }}
</div>
</div>
</el-row>
</template>
</el-table-column>
<el-table-column label="会员等级" prop="gradeName" :min-width="140"></el-table-column>
<el-table-column label="会员生日" prop="birthdayMD" :min-width="140"></el-table-column>
<el-table-column label="会员卡号" prop="cardNo" :min-width="140"></el-table-column>
<el-table-column label="最近消费时间" :min-width="140">
<template slot-scope="{ row }">
<div>
<div>{{ row.lastCostTime | formatLongTimeDate("ymd") }}</div>
<div>{{ row.lastCostTime | formatLongTimeDate("hms") }}</div>
</div>
</template>
</el-table-column>
<el-table-column
label="移入原因"
prop="remark"
label-class-name="reason-label"
:min-width="140"
></el-table-column>
<el-table-column label="移入时间" :min-width="140">
<template slot-scope="{ row }">
<div>
<div>{{ row.createTime | formatDate("ymd") }}</div>
<div>{{ row.createTime | formatDate("hms") }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="220">
<template slot-scope="{ row }">
<!--
:limit-code="getCode('memberIntoCustomDetail')"
v-if="getCodeAuth('memberIntoCustomDetail')"
-->
<el-button type="text" @click="linkDetail(row.memberId)"
>查看</el-button
>
<dm-delete
tips="确认移出白名单吗?"
@confirm="clickRemoveItem(row)"
placement="top-start"
v-if="getCodeAuth('memberFrozenWhiteListRemove')"
>
<el-button type="text"
:limit-code="getCode('memberFrozenWhiteListRemove')">仅移出</el-button>
</dm-delete>
<el-button
type="text"
@click="clickRemoveAndFreeze(row)"
v-if="row.frozenStatus != 1 && getCodeAuth('memberFrozenWhiteListRemoveAndFrozen')"
:limit-code="getCode('memberFrozenWhiteListRemoveAndFrozen')"
>移出并冻结</el-button
>
</template>
</el-table-column>
</el-table>
<div class="pager" v-if="total > 0">
<dm-pagination
background
:page-size="searchData.pageSize"
:currentPage="searchData.currentPage"
:page-sizes="[20, 50, 75, 100]"
layout="total,sizes,prev, pager, next"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
:total="total"
>
</dm-pagination>
</div>
<import-dialog
:importList="whiteImportList"
:dialogVisible.sync="dialogImportVisible"
@successImport="(taskId) => handleToTaskCenter(taskId)"
/>
<freeze-dialog
v-bind.sync="freezeDialogOptions"
v-if="freezeDialogOptions.visible"
/>
</div>
</template>
<script src="./white-list.js"></script>
<!-- <script>
import action from './abnormal-member.js';
export default { ...action };
</script> -->
<style lang="less">
</style>
<style lang="less" src="./white-list.less"></style>
......@@ -718,7 +718,7 @@ import wechatTotalDetail from './wechatTotalDetail'
export default { ...wechatTotalDetail }
</script>
<style lang="stylus">
<style lang="stylus" scoped>
@import "../../../static/css/variables.styl"
.wechat
margin 0 auto
......
......@@ -688,7 +688,7 @@ import wechatmemberDetail from './wechatmemberDetail'
export default { ...wechatmemberDetail }
</script>
<style lang="stylus">
<style lang="stylus" scoped>
@import "../../../static/css/variables.styl"
.wechat
margin 0 auto
......
......@@ -43,6 +43,8 @@ export const constantRouterMap = [
meta: {
title: '全部客户',
keepAlive: true,
componentName: 'allCustomersList',
fromPath: ['/customerDetail'],
},
},
{
......@@ -127,16 +129,29 @@ export const constantRouterMap = [
},
{
path: '/frozenList',
component: _import('wechatmembers', 'frozenList'),
component: _import('wechatmembers', 'frozen-member/frozen-list/frozen-list'),
meta: {
title: '冻结会员列表',
componentName: 'forzenlist',
fromPath: ['/customerDetail','/frozenWhiteList','/frozenList/frozenMember'],
},
},
{
path: '/frozenWhiteList',
component: _import('wechatmembers', 'frozen-member/white-list/white-list'),
meta: {
title: '冻结会员白名单',
componentName: 'frozenMemberWhiteList',
fromPath: ['/customerDetail'],
},
},
{
path: '/frozenList/frozenMember',
component: _import('wechatmembers', 'frozenMember'),
component: _import('wechatmembers', 'frozen-member/frozen-member/frozen-member'),
meta: {
title: '冻结会员',
componentName: 'frozen-member',
fromPath: ['/customerDetail'],
},
},
{
......@@ -319,9 +334,19 @@ export const constantRouterMap = [
{
path: '/abnormal-member',
name: '/abnormal-member',
component: _import('wechatmembers', 'abnormal-member'),
component: _import('wechatmembers', 'abnormal-member/abnormal-member-list/abnormal-member'),
meta: {
title: '异常会员列表',
componentName: 'abnormal-member-list',
fromPath: ['/abnormal-setting','/customerDetail'],
},
},
{
path: '/abnormal-setting',
name: '/abnormal-setting',
component: _import('wechatmembers', 'abnormal-member/abnormal-setting/abnormal-setting'),
meta: {
title: '异常会员配置',
},
},
{
......
<template>
<div class="test-com">
<h1 class="txt">{{msg}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
msg: 'hello'
};
}
};
</script>
<template>
<div>
<div class="filter-list">
<el-select v-model="cardType" style="width: 200px;" placeholder="卡券类型" clearable @change="handleChange">
<el-option
v-for="item in cardOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
<el-input v-model="cardName" style="width: 200px; margin-left: 20px;" clear placeholder="输入卡券名称" @keyup.native.enter="handleSearch"></el-input>
</div>
<el-table
ref="multipleTable"
:data="cardData"
class="card-table"
tooltip-effect="dark"
style="width: 100%"
@row-click="handleCurrentChangeRow"
>
<el-table-column label width="55">
<template slot-scope="scope">
<el-radio class="radio-style" :label="scope.row.integralMallProId" v-model="radio">&nbsp;</el-radio>
</template>
</el-table-column>
<el-table-column label="卡券名称" prop="cardName" >
</el-table-column>
<el-table-column prop="proSubName" label="备注名"></el-table-column>
<el-table-column prop="integralCost" label="兑换限制"></el-table-column>
<el-table-column prop="virtualStock" label="库存"></el-table-column>
</el-table>
<div class="pagination" v-if="total>0">
<dm-pagination
@current-change="cardCurrentChange"
:current-page="cardCurrentPage"
small
:page-size="cardPageSize"
layout="prev, pager, next"
:total="total"
></dm-pagination>
</div>
</div>
</template>
<script>
export default {
name: "card-list",
props: {
pname: String
},
data() {
return {
cardType: null, // 卡券类型
cardOptions: [
{ value: 1, label: '折扣券' },
{ value: 0, label: '抵金券' }
],
cardName: '',
radio: null,
cardCurrentPage: 1,
cardPageSize: 5,
cardLimitType: 1,
cardData: [],
total: 0
};
},
methods: {
// 当某行点击的时候
handleCurrentChangeRow(row) {
this.$nextTick(_ => {
// if (row.integralMallProId == this.radio) {
this.$emit('pass-id', row);
// }
});
},
getCardList() {
var param = {
currentPage: this.cardCurrentPage,
pageSize: this.cardPageSize,
requestProject: this.pname,
cardType: this.cardType,
proName: this.cardName
};
this.axios
.get(this.baseUrl + "/api-integral-mall/page-cards-plug", {params: param})
.then(res => {
const resData = res.data;
if (resData.errorCode == 0) {
if (!!resData.result) {
if (!!resData.result.rows) {
this.cardData = resData.result.rows;
} else {
this.cardData = [];
}
this.total = resData.result.total;
}
} else {
this.$message.error({ duration: 1000, message: resData.message });
}
})
.catch(error => {
this.$message.error({
duration: 10000,
message: error.message
});
});
},
// 当前切换分页
cardCurrentChange(val) {
this.cardCurrentPage = val;
this.getCardList();
},
handleChange(val) {
this.cardCurrentPage = 1;
this.getCardList();
},
handleSearch() {
this.cardCurrentPage = 1;
this.getCardList();
}
},
created() {
const host = window.location.origin;
this.baseUrl = host.indexOf("localhost") > -1 ? 'http://www.gicdev.com' : host;
},
mounted() {
this.getCardList();
}
};
</script>
<style scoped>
.filter-list {
margin-bottom: 10px;
}
.pagination {
text-align: right;
margin-top: 10px;
}
</style>
<template>
<div class="gift-list">
<div class="links-tools-row">
<el-select
v-model="giftVal"
style="width: 200px;"
placeholder="礼品类型"
clearable
@change="handleChange"
>
<el-option
v-for="item in giftOptions"
:key="item.integralMallCategoryId"
:label="item.categoryName"
:value="item.integralMallCategoryId"
></el-option>
</el-select>
<el-input
v-model="giftName"
style="width: 200px; margin-left: 20px;"
placeholder="输入礼品名称"
@keyup.native.enter="handleSearch"
></el-input>
</div>
<div class="goods-link-content">
<ul class="goods-link-list">
<li
class="goods-link-item"
v-for="(item, index) in goodsList"
:key="index"
:class="activeIndex == index ? 'good-highlight' : ''"
@click="selectGoodLinkItem(item, index)"
>
<img
:src="item.mainImageUrl"
class="img"
alt="商品图片"
>
<div class="inline-block goods-message">
<p class="limit-2 pro-name">{{item.proName}}</p>
<p class="gray-color pro-code pro-name">所需积分:{{item.integralCost}}</p>
<p class="pro-price pro-name">所需现金:{{item.cashCost}}</p>
</div>
</li>
</ul>
</div>
<div
class="links-tools-page"
v-if="total > 0"
>
<dm-pagination
@current-change="handleChangePage"
:current-page="currentPage"
:page-size="pageSize"
layout="prev, pager, next"
:total="total"
></dm-pagination>
</div>
</div>
</template>
<script>
import qs from "qs";
export default {
name: "gift-list",
props: {
pname: String
},
data() {
return {
currentPage: 1,
activeIndex: -1,
pageSize: 6,
total: 0,
giftVal: null,
giftOptions: [],
goodsList: [],
giftName: ""
};
},
created() {
const host = window.location.origin;
this.baseUrl = host.indexOf("localhost") > -1 ? 'http://www.gicdev.com' : host;
},
methods: {
// 分类
getGiftList() {
this.axios
.get(
`${
this.baseUrl
}/api-integral-mall/load-category?requestProject=gic-web`
)
.then(res => {
const resData = res.data;
if (resData.errorCode === 0) {
if (!!resData.result && resData.result.length) {
this.giftOptions = resData.result;
}
}
});
},
// 分页换页
handleChangePage(val) {
this.currentPage = val;
this.getData();
},
handleChange() {
this.currentPage = 1;
this.getData();
},
// 分页数据 integralCost积分费用 cashCost现金费用 proName
getData() {
const params = {
requestProject: "gic-web",
currentPage: this.currentPage,
pageSize: this.pageSize,
category: this.giftVal,
giftName: this.giftName,
changeType: -1,
releaseType: -1,
showStatus: 1,
porHot: -1
};
this.axios
.post(
`${this.baseUrl}/api-integral-mall/page-gift`,
qs.stringify(params)
)
.then(res => {
const data = res.data;
if (data.errorCode == 0) {
if (!!data.result && data.result.rows) {
this.goodsList = data.result.rows;
}
this.total = data.result.total || 0;
}
});
},
selectGoodLinkItem(item, i) {
this.activeIndex = i;
this.$emit("pass-gift", item);
},
handleSearch() {
this.currentPage = 1;
this.getData();
}
},
mounted() {
this.getGiftList();
this.getData();
}
};
</script>
<style scoped>
.links-tools-row {
margin-bottom: 10px;
}
.links-tools-row .goods-link-item {
display: inline-block;
vertical-align: middle;
width: 307px;
padding: 8px;
margin-right: 7px;
margin-bottom: 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
box-sizing: border-box;
}
.links-tools-row .goods-link-item .img {
display: inline-block;
vertical-align: middle;
width: 80px;
height: 80px;
}
.links-tools-page {
text-align: right;
}
.links-tools-row .goods-link-item:hover {
cursor: pointer;
border-color: #2F54EB;
}
.links-tools-row .goods-link-item .goods-message {
margin-left: 10px;
padding: 5px;
width: 198px;
box-sizing: border-box;
font-size: 12px;
}
.links-tools-row .good-highlight {
border-color: #2F54EB;
}
.goods-link-item .goods-message .pro-name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
margin: 8px 0;
}
</style>
<template>
<div class="plug-sg">
<el-popover
popper-class="plug-sg__popover"
placement="bottom"
trigger="click"
v-model="treeVis"
>
<el-input
slot="reference"
suffix-icon="el-icon-arrow-down"
v-model="ategory"
placeholder="所有分类"
></el-input>
<el-tree
class="plug-sg__tree"
ref="tree"
:default-expand-all="true"
node-key="mallProTagId"
:data="treeData"
:props="defaultProps"
:highlight-current="true"
@node-click="handleNodeClick"
>
</el-tree>
<div class="good-tree-btn">
<el-button
@click.prevent.stop="hideTree"
type="text"
size="small"
style="color:#303133"
>取消</el-button>
<el-button
@click.prevent.stop="confirmBtn"
type="text"
size="small"
>确定</el-button>
</div>
</el-popover>
</div>
</template>
<script>
export default {
name: "goods-tree",
props: {
model: {
type: Object,
default() {
return {};
}
},
width: {
type: String,
default: "300"
},
treeData: Array
},
data() {
return {
treeVis: false,
ategory: "",
defaultProps: {
children: "childrenList",
label: "tagName"
}
};
},
methods: {
handleNodeClick(data) {
this.mallData = data;
this.ategory = data.tagName;
},
hideTree() {
this.treeVis = false;
},
confirmBtn() {
this.treeVis = false;
}
},
watch: {
treeVis(newval) {
if (!newval) {
本身是确保确定之后才传值出去
if (this.mallData) {
this.$emit("pass-mall", this.mallData);
}
}
}
}
};
</script>
<style lang="scss">
.plug-sg {
display: inline-block;
width: 200px;
&__popover {
padding: 10px 0 0 0;
}
&__btn {
height: 36px;
padding: 0 10px;
border-top: 1px solid #ebeef5;
line-height: 34px;
text-align: right;
&--cancel {
color: #606266;
}
}
&__tree {
height: 260px;
width: 200px;
overflow-y: auto;
.el-tree-node__label {
text-overflow: ellipsis;
display: inline-block;
white-space: nowrap;
width: 100%;
overflow: hidden;
}
&::-webkit-scrollbar {
width: 0px;
height: 0px;
}
}
}
.good-tree-btn {
float: right;
margin-right: 10px;
}
</style>
export function hasClass(el, cls) {
if (!el || !cls) return false;
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
if (el.classList) {
return el.classList.contains(cls);
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
}
/* istanbul ignore next */
export function addClass(el, cls) {
if (!el) return;
let curClass = el.className;
let classes = (cls || '').split(' ');
for (let i = 0, j = classes.length; i < j; i++) {
let clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.add(clsName);
} else if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
if (!el.classList) {
el.className = curClass;
}
}
/* istanbul ignore next */
export function removeClass(el, cls) {
let i = 0;
let j;
let clsName;
if (!el || !cls) return;
let classes = cls.split(' ');
let curClass = ' ' + el.className + ' ';
for (i, j = classes.length; i < j; i++) {
clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.remove(clsName);
} else if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
if (!el.classList) {
el.className = curClass;
}
}
// 向下查找
function broadcast(componentName, eventName, params) {
this.$children.forEach(child => {
const name = child.$options.name;
if (name === componentName) {
child.$emit.apply(child, [eventName].concat([params]));
} else {
broadcast.apply(child, [componentName, eventName].concat([params]));
}
});
}
// 向上查找组件
export default {
methods: {
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName, params]);
}
},
broadcast(componentName, eventName, params) {
broadcast.call(this, componentName, eventName, params);
},
findComponentUpward(context, componentName) {
let parent = context.$parent;
let name = parent.$options.name;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
return parent;
}
// findAnyComponent(componentName, root = null) {
// if (!root) {
// root = this.$root;
// }
// const childrens = root.$children;
// let children = null;
// if (childrens.length) {
// for (const child of childrens) {
// const name = child.$options.name;
// if (name === componentName) {
// children = child;
// break;
// } else {
// children = findAnyComponent.call(this, componentName, child);
// if (children) break;
// }
// }
// }
// return children;
// }
}
};
export function debounce(func, wait) {
let timeout;
return function(...args) {
let that = this;
clearTimeout(timeout);
timeout = setTimeout(_ => {
func.apply(that, args);
}, wait);
};
}
export function throttle(func, wait) {
let timeout;
// let previous = 0; // 时间戳
return function(...args) {
let that = this;
if (!timeout) {
timeout = setTimeout(_ => {
timeout = null;
func.apply(that, args);
}, wait);
}
};
}
<template>
<li :class="classes">
<span> {{ data.categoryName }} </span>
<i v-if="showArrow" class="el-icon-arrow-right fr"></i>
</li>
</template>
<script>
export default {
name: 'Casitem',
props: {
data: Object,
tmpItem: Object
},
computed: {
classes() {
return [
`cascader-menu__item`,
{
[`cascader-menu__item--extensible`]: this.data && this.data.isChildren,
[`is-active`]: this.tmpItem.categoryName === this.data.categoryName
}
];
},
showArrow() {
return this.data.isChildren;
}
},
watch: {
tmpItem(val) {
},
data(newval) {
}
}
};
</script>
<style lang="less" scoped>
.cascader-menu__item {
font-size: 14px;
padding: 8px 20px;
width: 152px;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #606266;
height: 34px;
line-height: 1.5;
box-sizing: border-box;
cursor: pointer;
outline: none;
&:hover {
color: #2F54EB;
}
.fr {
position: absolute;
font-size: 12px;
right: 15px;
top: 50%;
margin-top: -6px;
}
}
.is-active {
color: #2F54EB;
}
</style>
<template>
<div class="caspanel-box">
<span class="ate-keys-box">
<el-input placeholder="搜索关键字" prefix-icon="el-icon-search" v-model="keys" @keyup.native.enter="handleEnter($event)"> </el-input>
</span>
<div class="casitem-box">
<ul v-if="data && data.length" class="casitem-ul">
<Casitem v-for="(item, i) in data" :key="i" :data="item" :tmp-item="tmpItem" @click.native.stop="handleClickItem(item)" @dblclick.native.stop="handleDbClickItem(item)"> </Casitem>
</ul>
</div>
<Caspanel v-if="sublist && sublist.length" :data="sublist" :middle="sublist" :change-on-select="changeOnSelect"></Caspanel>
</div>
</template>
<script>
import Casitem from './casitem';
import Emitter from '../assist/emitter';
import { baseUrl } from '@/config/index.js';
let key = 1;
export default {
name: 'Caspanel',
components: {
Casitem
},
mixins: [Emitter],
props: {
data: {
type: Array,
default() {
return [];
}
},
middle: {
type: Array,
default() {
return [];
}
},
changeOnSelect: Boolean
},
data() {
return {
tmpItem: {},
result: [],
sublist: [],
keys: ''
};
},
methods: {
//
handleEnter(eve) {
let value = eve.target.value;
console.log(this.middle);
this.data = this.middle.filter(el => el.categoryName.indexOf(value) > -1);
},
handleClickItem(item) {
this.tmpItem = Object.assign({}, item);
this.getNextData(item.categoryId);
},
// 双击
handleDbClickItem(item) {
const goodItem = this.findComponentUpward(this, 'gooditem');
item.index = goodItem.goodsIndex;
const tags = Object.assign({}, item);
// 拿到tags比较是否有重复的id
const ategory = this.findComponentUpward(this, 'goods-ategory');
const Tags = ategory.tags;
let hasTag;
if (Tags && Tags.length) {
hasTag = Tags.findIndex(tag => {
return tag.categoryId === item.categoryId;
});
}
if (hasTag != void 0 && hasTag != -1) {
this.$message({
message: '已存在改品类,不能重复添加',
type: 'warning'
});
} else {
this.dispatch('vue-gic-goods-selector', 'handle-ategory', tags);
}
},
// 查找下级
getNextData(id) {
this.axios
.get(`${baseUrl}/api-mall/list-mall-goods-children-category?requestProject=mall&categoryId=${id}`)
.then(res => {
if (res.data.errorCode === 0) {
const data = res.data.result;
if (data && data.length) {
this.sublist = data;
} else if (data && data.length == 0) {
this.sublist = [];
}
} else {
// 占位
}
})
.catch(err => {
console.log(err);
});
},
getKey() {
return key++;
}
}
};
</script>
<style lang="less" scoped>
.caspanel-box {
position: relative;
display: inline-block;
vertical-align: top;
height: 240px;
.ate-keys-box {
display: inline-block;
height: 32px;
width: 138px;
padding: 8px 10px;
border: 1px solid #e8eaec;
border-bottom: none;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
background-color: #f5f7fa;
box-sizing: content-box;
}
.casitem-box {
position: absolute;
border: 1px solid #e8eaec;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
border-top: none;
background-color: #fff;
.casitem-ul {
display: inline-block;
vertical-align: top;
width: 158px;
height: 190px;
list-style: none;
margin: 0;
overflow: auto;
}
}
.caspanel-box {
position: absolute;
margin-left: 12px;
}
}
</style>
<template>
<transition name="transition-drop">
<div class="gic-caspanel">
<Caspanel :data="data" ref="caspanel" :middle="middle" :change-on-select="changeOnSelect"> </Caspanel>
</div>
</transition>
</template>
<script>
import Caspanel from './caspanel';
export default {
name: 'cascader',
components: {
Caspanel
},
props: {
data: {
type: Array,
default() {
return [];
}
},
middle: {
type: Array,
default() {
return [];
}
},
changeOnSelect: {
type: Boolean,
default: false
}
},
data() {
return {
// 占位
};
}
};
</script>
<style lang="less" scoped>
.gic-caspanel {
height: 240px;
padding-bottom: 12px;
overflow-x: auto;
overflow-y: hidden;
font-size: 0px;
}
</style>
import { addClass, removeClass } from './assist/dom';
const Transition = {
beforeEnter(el) {
addClass(el, 'collapse-transition');
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.style.height = '0';
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow;
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
} else {
el.style.height = '';
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
el.style.overflow = 'hidden';
},
afterEnter(el) {
// for safari: remove class then reset height is necessary
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {};
el.dataset.oldPaddingTop = el.style.paddingTop;
el.dataset.oldPaddingBottom = el.style.paddingBottom;
el.dataset.oldOverflow = el.style.overflow;
el.style.height = el.scrollHeight + 'px';
el.style.overflow = 'hidden';
},
leave(el) {
if (el.scrollHeight !== 0) {
// for safari: add class after set height, or it will jump to zero height suddenly, weired
addClass(el, 'collapse-transition');
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
}
},
afterLeave(el) {
removeClass(el, 'collapse-transition');
el.style.height = '';
el.style.overflow = el.dataset.oldOverflow;
el.style.paddingTop = el.dataset.oldPaddingTop;
el.style.paddingBottom = el.dataset.oldPaddingBottom;
}
};
export default {
name: 'ElCollapseTransition',
functional: true,
render(h, { children }) {
const data = {
on: Transition
};
return h('transition', data, children);
}
};
<template>
<div class="complex-info">
<div class="complex-items" v-for="(item, i) in abbrInfos" :key="i">
<complex-item :data="item"></complex-item>
<strong class="complex-and" v-if="abbrInfos[i + 1] && abbrInfos[i + 1].length">并且</strong>
</div>
</div>
</template>
<script>
import ComplexItem from './complex-item';
export default {
name: 'complex-info',
props: {
complexData: Array
},
components: {
ComplexItem
},
computed: {
},
watch: {
complexData: {
immediate: true,
handler(newval) {
this.abbrInfos = newval;
}
}
},
data() {
return {
abbrInfos: []
};
}
};
</script>
<style lang="less" scoped>
.complex-items {
.complex-and {
display: inline-block;
margin: 10px 0;
padding: 10px 20px;
color: #64666a;
border-radius: 20px;
background-color: #e2e2e2;
}
}
</style>
<template>
<!-- 缩略信息递归组件的一部分 -->
<div class="complex-item">
<div class="selector-item-txt" v-for="(item, i) in items" :key="i">
<span class="condition" v-if="item.optName"> {{ item.optName }}</span>
<div class="txt">
{{ item.typeName }}{{ item.belong }}
<div class="child-name" v-if="item.childNames.length">
<span v-for="(child, index) in item.childNames" :key="index">
{{ child || '' }}
</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'complex-item',
props: {
data: Array
},
watch: {
data: {
immediate: true,
handler(newval) {
this.items = newval;
}
}
},
data() {
return {
items: []
};
}
};
</script>
<style lang="less" scoped>
.complex-item {
.selector-item-txt {
display: inline-block;
vertical-align: middle;
.txt {
display: inline-block;
padding: 5px 10px;
font-size: 12px;
color: #8d8d8d;
background-color: #f5f7fa;
border-radius: 5px;
.child-name {
display: inline-block;
}
}
.condition {
display: inline-block;
vertical-align: middle;
margin: 0 5px;
font-size: 12px;
}
}
}
</style>
const host = window.location.origin;
export const baseUrl = host.('localhost') ? 'http://www.gicdev.com' : host;
<template>
<li class="good-item">
<el-checkbox v-model="item.check"></el-checkbox>
<div class="good-info">
<img :src="item.img" />
<p>{{ item.name }}</p>
<p>{{ item.code }}</p>
</div>
<span class="price"> {{ item.price }} </span>
<span class="store"> {{ item.store }} </span>
</li>
</template>
<script>
export default {
name: 'GoodFilterItem',
props: {
goods: Object
},
data() {
return {
item: {}
};
},
watch: {
goods: {
immediate: true,
handler(newval) {
this.item = newval;
}
}
}
};
</script>
<template>
<div class="goods-ategory">
<div class="check-title">
<div class="ategory-lists">
<span class="ate-txt" v-if="!tags.length">下方选择品类</span>
<el-tag v-for="tag in tags" size="small" :key="tag.categoryId" closable @close="handleClose(tag)"> {{ tag.categoryName }} </el-tag>
<el-popover placement="top" width="320" trigger="hover" popper-class="selector-popper">
<el-tag class="dm-pop-tag" v-for="tag in tags" size="small" :key="tag.categoryId" closable @close="handleClose(tag)"> {{ tag.categoryName }} </el-tag>
<span class="pop-tips" slot="reference">{{ tags.length }}</span>
</el-popover>
</div>
</div>
<div class="ate-group">
<Cascader :data="ateData" :middle="middle"></Cascader>
</div>
<slot></slot>
</div>
</template>
<script>
import Cascader from './cascader';
import { baseUrl } from '@/config/index.js';
export default {
name: 'goods-ategory',
components: {
Cascader
},
props: {
tags: {
type: Array,
default() {
return [];
}
}
},
data() {
return {
ateData: [{}],
middle: [{}]
};
},
methods: {
getData() {
this.axios
.get(`${baseUrl}/api-mall/list-mall-goods-all-category?requestProject=mall`)
.then(res => {
if (res.data.errorCode == 0) {
const data = res.data.result;
if (data && data.length) {
this.ateData = data;
this.middle = data;
console.log(this.middle);
}
} else {
// 占位
}
})
.catch(err => {
console.log(err);
});
},
handleClose(tag) {
let index = this.tags.findIndex(t => {
return t.categoryId === tag.categoryId;
});
if (index != -1) {
this.tags.splice(index, 1);
}
}
},
created() {
this.getData();
}
};
</script>
<style lang="less" scoped>
.goods-ategory {
.check-title {
height: 48px;
line-height: 48px;
background-color: #ebeef5;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
overflow: hidden;
}
.ategory-lists {
position: relative;
overflow: hidden;
white-space: nowrap;
margin: 7px 20px;
padding: 2px 10px;
height: 32px;
line-height: 24px;
font-size: 0px;
border: 1px solid #dcdfe6;
border-radius: 5px;
box-sizing: border-box;
background-color: #fff;
.ate-txt {
font-size: 14px;
color: #c0c4cc;
}
.pop-tips {
position: absolute;
top: 0;
right: 0;
height: 32px;
line-height: 32px;
width: 70px;
text-align: center;
font-size: 14px;
color: #606266;
background-color: rgba(255, 255, 255, 1);
}
}
.ate-group {
padding: 10px 12px;
overflow-x: scroll;
}
}
.el-tag + .el-tag {
margin-left: 10px;
}
.dm-pop-tag {
margin-right: 10px;
margin-bottom: 5px;
}
.dm-pop-tag + .dm-pop-tag {
margin-left: 0px;
}
</style>
<template>
<div class="goods-brand">
<div class="check-title">
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全部选择</el-checkbox>
</div>
<el-checkbox-group v-model="checkedBrandes" @change="handleCheckedBrandChange" class="brand-group">
<el-checkbox v-for="brand in brandes" :key="brand.brandId" :label="brand.brandId" class="brand-list">{{ brand.brandName }}</el-checkbox>
</el-checkbox-group>
<slot></slot>
</div>
</template>
<script>
import ElCollapseTransition from './collapse-transition';
import Emitter from './assist/emitter';
import { baseUrl } from '@/config/index.js';
// 品牌
export default {
name: 'goods-brand',
mixins: [Emitter],
components: {
ElCollapseTransition
},
props: {
goodsBrands: Array,
goodsIndex: Array
},
data() {
return {
isIndeterminate: false,
checkAll: false,
checkedBrandes: [],
brandes: []
};
},
methods: {
// 全选
handleCheckAllChange(val) {
this.checkedBrandes = val ? this.brandes : [];
this.isIndeterminate = false;
},
// 复选框多选
handleCheckedBrandChange(val) {
let checkCount = val.length;
this.checkAll = checkCount === this.brandes.length;
this.isIndeterminate = checkCount > 0 && checkCount < this.brandes.length;
},
getBrandList() {
const param = {
currentPage: 1,
pageSize: 20
};
this.axios
.get(`${baseUrl}/api-goods/brandlist?requestProject=goods`, {
params: param
})
.then(res => {
let data;
if (res.data.errorCode === 0) {
data = res.data.result;
this.brandes = data.result;
// 如果超过了20条 totalCount 是总数 根据总数来判断是否还要继续展示第二页的 并不适合全选
} else {
this.$message.error(res.data.message);
}
})
.catch(err => {
this.$message.error(err);
});
}
},
beforeMount() {
// 获取品牌列表
this.getBrandList();
},
watch: {
goodsBrands: {
immediate: true,
handler(newval) {
this.checkedBrandes = newval;
}
},
checkedBrandes(newval) {
this.dispatch('vue-gic-goods-selector', 'pass-checkbox', {
index: this.goodsIndex,
items: newval
});
}
}
};
</script>
<style lang="scss" scoped>
.goods-box {
.check-title {
height: 48px;
line-height: 48px;
padding-left: 20px;
background-color: #ebeef5;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
.brand-group {
padding: 10px 20px;
}
.brand-list {
line-height: 30px;
margin-left: 0;
margin-right: 10px;
}
}
.bounce-enter-active {
animation: bounce-in .5s;
}
.bounce-leave-active {
animation: bounce-in .5s reverse;
}
@keyframes bounce-in {
0% {
transform: scale(0);
}
50% {
transform: scale(1.5);
}
100% {
transform: scale(1);
}
}
</style>
<template>
<div class="collection">
<div class="coll-options" v-if="goodIndex[1] <= 3">
<el-radio-group v-model="bindCondition" @change="handleChange">
<el-radio :disabled="disabled" :label="0">并且</el-radio>
<el-radio :disabled="disabled" :label="1">或者</el-radio>
<el-radio :disabled="disabled" :label="2">剔除</el-radio>
</el-radio-group>
</div>
<div class="coll-options" v-else></div>
<div class="oper-btn">
<el-popover placement="top" width="150" trigger="click" v-model="visiable">
<el-radio-group v-model="goodOption" class="pop-options">
<el-radio :label="1" class="pop-goodlist">商品品牌</el-radio>
<el-radio :label="2" class="pop-goodlist">商品品类</el-radio>
<el-radio :label="3" class="pop-goodlist">商品规格</el-radio>
<el-radio :label="4" class="pop-goodlist">商品属性</el-radio>
<el-radio :label="5" class="pop-goodlist">部分商品</el-radio>
</el-radio-group>
<div class="insert-dir">
<el-button type="text" @click="insertUpward">上方插入</el-button>
<el-button type="text" @click="insertUpdown">下方插入</el-button>
</div>
<el-button type="text" class="button-txt" slot="reference" :disabled="length == 5">插入条件</el-button>
</el-popover>
<span class="cut-line">|</span>
<el-button type="text" class="button-txt" @click="deleteCondition">删除</el-button>
</div>
</div>
</template>
<script>
import Emitter from './assist/emitter';
// 集合条件 并且 或者 剔除
export default {
name: 'goods-collection',
props: {
disabled: Boolean,
goodIndex: Array,
length: Number,
condition: Number
},
mixins: [Emitter],
data() {
return {
bindCondition: '',
goodOption: 1, // 插入的商品
visiable: false
};
},
methods: {
deleteCondition() {
// 触发selector 组件去删除
this.dispatch('vue-gic-goods-selector', 'delete-gooditem', this.goodIndex);
},
handleChange(val) {
this.dispatch('vue-gic-goods-selector', 'pass-radioGroup', { index: this.goodIndex, val: this.bindCondition });
},
insertUpward() {
this.dispatch('vue-gic-goods-selector', 'insert-uselector', { index: this.goodIndex, type: parseInt(this.goodOption, 10) });
this.visiable = false;
},
insertUpdown() {
this.dispatch('vue-gic-goods-selector', 'insert-dselector', { index: this.goodIndex, type: parseInt(this.goodOption, 10) });
this.visiable = false;
}
},
watch: {
condition: {
immediate: true,
handler(val) {
this.bindCondition = val;
}
}
}
};
</script>
<style lang="less" scoped>
.collection {
margin-left: 20px;
margin-right: 20px;
padding-top: 10px;
border-top: 1px dashed #dcdfe6;
display: flex;
justify-content: space-between;
.coll-options {
display: inline-block;
}
.oper-btn {
display: inline-block;
text-align: right;
.cut-line {
color: #dcdfe6;
}
}
}
.pop-options {
text-align: center;
.pop-goodlist {
margin-left: 0;
line-height: 26px;
}
}
.insert-dir {
border-top: 1px solid #dcdfe6;
padding-top: 10px;
text-align: center;
}
.button-txt {
color: #a4a7aa;
&:hover {
color: #2F54EB;
}
}
</style>
import GoodsBrand from './goods-brand'; // 商品品牌
import GoodsAtegory from './goods-ategory'; // 商品品类
import GoodsSpecifications from './goods-specifications'; // 规格
import GoodsSome from './goods-some'; // 部分商品
import GoodsProperties from './goods-properties'; // 商品属性
import ElCollapseTransition from './collapse-transition';
export default {
name: 'gooditem',
components: {
GoodsBrand,
GoodsAtegory,
GoodsSpecifications,
GoodsSome,
GoodsProperties,
ElCollapseTransition
},
props: {
type: {
type: String,
validator: val => ['brand', 'ategory', 'specifications', 'properties', 'some'].indexOf(val) > -1
},
goodsIndex: Array,
tags: Array,
goodsBrands: Array
},
data() {
return {};
},
render(h) {
// 定义五种类型
const slotVal = this.$slots.default;
const type = this.type;
let FinalComponent;
// 扩展的属性
const goodsData = {
props: {
tags: this.tags,
'goods-brands': this.goodsBrands,
'goods-index': this.goodsIndex
}
};
if (type == 'brand') {
// 品牌
FinalComponent = <goods-brand {...goodsData}>{slotVal}</goods-brand>;
} else if (type == 'ategory') {
// 品类
FinalComponent = <goods-ategory {...goodsData}>{slotVal}</goods-ategory>;
} else if (type == 'specifications') {
// 规格
FinalComponent = <goods-specifications {...goodsData}>{slotVal}</goods-specifications>;
} else if (type == 'properties') {
// 属性
FinalComponent = <goods-properties {...goodsData}>{slotVal}</goods-properties>;
} else if (type == 'some') {
// 部分商品
FinalComponent = <goods-some {...goodsData}>{slotVal}</goods-some>;
}
return <el-collapse-transition>{FinalComponent}</el-collapse-transition>;
}
};
<template>
<div class="goods-properties">
<div class="check-title">
选择属性
<load-select v-model="propVal" @scrollload="loadMore" :load="load" @change-load="changeLoad">
<gic-load-item v-for="item in propOptions" :key="item.propertyId" :value="item.propertyId" :label="item.propertyName" @pass-item="resiver"> </gic-load-item>
</load-select>
<!-- 多选有 包含其一 和 包含所有-->
<!-- <el-select v-model="exclude" placeholder="请选择" style="width: 120px" v-if="propType === 'TYP_CHECK'">
<el-option
v-for="item in excludeOption"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select> -->
</div>
<div class="prop-content">
<!-- 单选 属性勾选 TYP_SINGLE -->
<!-- v-if="propType === 'TYP_SINGLE' || propType === 'TYP_CHECK'" -->
<div v-if="propType === 'TYP_SINGLE' || propType === 'TYP_CHECK'" class="prop-type">
<el-checkbox :indeterminate="isIndeterminate" v-model="propList.checkAll" @change="handleCheckAllChange">全选</el-checkbox>
<div class="box-group">
<el-checkbox-group v-model="checkedSpes" @change="handleCheckedSpesChange">
<el-checkbox v-for="spe in spes" class="dm-checkbox" :label="spe.propertyId" :key="spe.propertyId">
{{ spe.valueName }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
<!-- 文本 关键字搜索 -->
<!-- <div v-if="propType === 'TYP_TEXT'" class="prop-type">关键字搜索:<el-input v-model="propList.text" style="width: 200px;" maxlength="8" placeholder="关键字" clearable></el-input></div> -->
<!-- 整数 没有小数-->
<!-- <div v-if="propType === 'TYP_NUM'" class="prop-type">
<el-select v-model="interval" placeholder="请选择" style="width: 100px">
<el-option v-for="item in intervalOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
<el-input placeholder="请输入" maxlength="8" minlength="1" style="width: 150px" v-model="propList.number"></el-input>
</div> -->
<!-- 实数 有小数-->
<!-- <div v-if="propType === 'TYP_REAL_NUM'" class="prop-type">
<el-select v-model="interval" placeholder="请选择" style="width: 100px;">
<el-option v-for="item in intervalOption" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
<el-input placeholder="请输入" maxlength="8" minlength="1" style="width: 150px;" v-model="propList.rel_num"></el-input>
</div> -->
<!-- 时间 TYP_TIME -->
<!-- <div v-if="propType === 'TYP_TIME'" class="prop-type">
<el-date-picker v-model="propList.Time" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"> </el-date-picker>
</div> -->
</div>
<slot></slot>
</div>
</template>
<script>
import LoadSelect from './load-select';
import GicLoadItem from './load-item';
import Emitter from './assist/emitter';
import { baseUrl } from '@/config/index.js';
// 文本 单选 多选 勾选 整数 实数 货币 时间 百分比
const PROP_TYPE = [
'TYP_TEXT', // 文本
'TYP_SINGLE', // 单选
'TYP_CHECK', // 多选
'TYP_MULTI', // 勾选
'TYP_NUM', // 整数
'TYP_REAL_NUM', // 实数
'TYP_CURRENCY', // 货币
'TYP_TIME', // 时间
'TYP_PERCENT' // 百分比
];
export default {
name: 'goods-properties',
mixins: [Emitter],
props: {
goodsIndex: Array
},
components: {
GicLoadItem,
LoadSelect
},
data() {
return {
propOptions: [],
propVal: [],
checkedSpes: [],
load: false,
currentPage: 1,
spes: [],
interval: null,
isIndeterminate: false,
propType: '',
propList: {
Time: '',
checkAll: false,
number: null,
rel_num: null
}
// intervalOption: [{ label: '>=', value: 0 }, { label: '<=', value: 1 }, { label: '=', value: 2 }]
};
},
watch: {
checkedSpes(newval) {
this.dispatch('vue-gic-goods-selector', 'pass-property', {
index: this.goodsIndex,
items: {
propId: newval,
parentId: this.propertyId,
condition: this.exclude
}
});
},
},
methods: {
loadMore() {
if (this.propOptions.length == (this.currentPage - 1) * 20) {
this.getPropData('success');
} else {
this.load = true;
}
},
changeLoad() {
this.load = false;
},
handleCheckAllChange(val) {
this.checkedSpes = val ? this.spes : [];
this.isIndeterminate = false;
},
handleCheckedSpesChange(value) {
let checkedCount = value.length;
this.propList.checkAll = checkedCount === this.spes.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.spes.length;
},
// 商品属性列表下拉数据
getPropData(suc) {
const param = {
currentPage: this.currentPage,
pageSize: 20
};
this.axios
.get(`${baseUrl}/api-goods/page-property?requestProject=goods`, {
params: param
})
.then(res => {
if (res.data.errorCode === 0) {
let data = res.data.result;
this.propOptions = this.propOptions.concat(data.result);
this.currentPage++;
if (suc == 'success') {
this.load = true;
}
} else {
// this.$message.error(res.data.message);
}
})
.catch(err => {
console.log(err);
// this.$message.error(error);
});
},
resiver(val) {
this.propVal = val;
const item = this.propOptions.find(el => el.propertyName === val);
this.propertyId = item.propertyId;
// propertyType 字段属性类型
const type = PROP_TYPE.find(type => type === item.propertyType);
// 属性类型
if (type) {
this.propType = type;
if (this.propType == 'TYP_SINGLE' || this.propType == 'TYP_CHECK') {
const param = {
currentPage: 1,
pageSize: 20,
propertyId: item.propertyId
};
this.axios
.get(`${baseUrl}/api-goods/page-property-value?requestProject=goods`, {
params: param
})
.then(res => {
if (res.data.errorCode == 0) {
const data = res.data.result;
if (data.result && data.result.length) {
this.spes = data.result;
} else {
this.spes = [];
}
}
})
.catch(err => {
console.log(err);
});
}
// 多选
}
}
},
beforeMount() {
this.getPropData();
},
mounted() {
this.$on('pass-item', this.resiver);
}
};
</script>
<style lang="less" scoped>
.goods-properties {
.check-title {
height: 48px;
line-height: 48px;
padding-left: 20px;
background-color: #ebeef5;
font-size: 14px;
color: #606266;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
.prop-content {
padding: 10px 20px;
.box-group {
margin-top: 10px;
padding-top: 10px;
border-top: 1px dashed #dcdfe6;
}
.prop-type {
color: #606266;
font-size: 14px;
}
}
}
</style>
<template>
<div class="goods-specifications">
<div class="check-title">
选择规格 &nbsp;
<load-select v-model="specvalue" @scrollload="loadMore" :load="load" @change-load="changeLoad">
<gic-load-item v-for="item in speOptions" :key="item.standardId" :value="item.standardId" :label="item.standardName" @pass-item="resiver"> </gic-load-item>
</load-select>
<!-- 规格类型筛选 -->
<div class="spe-type">
<el-radio v-model="speRadio" label="2">通过规格值筛选</el-radio>
<el-radio v-model="speRadio" label="1">通过规格值组筛选</el-radio>
</div>
</div>
<div class="spe-con">
<spes v-if="spesGroup" :list-spes="spesList" :goods-index="goodsIndex"></spes>
<spe-group v-if="spesVal" :list-group="groupList" :goods-index="goodsIndex" @spe-list="speList"></spe-group>
<!-- <spes v-if="spesGroup && speRadio == '1'" :list-spes="spesList" :goods-index="goodsIndex"></spes>
<spe-group v-if="spesVal && speRadio == '2'" :list-group="groupList" :goods-index="goodsIndex"></spe-group> -->
</div>
<slot></slot>
</div>
</template>
<script>
import Emitter from './assist/emitter';
import Spes from './spes';
import SpeGroup from './spe-group';
import LoadSelect from './load-select';
import GicLoadItem from './load-item';
import { baseUrl } from '@/config/index.js';
export default {
name: 'goods-specifications',
mixins: [Emitter],
components: {
Spes,
SpeGroup,
LoadSelect,
GicLoadItem
},
props: {
goodsIndex: Array
},
data() {
return {
spesGroup: false,
spesVal: false,
speOptions: [], // 规格
speRadio: '2',
currentPage: 1,
load: false,
specvalue: '',
spesList: [],
groupList: [] // 规格值 在规格值组里面
};
},
methods: {
speList(list) {
this.dispatch('vue-gic-goods-selector', 'pass-spe-group-list', {
index: this.goodsIndex,
item: list
});
},
loadMore() {
if (this.speOptions.length == (this.currentPage - 1) * 20) {
this.getOptionsData('success');
} else {
this.load = true;
}
},
// 规格查找
getOptionsData(suc) {
const param = {
type: 'TYP_NORMAL',
currentPage: this.currentPage,
pageSize: 20
};
this.axios
.get(`${baseUrl}/api-goods/page-standard?requestProject=goods`, {
params: param
})
.then(res => {
let data;
if (res.data.errorCode === 0) {
data = res.data.result;
this.speOptions = this.speOptions.concat(data.result);
this.currentPage++;
if (suc == 'success') {
this.load = true;
}
} else {
this.$message.error(res.data.message);
}
})
.catch(err => {
this.$message.error(err);
});
},
changeLoad() {
this.load = false;
},
resiver(val) {
// 选中的值
console.log(val);
this.specvalue = val;
this.specList = this.speOptions.find(val => val.standardName == this.specvalue);
if (this.specList && this.specList.standardId) {
this.validateGoods();
}
},
// 查询是规格值还是规格值组
validateGoods() {
this.axios.get(`${baseUrl}/api-goods/validate-standard-pull-data?requestProject=goods&standardId=${this.specList.standardId}`).then(res => {
const data = res.data;
// false是规格值组 true 是规格值
if (data.errorCode === 0) {
if (data.result) {
this.spesGroup = false;
this.spesVal = true;
// this.speRadio = '2';
this.getSpeData();
} else {
this.spesVal = false;
this.spesGroup = true;
// this.speRadio = '1';
this.getSpeGroupData();
}
}
});
},
// 规格值分组数据
getSpeGroupData() {
const param = {
currentPage: 1,
pageSize: 20,
parentId: this.specList.standardId,
type: 'TYP_GROUP',
categoryId: this.specList.gicStandardId
};
this.axios
.get(`${baseUrl}/api-goods/page-standard?requestProject=goods`, {
params: param
})
.then(res => {
if (res.data.errorCode === 0) {
const data = res.data.result;
if (data.result && data.result.length) {
this.spesList = data.result;
} else {
this.spesList = [];
}
}
})
.catch(err => {
console.log(err);
});
},
// 规格值数据
getSpeData() {
const param = {
currentPage: 1,
pageSize: 20,
standardId: this.specList.standardId
};
this.axios
.get(`${baseUrl}/api-goods/page-standard-values?requestProject=goods`, {
params: param
})
.then(res => {
if (res.data.errorCode === 0) {
const data = res.data.result;
if (data.result && data.result.length) {
const middleData = data.result;
this.groupList = middleData;
// this.groupList = middleData.map(el => {
// if (el.standardGroupNames && el.standardGroupNames.length) {
// el.standardGroup = [];
// for (let i = 0; i < el.standardGroupNames.length; i++) {
// el.standardGroup.push({
// valueName: el.standardGroupNames[i],
// valueId: el.standardGroupIds[i]
// });
// }
// }
// return el;
// });
} else {
this.groupList = [];
}
}
})
.catch(err => {
console.log(err);
});
}
},
mounted() {
// this.$on('pass-item', this.resiver);
},
beforeMount() {
this.getOptionsData();
}
};
</script>
<style lang="less" scoped>
.goods-box {
.check-title {
height: 48px;
line-height: 48px;
padding-left: 20px;
font-size: 14px;
background-color: #ebeef5;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
.spe-con {
max-height: 285px;
padding: 10px 20px;
overflow: hidden;
}
.spe-type {
float: right;
margin-right: 20px;
}
}
</style>
import vueGicSelector from './index.vue';
const gicSelector = {
install(Vue, options) {
Vue.component(vueGicSelector.name, vueGicSelector);
}
};
if (typeof window !== 'undefined' && window.Vue) {
window.Vue.use(gicSelector);
}
export default gicSelector;
<template>
<li class="load-item" @click="handleClick">
<slot>
<span>{{ currentLabel }}</span>
</slot>
</li>
</template>
<script>
import Emitter from './assist/emitter';
export default {
name: 'gic-load-item',
mixins: [Emitter],
props: {
value: {
required: true
},
label: [String, Number]
},
computed: {
currentLabel() {
return this.label || this.value;
}
},
methods: {
handleClick() {
this.$emit('pass-item', this.currentLabel);
}
}
};
</script>
<style lang="less" scoped>
.load-item {
height: 24px;
line-height: 24px;
padding: 4px 10px;
cursor: pointer;
color: #606266;
&:hover {
background-color: #f5f7fa;
}
}
</style>
<template>
<el-popover placement="bottom" width="195" trigger="click" v-model="loadShow" popper-class="select-popper">
<ul class="load-ul" @scroll="handleScroll" ref="loadbox">
<slot></slot>
<p class="el-select-dropdown__empty no-data" v-if="isEmpty">
<i class="el-icon-loading"></i>
{{ emptyTxt }}
</p>
</ul>
<div class="load-select" slot="reference">
<el-input placeholder="请选择" v-model="selectLabel" readonly="readonly" :class="{ 'is-focus': visible }" ref="select">
<i slot="suffix" :class="['el-select__caret', 'el-input__icon', 'el-icon-arrow-up' + iconClass]" @click="handleIconClick"> </i>
</el-input>
</div>
</el-popover>
</template>
<script>
import LoadItem from './load-item'; // 加载的item选项
export default {
name: 'load-select',
components: {
LoadItem
},
props: {
value: {
required: true
},
load: {
type: Boolean,
default: false
},
loadover: {
type: Boolean,
default: false
}
},
computed: {
iconClass() {
if (this.visible) {
return ' is-reverse';
} else {
return '';
}
}
},
data() {
return {
readonly: false,
visible: false,
selectLabel: '',
isEmpty: false,
emptyTxt: '',
loadShow: false
};
},
watch: {
load: {
immediate: true,
handler(newval) {
if (newval) {
this.isEmpty = false;
this.$emit('change-load');
// 方案一 加载时候移动一下
// 方案二 价格loadover 标识
this.$refs.loadbox.scrollTop = this.$refs.loadbox.scrollHeight - 250;
}
}
},
value(newval) {
this.selectLabel = newval;
this.loadShow = false;
this.visible = false;
},
loadShow(newval) {
if (newval) {
this.visible = true;
} else {
this.visible = false;
}
}
},
methods: {
handleIconClick() {
this.visible = !this.visible;
},
// 滚动监听
handleScroll(e) {
const ele = e.target;
// scrollHeight 获取元素内容高度
// scrollTop 可以获取或者设置元素的偏移值
// 满足滚到底部和上次加载结束两个条件
if (ele.scrollHeight - ele.scrollTop == 220 && !this.isEmpty) {
// 滚到底部 先加载
this.emptyTxt = '加载中';
this.isEmpty = true;
setTimeout(_ => {
this.$emit('scrollload');
}, 500);
}
}
}
};
</script>
<style lang="less" scoped>
.load-select {
display: inline-block;
width: 200px;
cursor: pointer;
}
.load-ul {
position: relative;
max-height: 200px;
padding-bottom: 20px;
overflow: auto;
.no-data {
padding: 0;
text-align: center;
color: #ccc;
}
}
.el-select__caret {
color: #c0c4cc;
font-size: 14px;
transition: transform 0.3s;
transform: rotateZ(180deg);
cursor: pointer;
}
.el-select__caret.is-reverse {
transform: rotateZ(0deg);
}
</style>
<template>
<div class="sku-filter">
<div class="title">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange" v-if="!skuFlt"></el-checkbox>
<span class="arrow-bottom" v-if="skuFlt"></span>
<span class="good-info">
商品信息
</span>
<el-popover placement="bottom" width="280" trigger="click" v-model="showPopPrice">
<el-input placeholder="最低单价" :minlength="1" :maxlength="6" style="width: 90px;" v-model="lowPrice"></el-input>
<el-input placeholder="最高单价" :minlength="1" :maxlength="6" style="width: 90px;" v-model="mostPrice"></el-input>
&nbsp;
<el-button type="primary" @click="searchGoods">搜索</el-button>
<span class="price" :class="{ 'showpop-price': showPopPrice }" slot="reference" @click="showPopPrice = !showPopPrice">
单价
<i class="icon iconfont icon-shaixuan-shi icon-filter"></i>
</span>
</el-popover>
<el-popover placement="bottom" width="280" trigger="click" v-model="showPopNum">
<el-input placeholder="最低数量" :minlength="1" :maxlength="6" style="width: 90px;" v-model="lowStore"></el-input>
<el-input placeholder="最高数量" :minlength="1" :maxlength="6" style="width: 90px;" v-model="mostStore"></el-input>
&nbsp;
<el-button type="primary" @click="storeSearch">搜索</el-button>
<span class="price store" :class="{ 'showpop-num': showPopNum }" slot="reference" @click="showPopNum = !showPopNum">
库存
<i class="icon iconfont icon-shaixuan-shi icon-filter"></i>
</span>
</el-popover>
</div>
<ul class="goods-sku-lists">
<sku-left-item v-for="(item, i) in items" :key="i" :goods="item" :inx="i" :check="skuFlt" :checkbox.sync="item.check" @changeIndeterminate="handleIndeter"></sku-left-item>
<span class="el-table__empty-text no-data" v-if="!items || !items.length">暂无数据</span>
</ul>
</div>
</template>
<script>
import SkuLeftItem from './sku-left-item';
import { throttle } from './assist/util';
// 正则
const INTEGER_REG = /^[1-9]{1}[0-9]{0,5}$/; // 最小1 最大999999 的整数
export default {
name: 'SkuFilterTable',
components: {
SkuLeftItem
},
props: {
data: Array,
skufilter: Boolean // sku筛选
},
data() {
return {
skuFlt: null,
checkAll: false,
visiable: false,
items: [],
mostPrice: null,
lowPrice: null,
lowStore: null,
mostStore: null,
showPopPrice: false,
showPopNum: false,
isIndeterminate: false,
checkedGoods: [] // 选中的商品
};
},
methods: {
// 处理最低的库存
handleLowStore() {
// 占位
},
// 处理最高的库存
handleMostStore() {
// 占位
},
// item 是勾选的sku信息
resiverSku(val) {
// val里面有个check
if (val.checkAll !== void 0) {
this.$emit('resiverAllSku', {
skus: val.skus,
inx: val.inx,
})
} else {
this.$emit('resiverSku');
}
},
// 单价搜索
searchGoods() {
// 占位
},
// 库存搜索
storeSearch() {
// 占位
},
handleCheckAllChange(val) {
this.items = this.items.map(el => ({
...el,
check: val
}));
this.isIndeterminate = false;
this.$emit('resiverSku', this.items);
},
// 修改checkbox的状态
handleIndeter() {
this.checkedGoods = this.items.filter(el => el.check);
this.checkAll = this.checkedGoods.length === this.items.length;
this.isIndeterminate = this.checkedGoods.length > 0 && this.checkedGoods.length < this.items.length;
},
// 正则限制输入价格和库存
regInput(val) {
if (!INTEGER_REG.test(val)) {
this.$message.warning('单价必须大于0!');
}
}
},
mounted() {
this.$on('passku', this.resiverSku);
// 低价
this.$watch(
'lowPrice',
throttle(newval => {
this.regInput(newval);
}, 500)
);
// 高级
this.$watch(
'mostPrice',
throttle(newval => {
this.regInput(newval);
}, 500)
);
},
watch: {
skufilter: {
immediate: true,
handler(newval) {
this.skuFlt = newval;
}
},
data: {
immediate: true,
handler(newval) {
this.items = newval;
}
},
checkedGoods: {
immediate: true,
handler(newval) {
this.$emit('resiverSku');
}
}
}
};
</script>
<style lang="less" scoped>
.sku-filter {
height: 350px;
padding-bottom: 20px;
.title {
height: 44px;
line-height: 44px;
padding: 0 10px;
font-size: 14px;
background-color: #f5f7fa;
border-top-right-radius: 5px;
border-top-left-radius: 5px;
color: #909399;
.arrow-bottom {
display: inline-block;
vertical-align: middle;
width: 14px;
}
span {
display: inline-block;
text-align: center;
height: 44px;
}
.good-info {
width: 160px;
text-align: left;
padding-left: 10px;
}
.price {
position: relative;
width: 60px;
outline: none;
border: none;
.icon-filter::before {
top: 10px;
}
}
.store {
position: relative;
width: 60px;
}
.showpop-price,
.showpop-num {
background-color: #e3e5eb;
}
}
.goods-sku-lists {
height: 303px;
overflow: auto;
list-style: none;
.no-data {
display: inline-block;
width: 100%;
text-align: center;
font-size: 14px;
}
}
}
</style>
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment