fix: 文件上传功能

This commit is contained in:
lbw 2023-02-14 14:40:17 +08:00
parent 116b4389a0
commit 0b73210793
5 changed files with 200 additions and 180 deletions

View File

@ -1,5 +1,5 @@
# port 端口号
VITE_PORT = 8080
VITE_PORT = 8888
# 本地环境
ENV = 'development'

View File

@ -37,23 +37,24 @@ export const Local = {
export const Session = {
// 设置临时缓存
set(key: string, val: any) {
if (key === 'token') return Cookies.set(key, val);
if (key === 'token' || key === 'refresh_token') return Cookies.set(key, val);
window.sessionStorage.setItem(key, JSON.stringify(val));
},
// 获取临时缓存
get(key: string) {
if (key === 'token') return Cookies.get(key);
if (key === 'token' || key === 'refresh_token') return Cookies.get(key);
let json = <string>window.sessionStorage.getItem(key);
return JSON.parse(json);
},
// 移除临时缓存
remove(key: string) {
if (key === 'token') return Cookies.remove(key);
if (key === 'token' || key === 'refresh_token') return Cookies.remove(key);
window.sessionStorage.removeItem(key);
},
// 移除全部临时缓存
clear() {
Cookies.remove('token');
Cookies.remove('refresh_token');
window.sessionStorage.clear();
},
};

View File

@ -1,55 +1,47 @@
<template>
<el-dialog title="上传文件" v-model="visible"
:close-on-click-modal="false" draggable>
<el-upload
class="upload-demo"
drag
action="/admin/sys-file/upload"
:headers="headers"
multiple
@success="success"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
拖拽到这个位置或者<em>点击上传</em>
<el-dialog title="上传文件" v-model="visible" :close-on-click-modal="false" draggable>
<el-upload class="upload-demo" drag action="/admin/sys-file/upload" :headers="headers" multiple @success="success">
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
拖拽到这个位置或者<em>点击上传</em>
</div>
<template #tip>
<div class="el-upload__tip">
上传同步至文件服务器
</div>
<template #tip>
<div class="el-upload__tip">
上传同步至文件服务器
</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="SysFileDialog">
// /
import {Session} from "/@/utils/storage";
import { Local } from "/@/utils/storage";
import { Session } from "/@/utils/storage";
const emit = defineEmits(['refresh']);
const headers = reactive({
Authorization: ''
})
//
const visible = ref(false)
//
const headers = computed(() => {
const tenantId = Local.get("tenantId") ? Local.get("tenantId") : 1
return {
'Authorization': "Bearer " + Session.get("token"),
'TENANT-ID': tenantId
};
})
//
const openDialog = () => {
visible.value = true
// token
if (Session.get('token')) {
headers.Authorization = `Bearer ${Session.get('token')}`;
}
};
const success = () => {

View File

@ -1,10 +1,10 @@
<script setup lang="ts" name="authredirect">
import request from '/@/utils/request';
import { ElMessageBox } from 'element-plus';
import other from "/@/utils/other";
import { rule } from '/@/utils/validate';
import { Session } from '/@/utils/storage';
import { useUserInfo } from '/@/stores/userInfo';
import { useMessageBox } from '/@/hooks/message';
onMounted(async () => {
const url = window.location.search
@ -38,11 +38,8 @@ const bind = (state: string, code: string) => {
method: 'post',
params: { state, code }
}).then(() => {
ElMessageBox.alert('社交账号绑定成功', '成功', {
confirmButtonText: '确定',
callback: () => {
window.close()
}
useMessageBox().confirm('社交账号绑定成功').then(() => {
window.close()
})
})
}

View File

@ -7,19 +7,20 @@
<div class="personal-user">
<div class="personal-user-left">
<el-upload class="h100 personal-user-left-upload" action="/admin/sys-file/upload"
:headers="headers"
:on-success="handleAvatarSuccess" :limit="1">
:headers="headers" :on-success="handleAvatarSuccess" :limit="1">
<img :src="formData.avatar" />
</el-upload>
</div>
<div class="personal-user-right">
<el-row>
<el-col :span="24" class="personal-title mb18">{{ currentTime }}admin生活变的再糟糕也不妨碍我变得更好 </el-col>
<el-col :span="24" class="personal-title mb18">{{
currentTime
}}admin </el-col>
<el-col :span="24">
<el-row>
<el-col :xs="24" :sm="8" class="personal-item mb6">
<div class="personal-item-label">昵称</div>
<div class="personal-item-value">{{formData.nickname}}</div>
<div class="personal-item-value">{{ formData.nickname }}</div>
</el-col>
<el-col :xs="24" :sm="16" class="personal-item mb6">
<div class="personal-item-label">身份</div>
@ -49,18 +50,19 @@
<el-col :span="24">
<el-card shadow="hover" class="mt15 personal-edit" header="更新信息">
<div class="personal-edit-title">基本信息</div>
<el-form :model="formData" size="default" :rules="ruleForm" label-width="100px" class="mt35 mb35" ref="formdataRef">
<el-form :model="formData" size="default" :rules="ruleForm" label-width="100px" class="mt35 mb35"
ref="formdataRef">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" clearable disabled></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="手机" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="用户名" prop="username">
<el-input v-model="formData.username" clearable disabled></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="手机" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="邮箱" prop="email">
@ -72,64 +74,65 @@
<el-input v-model="formData.nickname" placeholder="请输入昵称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入姓名" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="原密码" prop="password">
<el-input v-model="formData.password" placeholder="请输入密码" clearable type="password"></el-input>
<el-input v-model="formData.password" placeholder="请输入密码" clearable
type="password"></el-input>
</el-form-item>
</el-col>
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
<el-form-item label="新密码" prop="newpassword1">
<el-input v-model="formData.newpassword1" clearable type="password"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="确认密码" prop="newpassword2">
<el-input v-model="formData.newpassword2" clearable type="password"></el-input>
</el-form-item>
</el-col>
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
<el-form-item label="社交登录" prop="social">
<div @click="handleClick('wechat')">
<span :style="{ backgroundColor: '#6ba2d6' }" class="container">
<i class="iconfont icon-weixin" icon-class="wechat" />
</span>
<p class="title">微信</p>
</div>
<div @click="handleClick('tencent')">
<span :style="{ backgroundColor: '#8dc349' }" class="container">
<i class="iconfont icon-qq" icon-class="qq" />
</span>
<p class="title">QQ</p>
</div>
<div @click="handleClick('gitee')">
<span :style="{ backgroundColor: '#bf3030' }" class="container">
<i class="iconfont icon-logo_gitee_icon" icon-class="qq" />
</span>
<p class="title">Gitee</p>
</div>
<div @click="handleClick('osc')">
<span :style="{ backgroundColor: '#007B25' }" class="container">
<i class="iconfont icon-oschina" icon-class="qq" />
</span>
<p class="title">开源中国</p>
</div>
</el-form-item>
</el-col>
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
<el-form-item label="新密码" prop="newpassword1">
<el-input v-model="formData.newpassword1" clearable type="password"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="确认密码" prop="newpassword2">
<el-input v-model="formData.newpassword2" clearable type="password"></el-input>
</el-form-item>
</el-col>
<el-col :lg="6" :md="8" :sm="12" :xl="4" :xs="24" class="mb20">
<el-form-item label="社交登录" prop="social">
<div @click="handleClick('wechat')">
<span :style="{ backgroundColor: '#6ba2d6' }" class="container">
<i class="iconfont icon-weixin" icon-class="wechat"/>
</span>
<p class="title">微信</p>
</div>
<div @click="handleClick('tencent')">
<span :style="{ backgroundColor: '#8dc349' }" class="container">
<i class="iconfont icon-qq" icon-class="qq"/>
</span>
<p class="title">QQ</p>
</div>
<div @click="handleClick('gitee')">
<span :style="{ backgroundColor: '#bf3030' }" class="container">
<i class="iconfont icon-logo_gitee_icon" icon-class="qq"/>
</span>
<p class="title">Gitee</p>
</div>
<div @click="handleClick('osc')">
<span :style="{ backgroundColor: '#007B25' }" class="container">
<i class="iconfont icon-oschina" icon-class="qq"/>
</span>
<p class="title">开源中国</p>
</div>
</el-form-item>
</el-col>
<el-col :lg="24" :md="24" :sm="24" :xl="24" :xs="24">
<el-form-item>
<el-button type="primary" @click="handleSaveUser">
<el-icon>
<ele-Position/>
</el-icon>
更新个人信息
</el-button>
</el-form-item>
<el-col :lg="24" :md="24" :sm="24" :xl="24" :xs="24">
<el-form-item>
<el-button type="primary" @click="handleSaveUser">
<el-icon>
<ele-Position />
</el-icon>
更新个人信息
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
@ -140,108 +143,105 @@
</template>
<script setup lang="ts" name="personal">
import {computed, reactive} from 'vue';
import {formatAxis} from '/@/utils/formatTime';
import {useUserInfo} from '/@/stores/userInfo';
import {editInfo} from '/@/api/admin/user'
import {useMessage} from "/@/hooks/message";
import {Session} from "/@/utils/storage";
import {rule} from "/@/utils/validate";
import { computed, reactive } from 'vue';
import { formatAxis } from '/@/utils/formatTime';
import { useUserInfo } from '/@/stores/userInfo';
import { editInfo } from '/@/api/admin/user'
import { useMessage } from "/@/hooks/message";
import { Session } from "/@/utils/storage";
import { rule } from "/@/utils/validate";
import other from '/@/utils/other';
//
const formData = reactive({
username: '',
name: '',
email: '',
avatar: '',
nickname: '',
phone: '',
password: '',
newpassword1: '',
newpassword2: ''
username: '',
name: '',
email: '',
avatar: '',
nickname: '',
phone: '',
password: '',
newpassword1: '',
newpassword2: ''
});
const formdataRef = ref()
const ruleForm = reactive({
password: [{ required: true, message: "密码不能为空", trigger: "blur" }],
phone: [{ required: true, message: "手机号不能为空", trigger: "blur" },{ validator: rule.validatePhone, trigger: 'blur' }],
nickname: [{ required: true, message: "昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱不能为空", trigger: "blur" }],
name: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
newpassword1: [{
min: 6,
max: 20,
message: "用户密码长度必须介于 6 和 20 之间",
trigger: "blur"
}]
password: [{ required: true, message: "密码不能为空", trigger: "blur" }],
phone: [{ required: true, message: "手机号不能为空", trigger: "blur" }, { validator: rule.validatePhone, trigger: 'blur' }],
nickname: [{ required: true, message: "昵称不能为空", trigger: "blur" }],
email: [{ required: true, message: "邮箱不能为空", trigger: "blur" }],
name: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
newpassword1: [{
min: 6,
max: 20,
message: "用户密码长度必须介于 6 和 20 之间",
trigger: "blur"
}]
})
const handleAvatarSuccess = (res: any) => {
formData.avatar = res.data.url;
formData.avatar = res.data.url;
}
const headers = computed(() => {
const tenantId = Session.get("tenantId")
return {
'Authorization': "Bearer " + Session.get("token"),
'TENANT-ID': tenantId ? tenantId : '1'
};
const tenantId = Session.get("tenantId")
return {
'Authorization': "Bearer " + Session.get("token"),
'TENANT-ID': tenantId ? tenantId : '1'
};
})
onMounted(() => {
const data = useUserInfo().userInfos
Object.assign(formData,data.user)
formData.password = ''
const data = useUserInfo().userInfos
Object.assign(formData, data.user)
formData.password = ''
})
const handleSaveUser = () =>{
formdataRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
editInfo(formData).then(() => {
useMessage().success("修改成功")
// /token
Session.clear();
// 使 reload resetRoute()
window.location.reload();
}).catch(err => {
useMessage().error(err.msg)
})
})
const handleSaveUser = () => {
formdataRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
editInfo(formData).then(() => {
useMessage().success("修改成功")
// user
useUserInfo().setUserInfos()
}).catch(err => {
useMessage().error(err.msg)
})
})
}
//
const currentTime = computed(() => {
return formatAxis(new Date());
return formatAxis(new Date());
});
const handleClick = (thirdpart: string) => {
let appid, client_id, redirect_uri, url;
redirect_uri = encodeURIComponent(
window.location.origin + "/#/authredirect"
);
if (thirdpart === "wechat") {
appid = "wxd1678d3f83b1d83a";
url = `https://open.weixin.qq.com/connect/qrconnect?appid=${appid}&redirect_uri=${redirect_uri}&state=WX-BIND&response_type=code&scope=snsapi_login#wechat_redirect`;
} else if (thirdpart === "tencent") {
client_id = "101322838";
url = `https://graph.qq.com/oauth2.0/authorize?response_type=code&state=QQ-BIND&client_id=${client_id}&redirect_uri=${redirect_uri}`;
} else if (thirdpart === "gitee") {
client_id =
"235ce26bbc59565b82c989aa3a407ce844cf59a7c5e0f9caa9bb3bf32cee5952";
url = `https://gitee.com/oauth/authorize?response_type=code&state=GITEE-BIND&client_id=${client_id}&redirect_uri=${redirect_uri}`;
} else if (thirdpart === "osc") {
client_id = "neIIqlwGsjsfsA6uxNqD";
url = `https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=${client_id}&state=OSC-BIND&redirect_uri=${redirect_uri}`;
}
other.openWindow(url, thirdpart, 540, 540)
let appid, client_id, redirect_uri, url;
redirect_uri = encodeURIComponent(
window.location.origin + "/#/authredirect"
);
if (thirdpart === "wechat") {
appid = "wxd1678d3f83b1d83a";
url = `https://open.weixin.qq.com/connect/qrconnect?appid=${appid}&redirect_uri=${redirect_uri}&state=WX-BIND&response_type=code&scope=snsapi_login#wechat_redirect`;
} else if (thirdpart === "tencent") {
client_id = "101322838";
url = `https://graph.qq.com/oauth2.0/authorize?response_type=code&state=QQ-BIND&client_id=${client_id}&redirect_uri=${redirect_uri}`;
} else if (thirdpart === "gitee") {
client_id = '0c29cfd9cb1e0037fc837521bc08c1a7483d8fd9b3e123d46beec59a5544a881'
url = `https://gitee.com/oauth/authorize?response_type=code&state=GITEE-BIND&client_id=${client_id}&redirect_uri=${redirect_uri}`;
} else if (thirdpart === "osc") {
client_id = "neIIqlwGsjsfsA6uxNqD";
url = `https://www.oschina.net/action/oauth2/authorize?response_type=code&client_id=${client_id}&state=OSC-BIND&redirect_uri=${redirect_uri}`;
}
other.openWindow(url, thirdpart, 540, 540)
}
@ -249,24 +249,29 @@ const handleClick = (thirdpart: string) => {
<style scoped lang="scss">
@import '../../theme/mixins/index.scss';
.personal {
.personal-user {
height: 130px;
display: flex;
align-items: center;
.personal-user-left {
width: 180px;
height: 130px;
border-radius: 3px;
:deep(.el-upload) {
height: 100%;
}
.personal-user-left-upload {
img {
width: 100%;
height: 100%;
border-radius: 3px;
}
&:hover {
img {
animation: logoAnimation 0.3s ease-in-out;
@ -274,51 +279,63 @@ const handleClick = (thirdpart: string) => {
}
}
}
.personal-user-right {
flex: 1;
padding: 0 15px;
.personal-title {
font-size: 18px;
@include text-ellipsis(1);
}
.personal-item {
display: flex;
align-items: center;
font-size: 13px;
.personal-item-label {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
}
.personal-item-value {
@include text-ellipsis(1);
}
}
}
}
.personal-info {
.personal-info-more {
float: right;
color: var(--el-text-color-secondary);
font-size: 13px;
&:hover {
color: var(--el-color-primary);
cursor: pointer;
}
}
.personal-info-box {
height: 130px;
overflow: hidden;
.personal-info-ul {
list-style: none;
.personal-info-li {
font-size: 13px;
padding-bottom: 10px;
.personal-info-li-title {
display: inline-block;
@include text-ellipsis(1);
color: var(--el-text-color-secondary);
text-decoration: none;
}
& a:hover {
color: var(--el-color-primary);
cursor: pointer;
@ -327,6 +344,7 @@ const handleClick = (thirdpart: string) => {
}
}
}
.personal-recommend-row {
.personal-recommend-col {
.personal-recommend {
@ -335,6 +353,7 @@ const handleClick = (thirdpart: string) => {
border-radius: 3px;
overflow: hidden;
cursor: pointer;
&:hover {
i {
right: 0px !important;
@ -342,6 +361,7 @@ const handleClick = (thirdpart: string) => {
transition: all ease 0.3s;
}
}
i {
position: absolute;
right: -10px;
@ -350,12 +370,14 @@ const handleClick = (thirdpart: string) => {
transform: rotate(-30deg);
transition: all ease 0.3s;
}
.personal-recommend-auto {
padding: 15px;
position: absolute;
left: 0;
top: 5%;
color: var(--next-color-white);
.personal-recommend-msg {
font-size: 12px;
margin-top: 10px;
@ -364,11 +386,13 @@ const handleClick = (thirdpart: string) => {
}
}
}
.personal-edit {
.personal-edit-title {
position: relative;
padding-left: 10px;
color: var(--el-text-color-regular);
&::after {
content: '';
width: 2px;
@ -380,21 +404,26 @@ const handleClick = (thirdpart: string) => {
background: var(--el-color-primary);
}
}
.personal-edit-safe-box {
border-bottom: 1px solid var(--el-border-color-light, #ebeef5);
padding: 15px 0;
.personal-edit-safe-item {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.personal-edit-safe-item-left {
flex: 1;
overflow: hidden;
.personal-edit-safe-item-left-label {
color: var(--el-text-color-regular);
margin-bottom: 5px;
}
.personal-edit-safe-item-left-value {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
@ -402,6 +431,7 @@ const handleClick = (thirdpart: string) => {
}
}
}
&:last-of-type {
padding-bottom: 0;
border-bottom: none;