前端
<template>
<van-nav-bar
title="基本资料"
left-text="返回"
left-arrow
@click-left="onBack"
fixed
/>
<div class="h50"></div>
<div class="user">
<div class="user-image">
<img :src="business.avatar_cdn" alt="" />
</div>
</div>
<div class="form">
<van-form @submit="onProfile" label-align="right" colon>
<van-field
v-model="business.mobile"
name="mobile"
label="手机号"
placeholder="手机号"
readonly
/>
<van-field
v-model="business.nickname"
name="nickname"
label="昵称"
placeholder="昵称"
:rules="[{ required: true, message: '昵称不能为空' }]"
/>
<van-field
v-model="business.email"
name="email"
label="邮箱"
placeholder="邮箱"
:rules="[{ required: true, message: '邮箱不能为空' }]"
/>
<van-field
v-model="business.password"
type="password"
name="password"
label="密码"
placeholder="密码为空不修改"
/>
<van-field name="gender" label="性别">
<template #input>
<van-radio-group
v-model="business.gender"
direction="horizontal"
>
<van-radio name="0">保密</van-radio>
<van-radio name="1">男</van-radio>
<van-radio name="2">女</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field
v-model="business.region_text"
is-link
readonly
name="area"
label="地区选择"
placeholder="选择省市区"
@click="showRegion = true"
/>
<!-- 弹出层 + 地区选择组件 -->
<van-popup v-model:show="showRegion" round position="bottom">
<van-area
title="地区选择"
v-model="code"
:area-list="areaList"
@confirm="onRegionConfirm"
@cancel="showRegion = false"
/>
</van-popup>
<van-field name="avatar" label="头像">
<template #input>
<van-uploader v-model="avatar" :max-count="1" />
</template>
</van-field>
<div style="margin: 16px">
<van-button round block type="primary" native-type="submit">
提交
</van-button>
</div>
</van-form>
</div>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue';
import { areaList } from '@vant/area-data';
const { proxy } = getCurrentInstance();
const business = ref(proxy.$cookies.get('business'));
// 省市区弹出框 false 为关闭状态
const showRegion = ref(false);
// 图片回显数据,可上传多个图片,具体参考 vant 官网
const avatar = ref([
{
url: business.value.avatar_cdn,
},
]);
// 获取 cookie 里的 省市区 code
const code = ref(business.value.district ? business.value.district : business.value.city ? business.value.city : business.value.province);
// 提交表单
const onProfile = async (values) => {
// 封装数据
let data = {
busid:business.value.id,
nickname:values.nickname.trim(),
email:values.email.trim(),
gender:values.gender
}
// 判断一下有没有选择地区
if(code.value)
{
data.code = code.value;
}
// 密码
if(values.password)
{
data.password = values.password;
}
// 判断图片是否有,有则将图片数据放入 data 里
if(values.avatar[0].file)
{
data.avatar = values.avatar[0].file;
}
// 发送请求
let result = await proxy.$Api.profile(data);
if(result && result.code === 1)
{
proxy.$showNotify({
type:'success',
message:result.msg,
duration:2000,
onClose:() => {
proxy.$router.push('/business/base/index');
}
});
return;
}else{
proxy.$showNotify({
type:'warning',
message:result.msg,
duration:2000,
});
return;
}
}
// selectedOptions 拿到选择的 省市区编码值
const onRegionConfirm = ({ selectedOptions }) => {
let [province, city, district] = selectedOptions;
let regionText = '';
let regionCode = null;
// 省
if (province.value) {
regionText = province.text + '-';
regionCode = province.value;
}
// 市
if(city.value)
{
regionText += city.text + '-';
regionCode = city.value;
}
// 区
if(district.value)
{
regionText += district.text;
regionCode = district.value;
}
code.value = regionCode;
business.value.region_text = regionText;
showRegion.value = false;
};
// 返回上一页
const onBack = () => {
proxy.$router.back();
};
</script>
<style>
@import url('/assets/css/profile.css');
</style>
后端
<?php
namespace app\shop\controller\business;
use think\Controller;
class Base extends Controller
{
protected $BusinessModel = null;
public function __construct()
{
parent::__construct();
$this->BusinessModel = model('business.Business');
}
public function profile()
{
// 接收全部参数,不包括头像
$params = $this->request->param();
$business = $this->BusinessModel->find($params['busid']);
if(!$business)
{
$this->error('用户不存在');
}
// 封装数据
$data = [
'id' => $params['busid'],
'nickname' => $params['nickname'],
'email' => $params['email'],
'gender' => $params['gender']
];
// 邮箱认证功能
if($data['email'] != $business['email'])
{
$data['auth'] = 0;
}
if(!empty($params['password']))
{
$repass = md5($params['password'] . $business['salt']);
if($repass == $business['password'])
{
$this->error('新密码与原密码一致');
}
$salt = build_randstr();
$password = md5($params['password'] . $salt);
$data['salt'] = $salt;
$data['password'] = $password;
}
if(!empty($params['code']))
{
$path = model('Region')->where(['code' => $params['code']])->value('parentpath');
if(!$path)
{
$this->error('所选地区不存在');
}
$pathArr = explode(',',$path);
$data['province'] = $pathArr[0] ?? null;
$data['city'] = $pathArr[1] ?? null;
$data['district'] = $pathArr[2] ?? null;
}
// 判断是否有文件变量声明并且文件大小大于0
if(isset($_FILES['avatar']) && $_FILES['avatar']['size'] > 0)
{
// 上传文件
$res = build_upload('avatar');
if($res['code'] === 0)
{
$this->error($res['msg']);
}
$data['avatar'] = $res['data'];
}
$result = $this->BusinessModel->validate('common/business/Business.profile')->isUpdate(true)->save($data);
// 判断用户是否更新成功
if($result === false)
{
// 将上传的文件删除
if(isset($data['avatar']) && $_FILES['avatar']['size'] > 0)
{
@is_file('.' . $data['avatar']) && @unlink('.' . $data['avatar']);
}
$this->error($this->BusinessModel->getError());
}else{
// 将原来的图片删除
if(isset($data['avatar']) && $_FILES['avatar']['size'] > 0)
{
@is_file('.' . $business['avatar']) && @unlink('.' . $business['avatar']);
}
// 如果没有路由守卫的,需要重新查询一次新的数据返回存cookie
$this->success('更新成功');
}
}
}
调用接口
import { POST, UPLOAD } from "../../services/request";
export default {
profile(data = {})
{
return UPLOAD({
url:'/business/base/profile',
params:data
});
}
}
Api 接口封装方法
request.js
//引入axios异步请求插件
import axios from 'axios';
let cancel,
promiseArr = {};
const CancelToken = axios.CancelToken;
//请求拦截器
axios.interceptors.request.use(
(config) => {
//发起请求时,取消掉当前正在进行的相同请求
if (promiseArr[config.url]) {
promiseArr[config.url]('操作取消');
promiseArr[config.url] = cancel;
} else {
promiseArr[config.url] = cancel;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
//响应拦截器即异常处理
axios.interceptors.response.use(
(response) => {
// return response
return response.data;
},
(err) => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = '错误请求';
break;
case 401:
err.message = '未授权,请重新登录';
break;
case 403:
err.message = '拒绝访问';
break;
case 404:
err.message = '请求错误,未找到该资源';
break;
case 405:
err.message = '请求方法未允许';
break;
case 408:
err.message = '请求超时';
break;
case 500:
err.message = '服务器端出错';
break;
case 501:
err.message = '网络未实现';
break;
case 502:
err.message = '网络错误';
break;
case 503:
err.message = '服务不可用';
break;
case 504:
err.message = '网络超时';
break;
case 505:
err.message = 'http版本不支持该请求';
break;
default:
err.message = `连接错误${err.response.status}`;
}
} else {
err.message = '连接到服务器失败';
}
console.error(err.message);
return Promise.resolve(err.response);
}
);
//请求的默认前缀 只要是发出去请求就会 默认带上这个前缀
axios.defaults.baseURL = '/shop';
//设置默认请求头 异步的
axios.defaults.headers = {
'X-Requested-With': 'XMLHttpRequest',
};
//设置超时请求时间
axios.defaults.timeout = 10000;
//get请求
let GET = (data = {}) => {
return new Promise((resolve, reject) => {
axios({
method: 'get',
url: data.url,
params: data.params,
cancelToken: new CancelToken((c) => {
cancel = c;
}),
}).then((res) => {
resolve(res);
});
});
};
//post请求
let POST = (data = {}) => {
return new Promise((resolve, reject) => {
axios({
method: 'post',
url: data.url,
data: data.params,
cancelToken: new CancelToken((c) => {
cancel = c;
}),
}).then((res) => {
resolve(res);
});
});
};
// 文件上传请求
let UPLOAD = (data = {}) => {
//封装表单数据对象
var RequestData = new FormData();
if (JSON.stringify(data.params) != '{}') {
for (var key in data.params) {
RequestData.append(key, data.params[key]);
}
}
return new Promise((resolve, reject) => {
axios({
method: 'post',
url: data.url,
data: RequestData,
headers: { 'Content-Type': 'multipart/form-data' },
cancelToken: new CancelToken((c) => {
cancel = c;
}),
}).then((res) => {
resolve(res);
});
});
};
export { GET, POST, UPLOAD };
图片上传方法
if(!function_exists('build_upload'))
{
/**
* 单图上传
* @param string $name 字段名
* @return array 返回结果集
*/
function build_upload($name)
{
$file = request()->file($name);
$result = [
'code' => 0,
'msg' => '请上传文件',
'data' => null
];
if($file)
{
$info = $file->move(ROOT_PATH . 'public/uploads');
if($info)
{
$result['data'] = '/uploads/' . $info->getSaveName();
$result['code'] = 1;
$result['msg'] = '上传成功';
}else{
$result['msg'] = $file->getError();
}
}
return $result;
}
}