| <link rel="icon" type="image/svg+xml" href="/logo_1.jpg" /> | <link rel="icon" type="image/svg+xml" href="/logo_1.jpg" /> | ||||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
| <title>菊城人才市场后台管理</title> | <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"> | <link rel="stylesheet" crossorigin href="/assets/index-EE_SYqet.css"> | ||||
| </head> | </head> | ||||
| <body> | <body> | 
| export const Login = postModel(url.userLogin); | export const Login = postModel(url.userLogin); | ||||
| export const GetUserMenulist = getModel(url.UserMenulist); | export const GetUserMenulist = getModel(url.UserMenulist); | ||||
| export const PostSmsSend = postModel(url.SmsSend); | |||||
| export const GetCaptcha = getModel(url.Captcha); | |||||
| // 角色 | // 角色 | ||||
| export const PostRoleAdd = postModel(url.RoleAdd); | export const PostRoleAdd = postModel(url.RoleAdd); | ||||
| export const GetSysconfigDetail = getModel(url.SysconfigDetail); | 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 GetCustomerDetail = getModel(url.CustomerDetail); | ||||
| export const PostEsJobseeker = postModel(url.EsJobseeker); | export const PostEsJobseeker = postModel(url.EsJobseeker); | ||||
| export const PostTokenizerModify = postModel(url.TokenizerModify); | export const PostTokenizerModify = postModel(url.TokenizerModify); | ||||
| export const GetTokenizerGet = getModel(url.TokenizerGet); | |||||
| export const GetTokenizerGet = getModel(url.TokenizerGet); | 
| declare namespace urlType { | declare namespace urlType { | ||||
| type url = { | type url = { | ||||
| Captcha : String, | |||||
| SmsSend : String, | |||||
| userLogin : String, | userLogin : String, | ||||
| UserMenulist : String, | UserMenulist : String, | ||||
| RoleAdd : String, | RoleAdd : String, | ||||
| StatsPosition : String, | StatsPosition : String, | ||||
| StatsTitleAndSkill : String, | StatsTitleAndSkill : String, | ||||
| StatsJobMajor : 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, | |||||
| } | } | ||||
| } | } | 
| export const url : urlType.url = { | export const url : urlType.url = { | ||||
| userLogin: admin + '/user/login', | userLogin: admin + '/user/login', | ||||
| UserMenulist: admin + '/user/menulist', | UserMenulist: admin + '/user/menulist', | ||||
| SmsSend: common + '/sms/send', // 短信验证码 | |||||
| Captcha: common + '/captcha', // 获取验证码 | |||||
| // 角色 | // 角色 | ||||
| RoleAdd: admin + '/role/add', | RoleAdd: admin + '/role/add', | ||||
| RoleList: admin + '/role/list', | RoleList: admin + '/role/list', | 
| <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> | 
| import ACSelectCommon from '@/components/cSelect/common.vue'; | import ACSelectCommon from '@/components/cSelect/common.vue'; | ||||
| import UploadOne from '@/components/upload/one.vue'; | import UploadOne from '@/components/upload/one.vue'; | ||||
| import UploadFile from '@/components/upload/file.vue'; | import UploadFile from '@/components/upload/file.vue'; | ||||
| import ImageContainer from '@/components/form/image-container.vue'; | |||||
| import { Model } from 'node_modules/echarts/index'; | import { Model } from 'node_modules/echarts/index'; | ||||
| // router.beforeEach(async (to, from, next) => { | // router.beforeEach(async (to, from, next) => { | ||||
| app.component('a-xuanze', AXuanze); | app.component('a-xuanze', AXuanze); | ||||
| app.component('a-shujilian', AShujilian); | app.component('a-shujilian', AShujilian); | ||||
| app.component('search-select', SearchSelect); | app.component('search-select', SearchSelect); | ||||
| app.component('image-container', ImageContainer) | |||||
| app.component('a-c-select-common', ACSelectCommon); | app.component('a-c-select-common', ACSelectCommon); | ||||
| app.component('QuillEditor', QuillEditor) | app.component('QuillEditor', QuillEditor) | ||||
| app.component('upload-one', UploadOne) | app.component('upload-one', UploadOne) | 
| <a-col span="24"> | <a-col span="24"> | ||||
| <a-form-item label="上传文件,可将链接放入文章内容"> | <a-form-item label="上传文件,可将链接放入文章内容"> | ||||
| <upload-file @uploadSuccess="uploadDocSuccess"></upload-file> | <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-typography-paragraph> | ||||
| </a-form-item> | </a-form-item> | ||||
| </a-col> | </a-col> | ||||
| // 上传文件 | // 上传文件 | ||||
| const uploadDocSuccess = (data : Object) => { | const uploadDocSuccess = (data : Object) => { | ||||
| createForm.value.doc = data | |||||
| createForm.value.doc_url = data | |||||
| } | } | ||||
| // 选择栏目/频道 | // 选择栏目/频道 | 
| export let dataForm = { | export let dataForm = { | ||||
| title: '', | title: '', | ||||
| cover_img: '', | cover_img: '', | ||||
| doc: '', | |||||
| doc_url: '', | |||||
| section_id: 0, | section_id: 0, | ||||
| content: '', | content: '', | ||||
| stick_top: 0, | stick_top: 0, | ||||
| dataForm = { | dataForm = { | ||||
| title: '', | title: '', | ||||
| cover_img: '', | cover_img: '', | ||||
| doc: '', | |||||
| doc_url: '', | |||||
| section_id: 0, | section_id: 0, | ||||
| content: '', | content: '', | ||||
| stick_top: 0, | stick_top: 0, | 
| <h2 class="title">菊城人才市场招聘后台管理系统</h2> | <h2 class="title">菊城人才市场招聘后台管理系统</h2> | ||||
| <div class="sub-title">欢迎使用</div> | <div class="sub-title">欢迎使用</div> | ||||
| <a-form> | <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> | </a-form> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </template> | </template> | ||||
| <script lang="ts" setup> | <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 { useAsRouter } from '@/hooks/useAsRouter' | ||||
| import { UserOutlined, InfoCircleOutlined, LockOutlined, EyeInvisibleOutlined } from '@ant-design/icons-vue'; | import { UserOutlined, InfoCircleOutlined, LockOutlined, EyeInvisibleOutlined } from '@ant-design/icons-vue'; | ||||
| import { useCommon } from '@/hooks/useCommon'; | import { useCommon } from '@/hooks/useCommon'; | ||||
| let { message } = useCommon(); | let { message } = useCommon(); | ||||
| const { routerTo } = useAsRouter(); | const { routerTo } = useAsRouter(); | ||||
| let capt_id = ref<String>('') | |||||
| let codeImage = ref<String>('') | |||||
| const createForm = ref<Object>({ | const createForm = ref<Object>({ | ||||
| mobile: '', | 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 = () => { | const toLogin = () => { | ||||
| if (!createForm.value.mobile) { | if (!createForm.value.mobile) { | ||||
| if (!createForm.value.password) { | if (!createForm.value.password) { | ||||
| message.warning('请输入密码'); | message.warning('请输入密码'); | ||||
| return false; | return false; | ||||
| } | |||||
| } | |||||
| Login(createForm.value).then(res => { | Login(createForm.value).then(res => { | ||||
| sessionStorage.setItem('token', res.data.jwttoken.accesstoken); | sessionStorage.setItem('token', res.data.jwttoken.accesstoken); | ||||
| routerTo('/home'); | routerTo('/home'); | ||||
| // sessionStorage.setItem('token', '1321'); | // sessionStorage.setItem('token', '1321'); | ||||
| // routerTo('/home'); | // 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> | </script> | ||||
| <style lang="less"> | <style lang="less"> |