| @@ -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"> | |||