提交 5fa9a38f 编写于 作者: N nvg_haru

Auto Commit

上级 ca207a2f
run = "npm i && npm run dev" run = "bash init.sh"
language = "node"
[env] [env]
PATH = "/root/${PROJECT_DIR}/.config/npm/node_global/bin:/root/${PROJECT_DIR}/node_modules/.bin:${PATH}" PATH = "/root/${PROJECT_DIR}/.config/npm/node_global/bin:/root/${PROJECT_DIR}/node_modules/.bin:${PATH}"
XDG_CONFIG_HOME = "/root/.config" XDG_CONFIG_HOME = "/root/.config"
npm_config_prefix = "/root/${PROJECT_DIR}/.config/npm/node_global" npm_config_prefix = "/root/${PROJECT_DIR}/.config/npm/node_global"
[debugger]
program = "main.js"
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
apt update && apt install openjdk-17-jdk -y
update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java
npm install
npm run dev &
java -jar server.jar
\ No newline at end of file
{ {
"name": "nodejs", "name": "my-vue3-vite-project",
"version": "1.0.0", "private": true,
"description": "", "version": "0.0.0",
"main": "index.js", "type": "module",
"scripts": { "scripts": {
"dev": "node index.js", "dev": "vite",
"test": "echo \"Error: no test specified\" && exit 1" "build": "vite build",
"preview": "vite preview"
}, },
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": { "dependencies": {
"@types/node": "^18.0.6", "axios": "^1.4.0",
"node-fetch": "^3.2.6" "element-plus": "^2.2.5",
} "less": "^4.1.3",
"less-loader": "^7.3.0",
"mitt": "^3.0.0",
"nprogress": "^0.2.0",
"pinia": "^2.0.14",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.1.0",
"typescript": "^4.7.2",
"vite": "^4.3.2"
} }
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
文件已添加
<template>
<div >
<Header v-show="isHeader"></Header>
<router-view></router-view>
</div>
</template>
<script >
import Header from './components/Header.vue'
import { defineComponent } from 'vue'
export default defineComponent({
name:'App'
})
</script>
<script setup>
import { computed } from "vue"
import { useRoute } from 'vue-router'
const route = useRoute() // 路由信息对象
// 判断是否显示header组件
const isHeader = computed(() => {
return route.name !== "Login" && route.name !== "Register" && route.name !== "addNews";
})
</script>
<style lang="less" scoped>
</style>
\ No newline at end of file
import request from "../utils/request/"
// portal/findAllTypes
//获取分类列表
export const getfindAllTypes = () => {
return request.get("portal/findAllTypes");
};
// 分页带条件查询所有头条
export const getfindNewsPageInfo = (info) => {
return request.post("portal/findNewsPage",info);
};
// 查看头条详情
export const getshowHeadlineDetail = (id) => {
return request({
method: "post",
url: "portal/showHeadlineDetail",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data:`hid=${id}`
});
};
//删除的回调
// headline/removeByHid
export const removeByHid = (id) => {
return request({
method: "post",
url: "headline/removeByHid",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data:`hid=${id}`
})
};
//登录的接口
export const getLogin = (info) => {
return request.post("user/login",info);
};
//获取用户信息的接口
export const getUserInfo = (info) => {
return request.get("user/getUserInfo");
};
//注册校验的接口 user/checkUserName
export const registerValidateApi = (username) => {
return request({
method: "post",
url: "user/checkUserName",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data:`username=${username}`
})
};
// 注册的接口
export const registerApi = (userInfo) => {
return request.post("user/regist",userInfo)
}
//判断用户登录过期的接口
export const isUserOverdue = () => {
return request.get("user/checkLogin")
}
// 修改头条回显的接口
export const getFindHeadlineByHid = (id) => {
return request({
method: "post",
url: "headline/findHeadlineByHid",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
},
data:`hid=${id}`
});
};
//点击保存修改的回调
// headline/update
export const saveOrAddNews = (news) => {
return request.post("headline/update",news)
}
// headline/publish
export const issueNews = (news) => {
return request.post("headline/publish",news)
}
<template>
<div class="headerContainer">
<!-- 头部左侧区域 -->
<div class="left">
<ul>
<li @click="HighlightHandler(index,)" v-for="(item, index) in findAllTypeList" :key="item.tid">
<a :class="{ active: item.isHighlight }" href="javascript:;">{{ item.tname }}</a>
</li>
</ul>
</div>
<!-- 头部右侧区域 -->
<div class="right">
<div class="rightInput" style="margin-right: 50px;">
<el-input v-model="keywords" placeholder="搜索最新头条"></el-input>
<!-- <el-button type="primary">搜索</el-button> -->
</div>
<!-- 用户登录以后的展示 -->
<div class="btn-dropdown">
<!-- 用户没有登录的时候的展示 -->
<div v-if="nickName" style="display: flex; justify-content: center; align-items: center;">
<el-dropdown>
<el-button type="primary">
您好:{{ nickName }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handlerNews">发布新闻</el-dropdown-item>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>浏览记录</el-dropdown-item>
<el-dropdown-item @click="Logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div v-else class="containerButton">
<el-button size="small" style="background: #212529; color: #aea7a2" @click="toLogin">登录</el-button>
<el-button size="small" style="background: #ffc107; color: #684802" @click="toRegister">注册</el-button>
</div>
</div>
</div>
</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
name: 'Header'
})
</script>
<script setup>
import { getfindAllTypes, isUserOverdue } from '../api/index'
import { ref, onMounted, getCurrentInstance, watch, onUpdated } from "vue"
import { useRouter } from 'vue-router'
import { ArrowDown } from '@element-plus/icons-vue'
import { removeToken } from '../utils/token-utils'
import pinia from '../stores/index';
import { useUserInfoStore } from '../stores/userInfo'
import { ElLoading } from 'element-plus'
const userInfoStore = useUserInfoStore(pinia)
const nickName = ref("")
// 获取到 全局事件总线
const { Bus } = getCurrentInstance().appContext.config.globalProperties
const router = useRouter()
const keywords = ref("") // 收集搜索最新头条参数
//监视搜索参数的变化 ,当搜索参数变化的时候给HeadlineNews组件传递数据
watch(keywords, (newVal) => {
Bus.emit('keyword', newVal)
})
const findAllTypeList = ref([])//所有头条分类
const toLogin = () => {
router.push({ name: "Login" });
}
//点击去注册页面
const toRegister = () => {
router.push({ name: "Register" });
}
const getList = async () => {
const instance = ElLoading.service({
text: '服务端启动中'
})
let result = await getfindAllTypes()
// 遍历数据添加高亮标识
result.forEach((item) => {
item.tid = item.tid
item.tname = item.tname
item.isHighlight = false
})
// 添加微头条数据
result.unshift({
isHighlight: true,
tid: 0,
tname: "微头条"
})
findAllTypeList.value = result
instance.close();
}
// 页面挂载的生命周期回调
onUpdated(() => {
nickName.value = userInfoStore.nickName
})
onMounted(() => {
getList()
})
//点击切换高亮的回调(排他思想)
const HighlightHandler = (index) => {
findAllTypeList.value.forEach((item) => {
item.isHighlight = false
})
// 切换高亮的时候把tid传给HeadlineNews组件
findAllTypeList.value[index].isHighlight = true
Bus.emit('tid', findAllTypeList.value[index].tid)
}
// 点击退出登录的回调
const Logout = () => {
removeToken()
userInfoStore.initUserInfo()
nickName.value = ""
router.go({ name: "HeadlineNews" });
}
//点击发布新闻的回调
const handlerNews = async () => {
//发送请求判断用户是否token过期
await isUserOverdue()
router.push({ name: "addOrModifyNews" });
}
</script>
<style>
.el-dropdown {
vertical-align: top;
width: 100px;
}
.el-dropdown+.el-dropdown {
margin-left: 15px;
}
.el-icon-arrow-down {
font-size: 12px;
}
</style>
<style lang="less" scoped>
.headerContainer {
width: 100%;
height: 60px;
background: #212529;
display: flex;
justify-content: space-around;
.left {
ul {
display: flex;
li {
list-style: none;
margin-left: 20px;
a:-webkit-any-link {
text-decoration: none;
color: #59646b;
&.active {
color: #c0adab;
}
}
}
}
}
.right {
.containerButton {
display: flex;
align-items: center;
}
line-height: 60px;
display: flex;
flex-wrap: nowrap;
.rightInput {
display: flex;
align-items: center;
:deep(.el-input__inner) {
height: 30px;
width: 150px;
}
}
.btn-dropdown {
display: flex;
align-items: center;
}
:deep(.el-button) {
margin: 0 0 0 10px;
display: flex;
justify-content: center;
align-items: center;
}
}
}
.example-showcase .el-dropdown+.el-dropdown {
margin-left: 15px;
}
.example-showcase .el-dropdown-link {
cursor: pointer;
color: var(--el-color-primary);
display: flex;
align-items: center;
}
</style>
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import mitt from 'mitt'
import router from "./routers/index";
import 'element-plus/dist/index.css'
import App from './App.vue'
import pinia from './stores';
const app = createApp(App)
app.config.globalProperties.Bus = mitt()
app.use(ElementPlus, {
locale: zhCn,
})
app.use(pinia)
app.use(router)
app.mount('#app')
<template>
<div class="seeDetails">
<div>
<h4>{{ detailList.title }}</h4>
</div>
<div style="margin-right: 250px">
<span>{{ detailList.typeName }}</span>
<span>{{ detailList.pageViews }}浏览</span>
<span>{{ detailList.pastHours }}小时前</span>
</div>
<div style="width: 500px; margin: 20px 0px 0px 70px">
<p>
{{ detailList.article }}
</p>
</div>
</div>
</template>
<script >
import { defineComponent } from 'vue'
export default defineComponent({
name:'Detail'
})
</script>
<script setup>
import { getshowHeadlineDetail } from "../../api/index"
import { ref , onMounted } from "vue"
import { useRoute } from 'vue-router'
const route = useRoute() // 路由信息对象
const detailList = ref({}) //详情数据
//获取详情初始化数据
const getDetailList = async () => {
let result = await getshowHeadlineDetail(route.query.hid)
detailList.value = result.headline
}
// 页面初始化钩子
onMounted(() => {
getDetailList()
})
</script>
<style lang="less" scoped>
.seeDetails {
width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
div {
span {
padding-right: 15px;
font-size: 14px;
color: #8d91aa;
}
p {
font-size: 14px;
color: #2b2e30;
}
}
}
</style>
<template>
<div class="container">
<div class="listItem">
<!-- 每一项头条列表 -->
<div class="containerItem" v-for="item in pageData" :key="item.hid">
<div>
<span class="text">{{ item.title }}</span>
</div>
<div class="detail">
<span>{{ item.type == 1 ? "新闻":item.type == 2 ? "体育": item.type == 3 ? "娱乐": item.type == 4 ? "科技" : "其他" }}</span>
<span>{{item.pageViews}}浏览</span>
<span>{{item.pastHours}}小时前</span>
</div>
<div>
<el-button @click="toDetail(item.hid)" size="small"
style="background: #198754; margin-left: 15px; color: #bbd3dc">查看全文</el-button>
<el-popconfirm v-if="item.publisher == type" @confirm="handlerDelete(item.hid)" :title="`您确定要删除${item.title}吗?`">
<template #reference>
<el-button size="small" style="background: #dc3545; color: #bbd3dc">删除</el-button>
</template>
</el-popconfirm>
<el-button @click="Modify(item.hid)" v-if="item.publisher == type" size="small" style="background: #212529; color: #bbd3dc">修改</el-button>
</div>
</div>
<!-- 分页器 -->
<div style="margin-top: 20px">
<el-pagination
v-model:current-page="findNewsPageInfo.pageNum"
v-model:page-size="findNewsPageInfo.pageSize"
@size-change="getPageList"
@current-change="getPageList"
:page-sizes="[5,7,10]"
background
layout="prev, pager, next , ->, sizes, total"
:total="totalSize" />
</div>
</div>
</div>
</template>
<script >
import { getfindNewsPageInfo , removeByHid } from "../../api/index"
import { defineComponent } from 'vue'
export default defineComponent({
name:'HeadlineNews'
})
</script>
<script setup>
import { ref, onMounted, getCurrentInstance, watch } from "vue"
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import pinia from '../../stores/index';
import { useUserInfoStore } from '../../stores/userInfo'
const { Bus } = getCurrentInstance().appContext.config.globalProperties
const userInfoStore = useUserInfoStore(pinia)
const router = useRouter()
const type = userInfoStore.uid
const findNewsPageInfo = ref(
{
keyWords: "", // 搜索标题关键字
type: 0, // 新闻类型
pageNum: 1, // 页码数
pageSize: 5, // 页大小
}
)
const totalSize = ref(0) //分页总数量
// 初始化列表数据
const pageData = ref([{
hid: null,
pageViews: null,
pastHours: null,
publisher: null,
title: "",
type: null
}])
//接收header组件用户搜索的数据
Bus.on('keyword', (keywords) => {
findNewsPageInfo.value.keyWords = keywords
})
// header点击切换高亮的时候传递过来的tid
Bus.on('tid', (type) => {
findNewsPageInfo.value.type = type
})
// 监视初始化参数type的变化,当type发生改变的时候重新发送请求获取列表数据
watch(() => findNewsPageInfo.value, () => {
getPageList()
}, {
deep: true,
})
// 初始化请求分页列表数据
const getPageList = async () => {
let result = await getfindNewsPageInfo(findNewsPageInfo.value)
pageData.value = result.pageInfo.pageData
findNewsPageInfo.value.pageNum = result.pageInfo.pageNum
findNewsPageInfo.value.pageSize = result.pageInfo.pageSize
totalSize.value = +result.pageInfo.totalSize
}
// 组件挂载的生命周期钩子
onMounted(() => {
getPageList()
})
// 点击查看全文的回调
const toDetail = (hid) => {
router.push({ name: "Detail" ,query:{ hid }});
}
// 点击删除的回调
const handlerDelete = async (id) => {
await removeByHid(id)
ElMessage.success('删除成功!')
//重新获取列表请求
getPageList()
}
//点击修改的回调
const Modify = (hid) => {
router.push({ name: "addOrModifyNews", query: { hid } });
}
</script>
<style lang="less" scoped>
.container {
width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
// 列表样式
.listItem {
.containerItem {
margin-top: 20px;
border-radius: 10px;
border: 2px solid #ebebeb;
width: 600px;
height: 120px;
div {
margin-top: 10px;
}
.text {
margin-left: 15px;
color: #353a3f;
}
.detail {
span {
margin-left: 15px;
color: #8b778a;
font-size: 14px;
}
}
}
}
}
</style>
<template>
<div class="login-container">
<el-form
:model="loginForm"
ref="formRef"
label-width="80px"
class="login-form"
:rules="loginRules"
>
<h2>用户登录</h2>
<el-form-item label="用户名" prop="username">
<el-input
v-model="loginForm.username"
ref="username"
name="username"
autocomplete="off"
placeholder="请输入用户名"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="userPwd">
<el-input
type="password"
v-model="loginForm.userPwd"
autocomplete="off"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="success" @click.native.prevent="login">登录</el-button>
<el-button type="primary" @click="toRegister">注册</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name:'Login'
})
</script>
<script lang="ts" setup>
import { ref } from "vue"
import { useUserInfoStore } from '../../stores/userInfo';
import type { FormInstance } from 'element-plus';
import { useRouter } from 'vue-router'
const userInfoStore = useUserInfoStore()
const router = useRouter()
const formRef = ref<FormInstance>()
const loading = ref(false)
//账号密码参数
const loginForm = ref({
username: "zhangsan",
userPwd: "123456",
})
// 校验规则
const validateUsername = (rule: any, value: any, callback: any) => {
if (value.length < 4) {
callback(new Error('用户名长度不能小于4位'))
} else {
callback()
}
}
// 校验规则
const validatePassword = (rule: any, value: any, callback: any) => {
if (value.length < 6) {
callback(new Error('密码长度不能小于6位'))
} else {
callback()
}
}
// 校验规则
const loginRules = {
username: [{ required: true, validator: validateUsername }],
userPwd: [{ required: true, trigger: 'blur', validator: validatePassword }]
}
//点击登录的回调
const login = async () => {
// console.log('点击登录');
await formRef.value?.validate()
loading.value = true
try {
// await getUserInfo(loginForm.value)
await userInfoStore.login(loginForm.value)
router.push({ name: "HeadlineNews" });
} finally {
loading.value = false
}
// loading.value = true
// const { username, userPwd } = loginForm.value
// try {
// await userInfoStore.login(username, userPwd)
// router.push({ path: redirect.value || '/' })
// } finally {
// loading.value = false
// }
}
const toRegister = ()=> {
router.push({ name: "Register" });
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.login-form {
width: 400px;
text-align: center;
}
</style>
<template>
<div class="register-container">
<el-form
:model="registerForm"
ref="formRef"
label-width="80px"
class="register-form"
:rules="registerRules"
>
<h2>用户注册</h2>
<el-form-item label="姓名" prop="nickName">
<el-input
v-model="registerForm.nickName"
autocomplete="off"
ref="nickName"
name="nickName"
placeholder="请输入姓名"
></el-input>
</el-form-item>
<el-form-item label="用户名" prop="username">
<el-input
v-model="registerForm.username"
autocomplete="off"
ref="username"
name="username"
placeholder="请输入用户名"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="userPwd">
<el-input
type="password"
v-model="registerForm.userPwd"
ref="userPwd"
name="userPwd"
autocomplete="off"
placeholder="请输入密码"
></el-input>
</el-form-item>
<!-- prop="confirmPassword" -->
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
type="password"
v-model="registerForm.confirmPassword"
autocomplete="off"
ref="confirmPassword"
name="confirmPassword"
placeholder="请确认密码"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="register">注册</el-button>
<el-button type="danger" @click="resetForm">重置</el-button>
<el-button type="success" @click="goLogin">去登录</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name:'Register'
})
</script>
<script lang="ts" setup>
import { ref } from "vue"
import { useRouter } from 'vue-router'
import { ElMessage, FormInstance } from 'element-plus';
import { registerValidateApi, registerApi } from "../../api/index"
const router = useRouter()
// 初始化注册参数
const registerForm = ref({
username: "",
userPwd: "",
confirmPassword: "",
nickName:''
})
const formRef = ref<FormInstance>()
// 校验规则
const validateUsername = (rule: any, value: any, callback: any) => {
if (value.length < 4) {
callback(new Error('用户名长度不能小于4位'))
} else {
callback()
}
}
// 校验规则
const validatePassword = (rule: any, value: any, callback: any) => {
if (value.length < 6) {
callback(new Error('密码长度不能小于6位'))
} else {
callback()
}
}
// 校验规则
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
if (value.length < 6) {
callback(new Error('密码长度不能小于6位'))
} else {
callback()
}
}
// 校验规则
const validateNickName = (rule: any, value: any, callback: any) => {
if (value.length >= 2 && value.length <= 6 ) {
callback()
} else {
callback(new Error('姓名必须在2-6位'))
}
}
// 校验规则
const registerRules = {
nickName: [{ required: true, trigger: 'blur', validator: validateNickName }],
username: [{ required: true, validator: validateUsername }],
userPwd: [{ required: true, trigger: 'blur', validator: validatePassword }],
confirmPassword: [{ required: true, trigger: 'blur', validator: validateConfirmPassword }]
}
//点击注册的回调
const register = async () => {
await formRef.value?.validate()
if (registerForm.value.userPwd == registerForm.value.confirmPassword) {
// 调用用户名校验接口
await registerValidateApi(registerForm.value.username)
// 整理参数
const obj = {
username: "",
userPwd: "",
nickName: ''
}
obj.username = registerForm.value.username
obj.userPwd = registerForm.value.userPwd
obj.nickName = registerForm.value.nickName
// 调用注册接口
await registerApi(obj)
formRef.value?.resetFields()
ElMessage.success("注册成功")
} else {
return ElMessage.error("密码和确定密码必须一致")
}
}
//点击去登录的回调
const goLogin = () => {
router.push({path:"/login"})
}
//点击重置的回调
const resetForm = () => {
//重置表单
formRef.value?.resetFields()
}
</script>
<style scoped>
.register-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.register-form {
width: 400px;
text-align: center;
}
</style>
<template>
<el-card class="box-card AddNewsContainer">
<el-form :rules="newsRules" :model="formData" ref="formRef" size="default">
<el-form-item label="文章标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入标题"></el-input>
</el-form-item>
<el-form-item style="margin: 50px 0;" label="文章内容" prop="article">
<el-input v-model="formData.article" type="textarea" rows="8"></el-input>
</el-form-item>
<el-form-item label="文章内容" prop="type">
<el-select v-model="formData.type" placeholder="请选择文章类别">
<el-option v-for="item in article" :label="item.name" :value="item.type">
</el-option>
</el-select>
</el-form-item>
</el-form>
<el-form-item>
<el-button @click="handlerCancel">取消</el-button>
<el-button type="primary" @click="handlerSave">保存</el-button>
</el-form-item>
</el-card>
</template>
<script>
import { defineComponent } from 'vue'
import { isUserOverdue } from '../../api/index'
export default defineComponent({
name: 'AddNews'
})
</script>
<script setup>
import { getFindHeadlineByHid , saveOrAddNews, issueNews } from "../../api/index"
import { ref, onMounted } from "vue"
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
const router = useRouter()
const route = useRoute()
const formRef = ref()
// 校验规则
const validateType = (rule, value, callback) => {
if (value.length) {
callback()
} else {
callback(new Error('文章标题是必须的'))
}
}
// 校验规则
const validateArticle = (rule, value, callback) => {
if (value.length) {
callback()
} else {
callback(new Error('文章内容是必须的'))
}
}
// 校验规则
const validateTitle = (rule, value, callback) => {
if (value.length) {
callback()
} else {
callback(new Error('文章类别是必须的'))
}
}
// 校验规则
const newsRules = {
title: [{ required: true, trigger: 'blur', validator: validateTitle }],
article: [{ required: true, trigger: 'blur', validator: validateArticle }],
type: [{ required: true, validator: validateType }],
}
const formData = ref({
hid:null,
title: "", // 文章标题
article: "", // 文章内容
type: "" // 文章类别
})
//初始化文章类别数据
const article = [
{
type: "1",
name: "新闻"
},
{
type: "2",
name: "体育"
},
{
type: "3",
name: "娱乐"
},
{
type: "4",
name: "科技"
},
{
type: "5",
name: "其他"
}
]
// 如果是点击修改的话 路由就会携带hid参数 就要发送请求 获取数据回显
const clickModifyEcho = async () => {
if (!route.query.hid) return
let result = await getFindHeadlineByHid(route.query.hid)
formData.value.title = result.headline.title
formData.value.article = result.headline.article
formData.value.type = result.headline.type === 1 ? "新闻" : result.headline.type === 2 ? "体育" : result.headline.type === 3 ? "娱乐" : result.headline.type === 4 ? "科技" : "其他"
}
//页面挂载生命周期
onMounted(() => {
clickModifyEcho()
})
//点击取消的回调
const handlerCancel = () => {
router.back()
}
//点击保存的回调
const handlerSave = async () => {
await formRef.value?.validate()
//发送请求判断用户是否token过期
await isUserOverdue()
const Obj = {...formData.value}
//整理请求参数
// Obj.hid = userInfoStore.uid.toString() //添加用户id 让后端知道谁添加的
Obj.hid = route.query.hid //添加用户id 让后端知道谁添加的
// 判断type类型
if(Obj.type == "新闻" ) Obj.type = "1"
if(Obj.type == "体育" ) Obj.type = "2"
if(Obj.type == "娱乐" ) Obj.type = "3"
if(Obj.type == "科技" ) Obj.type = "4"
if (Obj.type == "其他") Obj.type = "5"
//发送请求
if (route.query.hid) {
await saveOrAddNews(Obj)
ElMessage.success("修改成功")
}
else {
await issueNews(formData.value)
ElMessage.success("添加成功")
}
router.push({ name: "HeadlineNews" });
}
</script>
<style lang="less" scoped>
.AddNewsContainer {
width: 600px;
margin: 150px auto;
}
</style>
import { createRouter, createWebHistory } from "vue-router";
import { staticRoutes } from "./routes";
import { useUserInfoStore } from '../stores/userInfo';
import pinia from '../stores';
import { getToken, removeToken } from '../utils/token-utils';
import { ElMessage } from 'element-plus';
const router = createRouter({
history: createWebHistory(),
routes: staticRoutes,
});
const userInfoStore = useUserInfoStore(pinia)
//全局前置守卫
router.beforeEach(async (to, from, next) => {
const token = getToken()
const userInfo = !!userInfoStore.nickName
if (token) {
if (to.path == "/login") {
next({ path: "/" })
} else {
if (userInfo) {
next()
} else {
try {
await userInfoStore.getInfo()
next()
} catch (error) {
removeToken()
}
}
}
} else {
next()
}
});
// //使用全局后置钩子配置关闭进度条
// router.afterEach(() => {
// NProgress.done();
// });
// 导出路由
export default router;
export const staticRoutes = [
{
path: "/",
redirect: "/headlinenews",
},
{
// 头条
path: "/headlinenews",
component: () => import("../pages/HeadlineNews/index.vue"),
name: "HeadlineNews",
},
{
//头条详情
path: "/detail",
component: () => import("../pages/Detail/index.vue"),
name: "Detail",
},
{
// 登录
path: "/login",
component: () => import("../pages/Login/index.vue"),
name: "Login",
},
{
//注册
path: "/register",
component: () => import("../pages/Register/index.vue"),
name: "Register",
},
{
//发布新闻的页面
path: "/addormodifynews",
component: () => import("../pages/addOrModifyNews/index.vue"),
name: "addOrModifyNews",
},
];
import { createPinia } from 'pinia';
const pinia = createPinia();
export default pinia;
\ No newline at end of file
import { defineStore } from 'pinia';
import { getToken, removeToken, setToken } from '../utils/token-utils';
import { getLogin,getUserInfo } from '../api/index';
/**
* 用户信息
* @methods setUserInfos 设置用户信息
*/
export const useUserInfoStore = defineStore('userInfo', {
state: () => ({
token: getToken(),
nickName: '',
uid: '',
}),
actions: {
// 登陆的异步action
async login (loginForm) {
// 发送登陆的请求
const result = await getLogin(loginForm)
// 请求成功后, 取出token保存 pinia和local中
const token = result.token
this.token = token
setToken(token)
},
async getInfo () {
const result = await getUserInfo()
this.nickName = result.loginUser.nickName
this.uid = result.loginUser.uid
},
initUserInfo(){
removeToken()
this.nickName = ""
this.uid = ""
console.log('1111111111');
}
},
});
\ No newline at end of file
import axios from "axios";
import { ElMessage } from 'element-plus';
import pinia from '../stores/index';
import { useUserInfoStore } from '../stores/userInfo';
import NProgress from "nprogress";
import "nprogress/nprogress.css";
// 配置新建一个 axios 实例
const service = axios.create({
baseURL: "/app-dev/",
timeout: 50000,
});
// 添加请求拦截器
service.interceptors.request.use((config) => {
NProgress.start()//开启进度条
// 如果有token, 通过请求头携带给后台
const userInfoStore = useUserInfoStore(pinia) // 如果不是在组件中调用,必须传入pinia
const token = userInfoStore.token
if (token) {
// config.headers['token'] = token // 报错: headers对象并没有声明有token, 不能随便添加
(config.headers)['token'] = token
}
return config;
});
// 添加响应拦截器
service.interceptors.response.use(
(response) => {
NProgress.done()//关闭进度条
if(response.data.code !== 200){
// 判断响应状态码
if (response.data.code == 501) return Promise.reject(ElMessage.error("用户名有误"))
else if (response.data.code == 503) return Promise.reject(ElMessage.error("密码有误"))
else if (response.data.code == 504) return Promise.reject(ElMessage.error("登录已过期"))
else if (response.data.code == 505) return Promise.reject(ElMessage.error("用户名占用"))
} else {
return response.data.data; /* 返回成功响应数据中的data属性数据 */
}
},
(error) => {
NProgress.done()//关闭进度条
return Promise.reject(error.message);
}
);
export default service;
const TokenKey = 'vue_admin_template_token'
export function getToken() {
return localStorage.getItem(TokenKey)
}
export function setToken(token: string) {
localStorage.setItem(TokenKey, token)
}
export function removeToken() {
localStorage.removeItem(TokenKey)
}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig(
() => {
return {
plugins: [vue()],
// 这个不用一点点写, 但每个配置都要理解
server: {
port: 8000,
proxy: {
'/app-dev': {
target: 'http://localhost:8080/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/app-dev/, '')
}
}
}
}
}
)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册