mirror of
https://github.com/crmeb/CRMEB.git
synced 2026-10-29 22:10:49 +00:00
Merge branch 'v5.0.0dev' of https://gitee.com/ZhongBangKeJi/CRMEB into v5.0.0dev
This commit is contained in:
commit
8ba0348f01
@ -148,6 +148,10 @@ class SystemCrudServices extends BaseServices
|
||||
'addSoftDelete',
|
||||
],
|
||||
'form' => [
|
||||
[
|
||||
'value' => '',
|
||||
'label' => '请选择',
|
||||
],
|
||||
[
|
||||
'value' => 'input',
|
||||
'label' => '输入框',
|
||||
|
||||
5
template/admin/package-lock.json
generated
5
template/admin/package-lock.json
generated
@ -23078,6 +23078,11 @@
|
||||
"diff-match-patch": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"vue-cropper": {
|
||||
"version": "0.5.11",
|
||||
"resolved": "https://registry.npmmirror.com/vue-cropper/-/vue-cropper-0.5.11.tgz",
|
||||
"integrity": "sha512-UeA3qL2BLCTGkOEAxEsxSNFO+qLYAn6YRHv4oS32cP9lMhF1vFmnAf/z+ZamtR0/Fh3sbZeZUCLVR2Ol2/dpTQ=="
|
||||
},
|
||||
"vue-eslint-parser": {
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
"vue-awesome-swiper": "^4.1.1",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-codemirror": "^4.0.6",
|
||||
"vue-cropper": "^0.5.11",
|
||||
"vue-happy-scroll": "^2.1.1",
|
||||
"vue-i18n": "^7.8.0",
|
||||
"vue-pickers": "^2.5.3",
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
import request from '@/libs/request';
|
||||
import { getCookies } from '@/libs/util';
|
||||
|
||||
/**
|
||||
* @description 设置 系统设置 应用设置头部
|
||||
@ -1122,3 +1123,17 @@ export function codeCrud(data) {
|
||||
data,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @description 图片上传
|
||||
*/
|
||||
export function fileUpload(data) {
|
||||
return request({
|
||||
url: `file/upload`,
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Authori-zation': 'Bearer ' + getCookies('token'),
|
||||
'content-type': 'multipart/form-data;' + 'Bearer ' + getCookies('token'),
|
||||
},
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
280
template/admin/src/components/cropperImg/index.vue
Normal file
280
template/admin/src/components/cropperImg/index.vue
Normal file
@ -0,0 +1,280 @@
|
||||
<template>
|
||||
<div class="cropper-content">
|
||||
<div class="cropper-box">
|
||||
<div class="cropper">
|
||||
<vue-cropper
|
||||
ref="cropper"
|
||||
:img="option.img"
|
||||
:outputSize="option.outputSize"
|
||||
:outputType="option.outputType"
|
||||
:info="option.info"
|
||||
:canScale="option.canScale"
|
||||
:autoCrop="option.autoCrop"
|
||||
:autoCropWidth="option.autoCropWidth"
|
||||
:autoCropHeight="option.autoCropHeight"
|
||||
:fixed="option.fixed"
|
||||
:fixedNumber="option.fixedNumber"
|
||||
:full="option.full"
|
||||
:fixedBox="option.fixedBox"
|
||||
:canMove="option.canMove"
|
||||
:canMoveBox="option.canMoveBox"
|
||||
:original="option.original"
|
||||
:centerBox="option.centerBox"
|
||||
:height="option.height"
|
||||
:infoTrue="option.infoTrue"
|
||||
:maxImgSize="option.maxImgSize"
|
||||
:enlarge="option.enlarge"
|
||||
:mode="option.mode"
|
||||
@realTime="realTime"
|
||||
@imgLoad="imgLoad"
|
||||
>
|
||||
</vue-cropper>
|
||||
</div>
|
||||
<!--底部操作工具按钮-->
|
||||
<div class="footer-btn">
|
||||
<div class="scope-btn">
|
||||
<input
|
||||
type="file"
|
||||
id="uploads"
|
||||
style="position: absolute; clip: rect(0 0 0 0)"
|
||||
accept="image/png, image/jpeg, image/gif, image/jpg"
|
||||
@change="selectImg($event)"
|
||||
/>
|
||||
<el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
|
||||
<el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
|
||||
<el-button size="mini" type="danger" plain @click="rotateLeft">↺ 左旋转</el-button>
|
||||
<el-button size="mini" type="danger" plain @click="rotateRight">↻ 右旋转</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--预览效果图-->
|
||||
<div class="show-preview">
|
||||
<div class="preview">
|
||||
<img :src="previews.url" :style="previews.img" />
|
||||
</div>
|
||||
<div class="upload-btn">
|
||||
<label class="btn" for="uploads">选择图片</label>
|
||||
<el-button size="mini" type="success" @click="uploadImg()">确认上传</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { VueCropper } from 'vue-cropper';
|
||||
// import { updateAvatar } from ''; //这里为文件上传的接口换成自己的文件
|
||||
import { fileUpload } from '@/api/setting';
|
||||
export default {
|
||||
name: 'CropperImage',
|
||||
components: {
|
||||
VueCropper,
|
||||
},
|
||||
props: ['Name'],
|
||||
data() {
|
||||
return {
|
||||
name: this.Name,
|
||||
resImg: '',
|
||||
previews: {},
|
||||
option: {
|
||||
img: this.Name, //裁剪图片的地址
|
||||
outputSize: 1, //裁剪生成图片的质量(可选0.1 - 1)
|
||||
outputType: 'png', //裁剪生成图片的格式(jpeg || png || webp)
|
||||
info: true, //图片大小信息
|
||||
canScale: true, //图片是否允许滚轮缩放
|
||||
autoCrop: true, //是否默认生成截图框
|
||||
autoCropWidth: 200, //默认生成截图框宽度
|
||||
autoCropHeight: 200, //默认生成截图框高度
|
||||
fixed: false, //是否开启截图框宽高固定比例
|
||||
fixedNumber: [1.53, 1], //截图框的宽高比例
|
||||
full: false, //false按原比例裁切图片,不失真
|
||||
fixedBox: false, //固定截图框大小,不允许改变
|
||||
canMove: true, //上传图片是否可以移动
|
||||
canMoveBox: true, //截图框能否拖动
|
||||
original: false, //上传图片按照原始比例渲染
|
||||
centerBox: true, //截图框是否被限制在图片里面
|
||||
height: false, //是否按照设备的dpr 输出等比例图片
|
||||
infoTrue: false, //true为展示真实输出图片宽高,false展示看到的截图框宽高
|
||||
maxImgSize: 3000, //限制图片最大宽度和高度
|
||||
enlarge: 1, //图片根据截图框输出比例倍数
|
||||
mode: '300px 300px', //图片默认渲染方式
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
//初始化函数
|
||||
imgLoad(msg) {
|
||||
console.log('工具初始化函数=====' + msg);
|
||||
},
|
||||
//图片缩放
|
||||
changeScale(num) {
|
||||
num = num || 1;
|
||||
this.$refs.cropper.changeScale(num);
|
||||
},
|
||||
//向左旋转
|
||||
rotateLeft() {
|
||||
this.$refs.cropper.rotateLeft();
|
||||
},
|
||||
//向右旋转
|
||||
rotateRight() {
|
||||
this.$refs.cropper.rotateRight();
|
||||
},
|
||||
// //实时预览函数
|
||||
realTime(data) {
|
||||
let that = this;
|
||||
that.previews = data;
|
||||
this.$refs.cropper.getCropBlob((data) => {
|
||||
this.blobToDataURI(data, function (res) {
|
||||
that.previewImg = res;
|
||||
});
|
||||
});
|
||||
},
|
||||
blobToDataURI(blob, callback) {
|
||||
var reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onload = function (e) {
|
||||
callback(e.target.result);
|
||||
};
|
||||
},
|
||||
//选择图片
|
||||
selectImg(e) {
|
||||
let file = e.target.files[0];
|
||||
if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
|
||||
this.$message({
|
||||
message: '图片类型要求:jpeg、jpg、png',
|
||||
type: 'error',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
//转化为blob
|
||||
let reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
let data;
|
||||
if (typeof e.target.result === 'object') {
|
||||
data = window.URL.createObjectURL(new Blob([e.target.result]));
|
||||
} else {
|
||||
data = e.target.result;
|
||||
}
|
||||
this.option.img = data;
|
||||
};
|
||||
//转化为base64
|
||||
reader.readAsDataURL(file);
|
||||
},
|
||||
|
||||
base64ImgtoFile(dataurl, filename = 'file') {
|
||||
//将base64格式分割:['data:image/png;base64','XXXX']
|
||||
const arr = dataurl.split(',');
|
||||
// .*? 表示匹配任意字符到下一个符合条件的字符 刚好匹配到:
|
||||
// image/png
|
||||
const mime = arr[0].match(/:(.*?);/)[1]; //image/png
|
||||
//[image,png] 获取图片类型后缀
|
||||
const suffix = mime.split('/')[1]; //png
|
||||
const bstr = atob(arr[1]); //atob() 方法用于解码使用 base-64 编码的字符串
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return new File([u8arr], `${filename}.${suffix}`, {
|
||||
type: mime,
|
||||
});
|
||||
},
|
||||
|
||||
uploadFile(file) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
fileUpload(formData).then((res) => {
|
||||
console.log(res);
|
||||
if (res.status == 200) {
|
||||
this.$emit('uploadImgSuccess', res.data);
|
||||
} else {
|
||||
this.$message({
|
||||
message: '上传失败',
|
||||
type: 'error',
|
||||
duration: 1000,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
//上传图片
|
||||
uploadImg() {
|
||||
this.$refs.cropper.getCropData((data) => {
|
||||
this.resImg = this.base64ImgtoFile(data);
|
||||
this.uploadFile(this.resImg);
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.btn {
|
||||
outline: none;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
-webkit-transition: 0.1s;
|
||||
transition: 0.1s;
|
||||
font-weight: 500;
|
||||
padding: 8px 15px;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
background-color: #409eff;
|
||||
border-color: #409eff;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.cropper-content {
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
justify-content: flex-end;
|
||||
.cropper-box {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
.cropper {
|
||||
width: auto;
|
||||
height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.show-preview {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
.preview {
|
||||
overflow: hidden;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
background: #cccccc;
|
||||
transform: scale(0.8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer-btn {
|
||||
margin-top: 30px;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
justify-content: space-around;
|
||||
.scope-btn {
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
justify-content: space-between;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.upload-btn {
|
||||
flex: 1;
|
||||
-webkit-flex: 1;
|
||||
display: flex;
|
||||
display: -webkit-flex;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -54,7 +54,7 @@
|
||||
</div>
|
||||
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onDropdownCommand">
|
||||
<span class="layout-navbars-breadcrumb-user-link">
|
||||
<!-- <img :src="getUserInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" /> -->
|
||||
<img :src="getUserInfos.head_pic" class="layout-navbars-breadcrumb-user-link-photo mr5" />
|
||||
{{ getUserInfos.account === '' ? 'test' : getUserInfos.account }}
|
||||
<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
@ -262,8 +262,8 @@ export default {
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
&-photo {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
<div>
|
||||
<Card :bordered="false" dis-hover class="ivu-mt">
|
||||
<Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="160" label-position="right">
|
||||
<FormItem label="头像">
|
||||
<div class="avatar" @click="avatarMoadl = true">
|
||||
<img v-if="formValidate.head_pic" :src="formValidate.head_pic" alt="" />
|
||||
<img v-else src="../../../assets/images/f.png" alt="" />
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="账号" prop="">
|
||||
<Input type="text" v-model="account" :disabled="true" class="input"></Input>
|
||||
</FormItem>
|
||||
@ -22,14 +28,19 @@
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
<Modal v-model="avatarMoadl" footer-hide title="头像上传" width="700">
|
||||
<CropperImg v-if="avatarMoadl" @uploadImgSuccess="uploadImgSuccess"></CropperImg>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { updtaeAdmin } from '@/api/user';
|
||||
import { mapState } from 'vuex';
|
||||
import CropperImg from '@/components/cropperImg';
|
||||
export default {
|
||||
name: 'setting_user',
|
||||
components: { CropperImg },
|
||||
computed: {
|
||||
...mapState('media', ['isMobile']),
|
||||
...mapState('userLevel', ['categoryId']),
|
||||
@ -43,7 +54,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
account: '',
|
||||
avatarMoadl: false,
|
||||
formValidate: {
|
||||
avatar: '',
|
||||
real_name: '',
|
||||
pwd: '',
|
||||
new_pwd: '',
|
||||
@ -59,15 +72,21 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.account = this.$store.state.userInfo.userInfo.account;
|
||||
this.formValidate.head_pic = this.$store.state.userInfo.userInfo.head_pic;
|
||||
this.formValidate.real_name = this.$store.state.userInfo.userInfo.real_name;
|
||||
},
|
||||
methods: {
|
||||
uploadImgSuccess(data) {
|
||||
this.avatarMoadl = false;
|
||||
this.formValidate.head_pic = data.src;
|
||||
},
|
||||
handleSubmit(name) {
|
||||
this.$refs[name].validate((valid) => {
|
||||
if (valid) {
|
||||
updtaeAdmin(this.formValidate)
|
||||
.then((res) => {
|
||||
this.$store.commit('userInfo/userRealName', this.formValidate.real_name);
|
||||
this.$store.commit('userInfo/userRealHeadPic', this.formValidate.head_pic);
|
||||
this.$Message.success(res.msg);
|
||||
})
|
||||
.catch((res) => {
|
||||
@ -84,8 +103,18 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.input {
|
||||
width: 400px;
|
||||
}
|
||||
.avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #f2f2f2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
<div v-else>--</div>
|
||||
</template>
|
||||
<template slot-scope="{ row, index }" slot="action">
|
||||
<a v-if="!foundation.primaryKey" @click="del(row, index)">删除</a>
|
||||
<a v-if="!tableField[index].primaryKey" @click="del(row, index)">删除</a>
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
@ -59,6 +59,9 @@ export default {
|
||||
userRealName(state, realName) {
|
||||
state.userInfo.real_name = realName;
|
||||
},
|
||||
userRealHeadPic(state, headPic) {
|
||||
state.userInfo.head_pic = headPic;
|
||||
},
|
||||
uniqueAuth(state, uniqueAuth) {
|
||||
state.uniqueAuth = uniqueAuth;
|
||||
},
|
||||
|
||||
@ -19,15 +19,14 @@ export default {
|
||||
async install(Vue, options) {
|
||||
Vue.directive('auth', {
|
||||
inserted(el, binding, vnode) {
|
||||
const { value } = binding;
|
||||
const access = store.state.userInfo.access;
|
||||
|
||||
if (value && value instanceof Array && value.length && access && access.length) {
|
||||
const isPermission = includeArray(value, access);
|
||||
if (!isPermission) {
|
||||
el.parentNode && el.parentNode.removeChild(el);
|
||||
}
|
||||
}
|
||||
// const { value } = binding;
|
||||
// const access = store.state.userInfo.access;
|
||||
// if (value && value instanceof Array && value.length && access && access.length) {
|
||||
// const isPermission = includeArray(value, access);
|
||||
// if (!isPermission) {
|
||||
// el.parentNode && el.parentNode.removeChild(el);
|
||||
// }
|
||||
// }
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@ -338,7 +338,7 @@
|
||||
}
|
||||
|
||||
],
|
||||
virtual_type: 0,
|
||||
virtual_type: 0,
|
||||
allPrice: 0,
|
||||
formContent: '',
|
||||
payType: '', //支付方式
|
||||
@ -946,6 +946,7 @@
|
||||
onAddress: function() {
|
||||
let that = this;
|
||||
if (this.addressInfo.real_name) {
|
||||
this.$refs.addressWindow.getAddressList();
|
||||
that.textareaStatus = false;
|
||||
that.address.address = true;
|
||||
that.pagesUrl = '/pages/users/user_address_list/index?news=' + this.news + '&cartId=' + this
|
||||
@ -954,6 +955,7 @@
|
||||
this.pinkId +
|
||||
'&couponId=' +
|
||||
this.couponId;
|
||||
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages/users/user_address/index?cartId=' + this.cartId + '&pinkId=' + this
|
||||
|
||||
@ -346,7 +346,8 @@
|
||||
overflow: hidden;
|
||||
padding: 0 14rpx;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
position: relative;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
|
||||
.productSort .conter .listw {
|
||||
|
||||
@ -258,18 +258,18 @@
|
||||
this.canShow = false
|
||||
if (this.isLogin == true) {
|
||||
this.hotPage = 1;
|
||||
this.hostProduct = [],
|
||||
this.hotScroll = false,
|
||||
this.getHostProduct();
|
||||
this.hostProduct = []
|
||||
this.hotScroll = false
|
||||
this.getHostProduct();
|
||||
this.loadend = false;
|
||||
this.page = 1;
|
||||
this.cartList.valid = [];
|
||||
this.getCartList();
|
||||
this.getCartList(1);
|
||||
this.loadendInvalid = false;
|
||||
this.pageInvalid = 1;
|
||||
this.cartList.invalid = [];
|
||||
this.getInvalidList();
|
||||
this.getCartNum();
|
||||
// this.getCartNum();
|
||||
this.goodsHidden = true;
|
||||
this.footerswitch = true;
|
||||
this.hostProduct = [];
|
||||
@ -769,7 +769,7 @@
|
||||
})
|
||||
});
|
||||
},
|
||||
async getCartList() {
|
||||
async getCartList(init) {
|
||||
uni.showLoading({
|
||||
title: this.$t(`加载中`),
|
||||
mask: true
|
||||
@ -782,6 +782,21 @@
|
||||
}
|
||||
getCartCounts().then(async c => {
|
||||
that.cartCount = c.data.count;
|
||||
if (init) {
|
||||
this.adding = false
|
||||
this.$store.commit('indexData/setCartNum', c.data.count > 99 ? '..' : c.data
|
||||
.count)
|
||||
if (c.data.count > 0) {
|
||||
wx.setTabBarBadge({
|
||||
index: 2,
|
||||
text: c.data.count + ''
|
||||
})
|
||||
} else {
|
||||
wx.hideTabBarRedDot({
|
||||
index: 2
|
||||
})
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < Math.ceil(c.data.ids.length / that.limit); i++) {
|
||||
let cartList = await this.getCartData(data)
|
||||
let valid = cartList.valid
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user