@@ -5,7 +5,7 @@ | |||
<link rel="icon" type="image/svg+xml" href="/logo_1.jpg" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
<title>菊城人才市场后台管理</title> | |||
<script type="module" crossorigin src="/assets/index-zplygJt9.js"></script> | |||
<script type="module" crossorigin src="/assets/index-i0sh_yC6.js"></script> | |||
<link rel="stylesheet" crossorigin href="/assets/index-EE_SYqet.css"> | |||
</head> | |||
<body> |
@@ -3,6 +3,8 @@ import { url } from '../url' | |||
export const Login = postModel(url.userLogin); | |||
export const GetUserMenulist = getModel(url.UserMenulist); | |||
export const PostSmsSend = postModel(url.SmsSend); | |||
export const GetCaptcha = getModel(url.Captcha); | |||
// 角色 | |||
export const PostRoleAdd = postModel(url.RoleAdd); | |||
@@ -213,19 +215,19 @@ export const GetSysconfigList = getModel(url.SysconfigList); // | |||
export const GetSysconfigDetail = getModel(url.SysconfigDetail); | |||
// 反馈 | |||
export const PostFeedbackAdd = postModel(url.FeedbackAdd); | |||
export const PostFeedbackDel = postModel(url.FeedbackDel); | |||
export const PostFeedbackUpdate = postModel(url.FeedbackUpdate); | |||
export const GetFeedbackList = getModel(url.FeedbackList); | |||
export const GetFeedbackDetail = getModel(url.FeedbackDetail); | |||
export const PostFeedbackAdd = postModel(url.FeedbackAdd); | |||
export const PostFeedbackDel = postModel(url.FeedbackDel); | |||
export const PostFeedbackUpdate = postModel(url.FeedbackUpdate); | |||
export const GetFeedbackList = getModel(url.FeedbackList); | |||
export const GetFeedbackDetail = getModel(url.FeedbackDetail); | |||
// 反馈 | |||
export const PostCustomerAdd = postModel(url.CustomerAdd); | |||
export const PostCustomerDel = postModel(url.CustomerDel); | |||
export const GetCustomerUpdate = getModel(url.CustomerUpdate); | |||
export const GetCustomerList = getModel(url.CustomerList); | |||
export const PostCustomerAdd = postModel(url.CustomerAdd); | |||
export const PostCustomerDel = postModel(url.CustomerDel); | |||
export const GetCustomerUpdate = getModel(url.CustomerUpdate); | |||
export const GetCustomerList = getModel(url.CustomerList); | |||
export const GetCustomerDetail = getModel(url.CustomerDetail); | |||
export const PostEsJobseeker = postModel(url.EsJobseeker); | |||
export const PostTokenizerModify = postModel(url.TokenizerModify); | |||
export const GetTokenizerGet = getModel(url.TokenizerGet); | |||
export const GetTokenizerGet = getModel(url.TokenizerGet); |
@@ -1,5 +1,7 @@ | |||
declare namespace urlType { | |||
type url = { | |||
Captcha : String, | |||
SmsSend : String, | |||
userLogin : String, | |||
UserMenulist : String, | |||
RoleAdd : String, | |||
@@ -184,31 +186,31 @@ declare namespace urlType { | |||
StatsPosition : String, | |||
StatsTitleAndSkill : String, | |||
StatsJobMajor : String, | |||
'SysconfigAdd':String, | |||
'SysconfigDel': String, | |||
'SysconfigUpdate':String, | |||
'SysconfigList': String, | |||
'SysconfigDetail': String, | |||
'SysconfigAdd' : String, | |||
'SysconfigDel' : String, | |||
'SysconfigUpdate' : String, | |||
'SysconfigList' : String, | |||
'SysconfigDetail' : String, | |||
// 反馈 | |||
FeedbackAdd: String, | |||
FeedbackDel: String, | |||
FeedbackUpdate: String, | |||
FeedbackList: String, | |||
FeedbackDetail: String, | |||
FeedbackAdd : String, | |||
FeedbackDel : String, | |||
FeedbackUpdate : String, | |||
FeedbackList : String, | |||
FeedbackDetail : String, | |||
// 反馈 | |||
CustomerAdd: String, | |||
CustomerDel: String, | |||
CustomerUpdate: String, | |||
CustomerList: String, | |||
CustomerDetail:String, | |||
DocUpload: String, | |||
EsJobseeker: String, | |||
TokenizerModify: String, | |||
TokenizerGet:String, | |||
CustomerAdd : String, | |||
CustomerDel : String, | |||
CustomerUpdate : String, | |||
CustomerList : String, | |||
CustomerDetail : String, | |||
DocUpload : String, | |||
EsJobseeker : String, | |||
TokenizerModify : String, | |||
TokenizerGet : String, | |||
} | |||
} |
@@ -4,6 +4,9 @@ let common : string = '/common'; | |||
export const url : urlType.url = { | |||
userLogin: admin + '/user/login', | |||
UserMenulist: admin + '/user/menulist', | |||
SmsSend: common + '/sms/send', // 短信验证码 | |||
Captcha: common + '/captcha', // 获取验证码 | |||
// 角色 | |||
RoleAdd: admin + '/role/add', | |||
RoleList: admin + '/role/list', |
@@ -0,0 +1,68 @@ | |||
<template> | |||
<div v-if="needPre"> | |||
<img :src="imgObj.src" alt="" | |||
:style="{width: imgObj.width,height: imgObj.height,'object-fit': imgObj.mode, 'border-radius': 0} " | |||
@click="preImage(imgObj.src)"> | |||
<a-modal v-model:open="imageBigOpen" width="50%" centered :footer="null" @cancel="close"> | |||
<div style="padding: 30px;"> | |||
<img :src="imgObj.src" style="width: 100%; height: 100%;"> | |||
</div> | |||
</a-modal> | |||
</div> | |||
<div v-else> | |||
<img :src="imgObj.src" alt="" | |||
:style="{width: imgObj.width,height: imgObj.height,'object-fit': imgObj.mode, 'border-radius': 0} "> | |||
</div> | |||
</template> | |||
<script lang="ts" setup> | |||
import { ref, onMounted, defineProps, watch, computed } from 'vue'; | |||
const props = defineProps({ | |||
imgObj: { | |||
type: Object, | |||
default: {} | |||
}, | |||
need: { | |||
type: Boolean, | |||
default: false | |||
} | |||
}); | |||
let needPre = ref<Boolean>(props.need) | |||
let imageBigOpen = ref<Boolean>(false) | |||
interface imgType { | |||
src ?: String, | |||
width ?: Number, | |||
height ?: Number, | |||
mode ?: String, | |||
} | |||
const imgObj = ref<imgType>({ | |||
src: '', | |||
width: 0, | |||
height: 0, | |||
mode: '', | |||
}) | |||
// 预览 | |||
const preImage = (src) => { | |||
imageBigOpen.value = true | |||
} | |||
const close = (src) => { | |||
imageBigOpen.value = false | |||
} | |||
watch(() => [props.imgObj], (newVal : any) => { | |||
if (newVal[0]) { | |||
imgObj.value = newVal[0] | |||
} | |||
}, { immediate: true }) | |||
</script> | |||
<style> | |||
</style> |
@@ -21,6 +21,7 @@ import ACSelect from '@/components/cSelect/select.vue'; | |||
import ACSelectCommon from '@/components/cSelect/common.vue'; | |||
import UploadOne from '@/components/upload/one.vue'; | |||
import UploadFile from '@/components/upload/file.vue'; | |||
import ImageContainer from '@/components/form/image-container.vue'; | |||
import { Model } from 'node_modules/echarts/index'; | |||
// router.beforeEach(async (to, from, next) => { | |||
@@ -76,7 +77,7 @@ app.component('a-c-select', ACSelect); | |||
app.component('a-xuanze', AXuanze); | |||
app.component('a-shujilian', AShujilian); | |||
app.component('search-select', SearchSelect); | |||
app.component('image-container', ImageContainer) | |||
app.component('a-c-select-common', ACSelectCommon); | |||
app.component('QuillEditor', QuillEditor) | |||
app.component('upload-one', UploadOne) |
@@ -17,8 +17,8 @@ | |||
<a-col span="24"> | |||
<a-form-item label="上传文件,可将链接放入文章内容"> | |||
<upload-file @uploadSuccess="uploadDocSuccess"></upload-file> | |||
<a-typography-paragraph v-if="createForm.doc" :copyable="{ text: imageprefix+createForm.doc}"> | |||
{{imageprefix+createForm.doc}} | |||
<a-typography-paragraph v-if="createForm.doc_url" :copyable="{ text: imageprefix+createForm.doc_url}"> | |||
{{imageprefix+createForm.doc_url}} | |||
</a-typography-paragraph> | |||
</a-form-item> | |||
</a-col> | |||
@@ -92,7 +92,7 @@ | |||
// 上传文件 | |||
const uploadDocSuccess = (data : Object) => { | |||
createForm.value.doc = data | |||
createForm.value.doc_url = data | |||
} | |||
// 选择栏目/频道 |
@@ -1,7 +1,7 @@ | |||
export let dataForm = { | |||
title: '', | |||
cover_img: '', | |||
doc: '', | |||
doc_url: '', | |||
section_id: 0, | |||
content: '', | |||
stick_top: 0, | |||
@@ -18,7 +18,7 @@ export const reset = () => { | |||
dataForm = { | |||
title: '', | |||
cover_img: '', | |||
doc: '', | |||
doc_url: '', | |||
section_id: 0, | |||
content: '', | |||
stick_top: 0, |
@@ -4,80 +4,136 @@ | |||
<h2 class="title">菊城人才市场招聘后台管理系统</h2> | |||
<div class="sub-title">欢迎使用</div> | |||
<a-form> | |||
<a-row> | |||
<a-col :span="24"><a-form-item> | |||
<a-input placeholder="账号" v-model:value="createForm.mobile"> | |||
<template #prefix> | |||
<user-outlined type="user" /> | |||
</template> | |||
</a-input> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row> | |||
<a-col :span="24"> | |||
<a-form-item> | |||
<a-input type="password" placeholder="密码" v-model:value="createForm.password"> | |||
<template #prefix> | |||
<LockOutlined /> | |||
</template> | |||
<template #suffix> | |||
<a-tooltip title="Extra information"> | |||
<EyeInvisibleOutlined style="color: rgba(0, 0, 0, 0.25)" /> | |||
</a-tooltip> | |||
</template> | |||
</a-input> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row :gutter="10"> | |||
<a-col :span="16"> | |||
<a-form-item> | |||
<a-input type="password" placeholder="验证码"> | |||
<template #prefix> | |||
<LockOutlined /> | |||
</template> | |||
<template #suffix> | |||
<a-tooltip title="Extra information"> | |||
<EyeInvisibleOutlined style="color: rgba(0, 0, 0, 0.25)" /> | |||
</a-tooltip> | |||
</template> | |||
</a-input> | |||
</a-form-item> | |||
</a-col> | |||
<a-col :span="8"> | |||
<a-button style="width: 100%;">验证码</a-button> | |||
</a-col> | |||
</a-row> | |||
<a-row type="flex" justify="end"> | |||
<a-col :span="6"> | |||
<a-form-item> | |||
<div>忘记密码?</div> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row> | |||
<a-col :span="24"> | |||
<a-button @click="toLogin" style="width: 100%;" type="primary">登录</a-button> | |||
</a-col> | |||
</a-row> | |||
<a-space direction="vertical"> | |||
<a-row :gutter="10"> | |||
<a-col :span="24"> | |||
<a-form-item> | |||
<a-input size="large" placeholder="账号" v-model:value="createForm.mobile"> | |||
<template #prefix> | |||
<user-outlined type="user" /> | |||
</template> | |||
</a-input> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row :gutter="10"> | |||
<a-col :span="24"> | |||
<a-form-item> | |||
<a-input size="large" type="password" placeholder="密码" | |||
v-model:value="createForm.password"> | |||
<template #prefix> | |||
<LockOutlined /> | |||
</template> | |||
<template #suffix> | |||
<a-tooltip title="Extra information"> | |||
<EyeInvisibleOutlined style="color: rgba(0, 0, 0, 0.25)" /> | |||
</a-tooltip> | |||
</template> | |||
</a-input> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row :gutter="10"> | |||
<a-col span="12"> | |||
<a-form-item> | |||
<a-input v-model:value="createForm.captcha" placeholder="图形验证码" size="large" /> | |||
</a-form-item> | |||
</a-col> | |||
<a-col span="12"> | |||
<a-form-item> | |||
<image-container :imgObj="{src: codeImage,width: '100%',height: '40px', mode: 'fill'}" | |||
@click="getCaptcha"></image-container> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<a-row :gutter="10"> | |||
<a-col span="16"> | |||
<a-form-item> | |||
<a-input v-model:value="createForm.sms_code" placeholder="短信验证码" size="large" /> | |||
</a-form-item> | |||
</a-col> | |||
<a-col span="8"> | |||
<a-form-item> | |||
<a-button type="primary" block size="large" @click="sendCode" | |||
:disabled="state.disabled"> | |||
{{ state.codeTxt }}</a-button> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> | |||
<!-- <a-row type="flex" justify="end"> | |||
<a-col :span="6"> | |||
<a-form-item> | |||
<div>忘记密码?</div> | |||
</a-form-item> | |||
</a-col> | |||
</a-row> --> | |||
<a-row> | |||
<a-col :span="24"> | |||
<a-button @click="toLogin" style="width: 100%;" type="primary">登录</a-button> | |||
</a-col> | |||
</a-row> | |||
</a-space> | |||
</a-form> | |||
</div> | |||
</div> | |||
</template> | |||
<script lang="ts" setup> | |||
import { ref } from 'vue'; | |||
import { Login } from '@/apis/models'; | |||
import { ref, onMounted, onBeforeUnmount } from 'vue'; | |||
import { Login, PostSmsSend, GetCaptcha } from '@/apis/models'; | |||
import { useAsRouter } from '@/hooks/useAsRouter' | |||
import { UserOutlined, InfoCircleOutlined, LockOutlined, EyeInvisibleOutlined } from '@ant-design/icons-vue'; | |||
import { useCommon } from '@/hooks/useCommon'; | |||
let { message } = useCommon(); | |||
const { routerTo } = useAsRouter(); | |||
let capt_id = ref<String>('') | |||
let codeImage = ref<String>('') | |||
const createForm = ref<Object>({ | |||
mobile: '', | |||
password: '' | |||
password: '', | |||
// captcha: '', | |||
// sms_code: '' | |||
}) | |||
interface State { | |||
count : number; | |||
sending : boolean; | |||
disabled : boolean; | |||
} | |||
const state = ref<State>({ | |||
count: 60, | |||
codeTxt: '获取验证码', | |||
disabled: false, | |||
}); | |||
let timer = ref<any>(null) | |||
const sendCode = () => { | |||
if (!createForm.value.mobile) { | |||
message.danger('请输入手机号') | |||
return false; | |||
} | |||
PostSmsSend({ mobile: createForm.mobile, captcha: '', capt_id: capt_id.value }).then(res => { | |||
message.success('发送验证码成功,验证码有效期为一分钟'); | |||
timer.value = setInterval(function () { | |||
if (state.value.count > 1) { | |||
state.value.count = state.value.count - 1; | |||
state.value.codeTxt = '剩余' + (state.value.count - 1) + '秒'; | |||
state.value.disabled = true | |||
} else { | |||
clearInterval(timer.value); | |||
state.value.count = 60; | |||
state.value.codeTxt = '获取验证码'; | |||
state.value.disabled = false | |||
}; | |||
}, 1000) | |||
}) | |||
}; | |||
onBeforeUnmount(() => { | |||
clearInterval(timer.value); | |||
}) | |||
const toLogin = () => { | |||
if (!createForm.value.mobile) { | |||
@@ -87,7 +143,7 @@ | |||
if (!createForm.value.password) { | |||
message.warning('请输入密码'); | |||
return false; | |||
} | |||
} | |||
Login(createForm.value).then(res => { | |||
sessionStorage.setItem('token', res.data.jwttoken.accesstoken); | |||
routerTo('/home'); | |||
@@ -99,6 +155,19 @@ | |||
// sessionStorage.setItem('token', '1321'); | |||
// routerTo('/home'); | |||
} | |||
const getCaptcha = () => { | |||
capt_id.value = '' | |||
GetCaptcha().then(res => { | |||
capt_id.value = res.data.capt_id; | |||
codeImage.value = res.data.img; | |||
}) | |||
} | |||
onMounted(() => { | |||
getCaptcha() | |||
}) | |||
</script> | |||
<style lang="less"> |