完成登录注册模块的接口与页面

修复首页图标未能正常获取的bug

完成小程序端部分接口对接
pull/75/head
riverflow 1 month ago
parent cfdb4c6122
commit 5aad968993

@ -53,6 +53,10 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
</dependencies>
<build>

@ -0,0 +1,48 @@
package com.itmk.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.util.StringUtils;
import javax.crypto.SecretKey;
import java.util.Date;
public class JwtUtils {
// 使用 Keys.secretKeyFor 生成足够强的密钥512位
private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS512);
private static final long EXPIRATION_TIME = 86400000; // 24小时
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SECRET_KEY, SignatureAlgorithm.HS512)
.compact();
}
public static Claims getClaimsByToken(String token) {
if (StringUtils.isEmpty(token)) {
return null;
}
try {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.build()
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
System.out.println("validate is token error, token: " + token + ", error: " + e);
return null;
}
}
public static String getSubject(String token) {
Claims claims = getClaimsByToken(token);
return claims != null ? claims.getSubject() : null;
}
}

@ -7,6 +7,8 @@ import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.order.entity.*;
import com.itmk.web.order.service.UserOrderService;
import com.itmk.web.order_detail.entity.UserOrderDetail;
import com.itmk.web.order_detail.service.UserOrderDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@ -18,98 +20,127 @@ public class UserOrderController {
@Autowired
private UserOrderService userOrderService;
//下的
@Autowired
private UserOrderDetailService userOrderDetailService;
//下单
@PostMapping("/splaceOrder")
public ResultVo splaceOrder(@RequestBody OrderParm parm){
public ResultVo splaceOrder(@RequestBody OrderParm parm) {
userOrderService.splaceOrder(parm);
return ResultUtils.success("提交成功!");
}
//查询订单
@GetMapping("/getOrderList")
public ResultVo getOrderList(WxOrderParm parm){
public ResultVo getOrderList(WxOrderParm parm) {
IPage<UserOrder> orderList = userOrderService.getOrderList(parm);
return ResultUtils.success("查询成功!",orderList);
return ResultUtils.success("查询成功!", orderList);
}
//查询pc订单
@GetMapping("/getPcOrderList")
public ResultVo getPcOrderList(WxOrderParm parm){
public ResultVo getPcOrderList(WxOrderParm parm) {
IPage<UserOrder> orderList = userOrderService.getPcOrderList(parm);
return ResultUtils.success("查询成功!",orderList);
return ResultUtils.success("查询成功!", orderList);
}
//发货
@PutMapping("/sendOrder")
public ResultVo sendOrder(@RequestBody SendParm parm){
public ResultVo sendOrder(@RequestBody SendParm parm) {
//判断订单是否被取消
QueryWrapper<UserOrder> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserOrder::getOrderId,parm.getOrderId()).eq(UserOrder::getStatus,"3");
queryWrapper.lambda().eq(UserOrder::getOrderId, parm.getOrderId()).eq(UserOrder::getStatus, "3");
UserOrder one = userOrderService.getOne(queryWrapper);
if(one != null){
if (one != null) {
return ResultUtils.error("订单已被取消,不能发货!");
}
//更新条件
LambdaUpdateWrapper<UserOrder> query = new LambdaUpdateWrapper<>();
query.eq(UserOrder::getOrderId,parm.getOrderId())
.set(UserOrder::getStatus,"1");
if(userOrderService.update(query)){
query.eq(UserOrder::getOrderId, parm.getOrderId())
.set(UserOrder::getStatus, "1");
if (userOrderService.update(query)) {
return ResultUtils.success("更新成功!");
}
return ResultUtils.error("更新失败!");
}
//取消订单
@PostMapping("/cancelOrder")
public ResultVo cancelOrder(@RequestBody SendParm parm){
public ResultVo cancelOrder(@RequestBody SendParm parm) {
//如果已发货,不能取消
QueryWrapper<UserOrder> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(UserOrder::getOrderId,parm.getOrderId()).eq(UserOrder::getStatus,"1");
queryWrapper.lambda().eq(UserOrder::getOrderId, parm.getOrderId()).eq(UserOrder::getStatus, "1");
UserOrder one = userOrderService.getOne(queryWrapper);
if(one != null){
if (one != null) {
return ResultUtils.error("订单已发货,不能取消!");
}
//更新条件
LambdaUpdateWrapper<UserOrder> query = new LambdaUpdateWrapper<>();
query.eq(UserOrder::getOrderId,parm.getOrderId())
.set(UserOrder::getStatus,"3");
if(userOrderService.update(query)){
query.eq(UserOrder::getOrderId, parm.getOrderId())
.set(UserOrder::getStatus, "3");
if (userOrderService.update(query)) {
return ResultUtils.success("取消成功!");
}
return ResultUtils.error("取消失败!");
}
//确定收货
@PostMapping("/confirmOrder")
public ResultVo confirmOrder(@RequestBody SendParm parm){
public ResultVo confirmOrder(@RequestBody SendParm parm) {
//更新条件
LambdaUpdateWrapper<UserOrder> query = new LambdaUpdateWrapper<>();
query.eq(UserOrder::getOrderId,parm.getOrderId())
.set(UserOrder::getStatus,"2");
if(userOrderService.update(query)){
query.eq(UserOrder::getOrderId, parm.getOrderId())
.set(UserOrder::getStatus, "2");
if (userOrderService.update(query)) {
return ResultUtils.success("收货成功!");
}
return ResultUtils.error("收货失败!");
}
// 在 UserOrderController 中添加删除订单接口
@DeleteMapping("/{orderId}")
public ResultVo deleteOrder(@PathVariable Long orderId) {
// 先删除订单详情
QueryWrapper<UserOrderDetail> detailQuery = new QueryWrapper<>();
detailQuery.lambda().eq(UserOrderDetail::getOrderId, orderId);
userOrderDetailService.remove(detailQuery);
// 再删除订单
if (userOrderService.removeById(orderId)) {
return ResultUtils.success("删除成功!");
}
return ResultUtils.error("删除失败!");
}
//首页统计 0:日 1月 2
@GetMapping("/getTotal")
public ResultVo getTotal(String type){
List<SunList> list = null;
switch (type){
case "1":
list = userOrderService.getMonths();
break;
case "2":
list = userOrderService.getYears();
break;
default:
list = userOrderService.getDays();
}
Echarts echarts = new Echarts();
if(list!= null && list.size() >0){
for (int i=0;i<list.size();i++){
echarts.getNames().add(list.get(i).getDays());
echarts.getValues().add(list.get(i).getPrice());
public ResultVo getTotal(String type) {
try {
List<SunList> list = null;
switch (type) {
case "1":
list = userOrderService.getMonths();
break;
case "2":
list = userOrderService.getYears();
break;
default:
list = userOrderService.getDays();
}
Echarts echarts = new Echarts();
if (list != null && list.size() > 0) {
for (SunList sun : list) {
// 添加空值检查
if (sun.getDays() != null && sun.getPrice() != null) {
echarts.getNames().add(sun.getDays());
echarts.getValues().add(sun.getPrice());
}
}
}
return ResultUtils.success("查询成功", echarts);
} catch (Exception e) {
e.printStackTrace();
return ResultUtils.error("统计查询失败: " + e.getMessage());
}
return ResultUtils.success("查询成功",echarts);
}
}

@ -5,22 +5,27 @@ import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itmk.utils.JwtUtils;
import com.itmk.utils.ResultUtils;
import com.itmk.utils.ResultVo;
import com.itmk.web.user.entity.SysUser;
import com.itmk.web.user.entity.UserPageParm;
import com.itmk.web.user.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/user")//所有含有/api/user的请求都交给这个控制器处理
public class SysUserController {
// 注入服务类
// 注入服务类
@Autowired
private SysUserService sysUserService;
// 新增用户
// 新增用户
@PostMapping//使用post请求
public ResultVo addUser(@RequestBody SysUser sysUser) {
// 1. 单独检查用户名
@ -43,41 +48,110 @@ public class SysUserController {
: ResultUtils.error("新增用户失败!");
}
// 编辑用户
// 编辑用户
@PutMapping
public ResultVo editUser(@RequestBody SysUser sysUser){
if(sysUserService.updateById(sysUser)){
public ResultVo editUser(@RequestBody SysUser sysUser) {
if (sysUserService.updateById(sysUser)) {
return ResultUtils.success("编辑用户成功!", sysUser);
}
return ResultUtils.error("编辑用户失败!");
}
// 删除用户
// 删除用户
@DeleteMapping("/{userId}")//delete请求时需要指定参数传递参数用户id
// 接收参数
public ResultVo deleteUser(@PathVariable Long userId){
if(sysUserService.removeById(userId)){
public ResultVo deleteUser(@PathVariable Long userId) {
if (sysUserService.removeById(userId)) {
return ResultUtils.success("删除用户成功!");
}
return ResultUtils.error("删除用户失败!");
}
// 列表查询
// 列表查询
// 列表查询需要分页
@GetMapping("/list")
public ResultVo getList(UserPageParm parm){
public ResultVo getList(UserPageParm parm) {
// 构造分页对象
IPage<SysUser> page = new Page<>(parm.getCurrentPage(),parm.getPageSize());
IPage<SysUser> page = new Page<>(parm.getCurrentPage(), parm.getPageSize());
// 构造查询条件
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
// 当parm.getName()或parm.getPhone()不为空时,设置查询条件,根据姓名和手机号模糊查询
queryWrapper.lambda().like(!StringUtils.isEmpty(parm.getName()),SysUser::getName,parm.getName())
.like(!StringUtils.isEmpty(parm.getPhone()),SysUser::getPhone,parm.getPhone())
queryWrapper.lambda().like(!StringUtils.isEmpty(parm.getName()), SysUser::getName, parm.getName())
.like(!StringUtils.isEmpty(parm.getPhone()), SysUser::getPhone, parm.getPhone())
// 根据姓名升序排序
.orderByAsc(SysUser::getName);
IPage<SysUser> list = sysUserService.page(page,queryWrapper);
IPage<SysUser> list = sysUserService.page(page, queryWrapper);
return ResultUtils.success("查询成功!", list);
}
return ResultUtils.success("查询成功!",list);
// 用户注册接口
@PostMapping("/register")
public ResultVo register(@RequestBody SysUser sysUser) {
// 检查用户名是否已存在
if (sysUserService.lambdaQuery()
.eq(SysUser::getUsername, sysUser.getUsername())
.exists()) {
return ResultUtils.error("用户名已存在!");
}
// 检查手机号是否已存在
if (sysUserService.lambdaQuery()
.eq(SysUser::getPhone, sysUser.getPhone())
.exists()) {
return ResultUtils.error("手机号已被使用!");
}
// 对密码进行MD5加密
String md5Password = DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes());
sysUser.setPassword(md5Password);
// 保存用户
if (sysUserService.save(sysUser)) {
return ResultUtils.success("注册成功!");
}
return ResultUtils.error("注册失败!");
}
// 用户登录接口
@PostMapping("/login")
public ResultVo login(@RequestBody SysUser sysUser) {
// 对密码进行MD5加密
String md5Password = DigestUtils.md5DigestAsHex(sysUser.getPassword().getBytes());
// 查询用户
QueryWrapper<SysUser> query = new QueryWrapper<>();
query.lambda().eq(SysUser::getUsername, sysUser.getUsername())
.eq(SysUser::getPassword, md5Password);
SysUser user = sysUserService.getOne(query);
if (user != null) {
// 生成token
String token = JwtUtils.generateToken(user.getUsername());
// 返回用户信息和token
Map<String, Object> result = new HashMap<>();
result.put("user", user);
result.put("token", token);
return ResultUtils.success("登录成功!", result);
}
return ResultUtils.error("用户名或密码错误!");
}
// 根据token获取用户信息
@GetMapping("/getUserInfo")
public ResultVo getUserInfo(@RequestHeader("token") String token) {
String username = JwtUtils.getClaimsByToken(token).getSubject();
SysUser user = sysUserService.lambdaQuery()
.eq(SysUser::getUsername, username)
.one();
if (user != null) {
// 不返回密码
user.setPassword(null);
return ResultUtils.success("查询成功", user);
}
return ResultUtils.error("用户不存在");
}
}

@ -15,14 +15,19 @@ public class WxUserController {
@PostMapping("/saveOrUpdate")
public ResultVo saveOrUpdate(@RequestBody WxUser wxUser){
wxUserService.saveOrUpdate(wxUser);
return ResultUtils.success("更新成功!");
// 使用 MyBatis Plus 自带的 saveOrUpdate 方法
boolean result = wxUserService.saveOrUpdate(wxUser);
if(result) {
return ResultUtils.success("更新成功!");
} else {
return ResultUtils.error("更新失败!");
}
}
//查询头像昵称
@GetMapping("/getUserInfo")
public ResultVo getUserInfo(String openid) {
WxUser user = wxUserService.getById(openid);
return ResultUtils.error("查询成功!",user);
return ResultUtils.success("查询成功!",user);
}
}

@ -4,12 +4,25 @@
<mapper namespace="com.itmk.web.order.mapper.UserOrderMapper">
<select id="getDays" resultType="com.itmk.web.order.entity.SunList">
select DATE_FORMAT(create_time,'%Y-%m-%d')days,sum(price)price from order where `status` = '2' group by days order by days asc
select DATE_FORMAT(create_time, '%Y-%m-%d') days, sum(price) price
from `user_order`
where `status` = '2'
group by days
order by days asc
</select>
<select id="getMonths" resultType="com.itmk.web.order.entity.SunList">
select DATE_FORMAT(create_time,'%Y-%m')days,sum(price)price from order where `status` = '2' group by days order by days asc
</select><select id="getYears" resultType="com.itmk.web.order.entity.SunList">
select DATE_FORMAT(create_time,'%Y')days,sum(price)price from order where `status` = '2' group by days order by days asc
</select>
select DATE_FORMAT(create_time, '%Y-%m') days, sum(price) price
from `user_order`
where `status` = '2'
group by days
order by days asc
</select>
<select id="getYears" resultType="com.itmk.web.order.entity.SunList">
select DATE_FORMAT(create_time, '%Y') days, sum(price) price
from `user_order`
where `status` = '2'
group by days
order by days asc
</select>
</mapper>

@ -0,0 +1,41 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itmk.web.wx_user.mapper.WxUserMapper">
<insert id="saveOrUpdateInfo" parameterType="com.itmk.web.wx_user.entity.WxUser">
insert into wx_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="user.openid != null and user.openid !=''">
openid,
</if>
<if test="user.nickName != null and user.nickName !=''">
nick_name,
</if>
<if test="user.avatarUrl != null and user.avatarUrl !=''">
avatar_url,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="user.openid != null and user.openid !=''">
#{user.openid},
</if>
<if test="user.nickName != null and user.nickName !=''">
#{user.nickName},
</if>
<if test="user.avatarUrl != null and user.avatarUrl !=''">
#{user.avatarUrl},
</if>
</trim>
on duplicate key update
<trim>
<if test="user.nickName != null and user.nickName !=''">
nick_name = #{user.nickName},
</if>
<if test="user.avatarUrl != null and user.avatarUrl !=''">
avatar_url = #{user.avatarUrl},
</if>
</trim>
</insert>
</mapper>

@ -50,6 +50,9 @@
import {
carStore
} from '../../store/car.js'
import {
orderStore
} from '../../store/order.js'
//store
const store = carStore();
const show = ref(true);
@ -140,6 +143,22 @@
})
//
const confirm = (item) => {
//
const selectedGoods = store.carList.filter(item => item.flag);
//
if (selectedGoods.length === 0) {
uni.showToast({
title: '请选择商品',
icon: 'none'
});
return;
}
// orderStore
const ostore = orderStore();
ostore.addOrderList(selectedGoods);
uni.navigateTo({
url: '../confirm/confirm'
});

@ -91,6 +91,19 @@
margin: 5px 10px 5px 0px;
}
.collect-container {
height: 100vh;
background-color: #f8f8f8;
.scroll-view {
height: 100%;
.empty-tip {
padding-top: 200rpx;
}
}
}
.item {
padding: 40rpx 20rpx;
display: flex;

@ -273,7 +273,25 @@
onLoad((options) => {
userLogin()
const goods = JSON.parse(options.goods)
//
let goodsParam = options.goods;
try {
// index.vue
goodsParam = JSON.parse(goodsParam);
} catch (e) {
// category.vue
try {
goodsParam = JSON.parse(decodeURIComponent(goodsParam));
} catch (e2) {
uni.showToast({
title: '参数错误',
icon: 'none'
});
return;
}
}
const goods = goodsParam;
swipperList.value = goods.goodsImage.split(',')
console.log(goods)
goodsUnit.value = goods.goodsUnit

@ -18,7 +18,7 @@
<view class="u-m-t-20">
<u-cell-group>
<u-cell-item @click="toOrder" icon="star" title="我的订单"></u-cell-item>
<u-cell-item icon="photo" title="我的收藏"></u-cell-item>
<u-cell-item @click="toCollect" icon="photo" title="我的收藏"></u-cell-item>
<u-cell-item icon="coupon" title="我的地址"></u-cell-item>
</u-cell-group>
</view>
@ -102,7 +102,7 @@
}
const onNickName = (e) => {
console.log(e)
uni.createSelectorQuery().in(instance) // in(this)
uni.createSelectorQuery().in(instance)
.select("#nickname-input")
.fields({
properties: ["value"],
@ -233,6 +233,14 @@
url: '../order/order'
});
}
//
const toCollect = () => {
uni.navigateTo({
url: '../collect/collect'
});
}
onShow(() => {
userLogin()
// getUserInfo()

@ -10,6 +10,11 @@ export const sendOrderApi = (orderId: string) => {
return http.put("/wxapi/order/sendOrder", { orderId: orderId })
}
// 删除订单
export const deleteOrderApi = (orderId: string) => {
return http.delete(`/wxapi/order/${orderId}`);
};
//统计
export const getTotalApi = (type:string)=>{
return http.get("/wxapi/order/getTotal",{type:type})

@ -1,5 +1,5 @@
import http from "../../http";
import type { ListUserParm, UserModel } from "./userModel";
import type { ListUserParm, UserModel, RegisterModel } from "./userModel";
// 新增接口
export const addUserApi = (parm:UserModel)=>{
@ -19,4 +19,19 @@ export const editUserApi = (parm:UserModel)=>{
// 删除接口
export const deleteUserApi = (userId:string)=>{
return http.delete(`/api/user/${userId}`)
}
// 用户登录
export const loginApi = (parm: { username: string; password: string }) => {
return http.post('/api/user/login', parm)
}
// 用户注册
export const registerApi = (parm: RegisterModel) => {
return http.post('/api/user/register', parm)
}
// 获取用户信息
export const getUserInfoApi = () => {
return http.get('/api/user/getUserInfo')
}

@ -17,4 +17,15 @@ export type UserModel = {
email: string;
sex: string;
name: string;
}
// 注册表单类型
export type RegisterModel = {
username: string;
password: string;
phone: string;
email: string;
sex: string;
name: string;
confirmPassword?: string;
}

@ -1,6 +1,6 @@
import type { OrderListParm } from '../../api/order/OrderModel'
import { nextTick, onMounted, reactive, ref } from 'vue'
import { gePcOrdertListApi, sendOrderApi } from '../../api/order'
import { gePcOrdertListApi, sendOrderApi, deleteOrderApi } from '../../api/order' // 导入 deleteOrderApi
import useInstance from '@/hooks/useInstance'
export default function useOrderTable() {
const { global } = useInstance()
@ -34,6 +34,7 @@ export default function useOrderTable() {
const resetBtn = () => {
listParm.currentPage = 1;
listParm.type = ''
listParm.userName = '' // 重置搜索条件
getList()
}
//页容量改变触发
@ -52,7 +53,29 @@ export default function useOrderTable() {
if (confirm) {
let res = await sendOrderApi(orderId)
if (res && res.code == 200) {
global.$message({ type: 'success', message: '发货成功!' })
getList()
} else {
global.$message({ type: 'error', message: res?.msg || '发货失败!' })
}
}
}
// 删除订单
const deleteOrder = async (orderId: string) => {
let confirm = await global.$myconfirm('确定删除该订单吗?此操作不可恢复。')
if (confirm) {
try {
let res = await deleteOrderApi(orderId)
if (res && res.code == 200) {
global.$message({ type: 'success', message: '删除成功!' })
getList()
} else {
global.$message({ type: 'error', message: res?.msg || '删除失败!' })
}
} catch (error) {
console.error('删除订单失败:', error)
global.$message({ type: 'error', message: '删除失败!' })
}
}
}
@ -66,6 +89,7 @@ export default function useOrderTable() {
return {
tableList,
sendOrder,
deleteOrder, // 返回删除订单方法
listParm,
getList,
searchBtn,

@ -33,10 +33,10 @@ class Http {
private interceptors() {
// 请求发送之前的拦截器通常用来配置、携带token
this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
// 设置token到请求头部
let token = "";
// 从localStorage获取token
const token = localStorage.getItem('token');
if (token) {
config.headers!['token'] = token;
config.headers!['Authorization'] = `Bearer ${token}`;
}
return config;
}, (error: any) => {
@ -59,58 +59,64 @@ class Http {
console.log('进入错误')
error.data = {}
if (error && error.response) {
switch (error.response.status) {
case 400:
error.data.msg = '错误请求'
ElMessage.error(error.data.msg)
break
case 401:
error.data.msg = '未授权,请重新登录'
ElMessage.error(error.data.msg)
break
case 403:
error.data.msg = '拒绝访问'
ElMessage.error(error.data.msg)
break
case 404:
error.data.msg = '请求错误,未找到该资源'
ElMessage.error(error.data.msg)
break
case 405:
error.data.msg = '请求方法未允许'
ElMessage.error(error.data.msg)
break
case 408:
error.data.msg = '请求超时'
ElMessage.error(error.data.msg)
break
case 500:
error.data.msg = '服务器端出错'
ElMessage.error(error.data.msg)
break
case 501:
error.data.msg = '网络未实现'
ElMessage.error(error.data.msg)
break
case 502:
error.data.msg = '网络错误'
ElMessage.error(error.data.msg)
break
case 503:
error.data.msg = '服务不可用'
ElMessage.error(error.data.msg)
break
case 504:
error.data.msg = '网络超时'
ElMessage.error(error.data.msg)
break
case 505:
error.data.msg = 'http版本不支持该请求'
ElMessage.error(error.data.msg)
break
default:
error.data.msg = `连接错误${error.response.status}`
ElMessage.error(error.data.msg)
if (error.response.status === 401) {
error.data.msg = '未授权,请重新登录'
ElMessage.error(error.data.msg)
// 清除本地存储的token和用户信息
localStorage.removeItem('token')
localStorage.removeItem('user')
// 跳转到登录页
window.location.href = '/login'
} else {
switch (error.response.status) {
case 400:
error.data.msg = '错误请求'
ElMessage.error(error.data.msg)
break
case 403:
error.data.msg = '拒绝访问'
ElMessage.error(error.data.msg)
break
case 404:
error.data.msg = '请求错误,未找到该资源'
ElMessage.error(error.data.msg)
break
case 405:
error.data.msg = '请求方法未允许'
ElMessage.error(error.data.msg)
break
case 408:
error.data.msg = '请求超时'
ElMessage.error(error.data.msg)
break
case 500:
error.data.msg = '服务器端出错'
ElMessage.error(error.data.msg)
break
case 501:
error.data.msg = '网络未实现'
ElMessage.error(error.data.msg)
break
case 502:
error.data.msg = '网络错误'
ElMessage.error(error.data.msg)
break
case 503:
error.data.msg = '服务不可用'
ElMessage.error(error.data.msg)
break
case 504:
error.data.msg = '网络超时'
ElMessage.error(error.data.msg)
break
case 505:
error.data.msg = 'http版本不支持该请求'
ElMessage.error(error.data.msg)
break
default:
error.data.msg = `连接错误${error.response.status}`
ElMessage.error(error.data.msg)
}
}
} else {
error.data.msg = "连接到服务器失败"

@ -1,36 +1,80 @@
<template>
<!-- 添加下拉菜单组件 -->
<el-dropdown>
<span class="el-dropdown-link">
<!-- <img src="../../assets/user.png" alt=""> -->
<!-- 将下拉菜单文字替换为用户头像 -->
<img class="uimage" src="@/assets/user.png" alt="">
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>退出登录</el-dropdown-item>
<!-- 目前只需要退出登录功能注释掉多余action -->
<!-- <el-dropdown-item>Action 2</el-dropdown-item>
<el-dropdown-item>Action 3</el-dropdown-item>
<el-dropdown-item disabled>Action 4</el-dropdown-item>
<el-dropdown-item divided>Action 5</el-dropdown-item> -->
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="user-info">
<span class="username">{{ userName }}</span>
<el-dropdown>
<span class="el-dropdown-link">
<img class="uimage" src="@/assets/user.png" alt="">
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleLogout">退</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
const router = useRouter()
const userName = ref('')
//
onMounted(() => {
const userStr = localStorage.getItem('user')
if (userStr) {
try {
const user = JSON.parse(userStr)
userName.value = user.name || user.username
} catch (e) {
console.error('解析用户信息失败', e)
}
}
})
// 退
const handleLogout = () => {
ElMessageBox.confirm('确定要退出登录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// token
localStorage.removeItem('token')
localStorage.removeItem('user')
// 退
ElMessage.success('退出登录成功')
//
router.push('/login')
}).catch(() => {
//
ElMessage.info('已取消退出')
})
}
</script>
<style scoped lang="scss">
//
.uimage{
height: 45px;
width: 45px;
border-radius: 50%;
cursor: pointer;
}
.user-info {
display: flex;
align-items: center;
gap: 10px;
}
.username {
font-size: 14px;
color: #606266;
}
//
.uimage{
height: 45px;
width: 45px;
border-radius: 50%;
cursor: pointer;
}
</style>

@ -26,7 +26,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'dashboard',
component: () => import('@/views/dashboard/Index.vue'),
meta: {
title: '首页'
title: '首页',
requiresAuth: true // 添加认证要求
},
},
{
@ -34,7 +35,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'banner',
component: () => import('@/views/banner/Index.vue'),
meta: {
title: '广告管理'
title: '广告管理',
requiresAuth: true // 添加认证要求
},
},
{
@ -42,7 +44,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'category',
component: () => import('@/views/category/Index.vue'),
meta: {
title: '菜品分类'
title: '菜品分类',
requiresAuth: true // 添加认证要求
},
},
{
@ -50,7 +53,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'comment',
component: () => import('@/views/comment/Index.vue'),
meta: {
title: '评论管理'
title: '评论管理',
requiresAuth: true // 添加认证要求
},
},
{
@ -58,7 +62,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'goods',
component: () => import('@/views/goods/Index.vue'),
meta: {
title: '菜品管理'
title: '菜品管理',
requiresAuth: true // 添加认证要求
},
},
{
@ -66,7 +71,8 @@ const routes: Array<RouteRecordRaw> = [
name: 'order',
component: () => import('@/views/order/Index.vue'),
meta: {
title: '订单管理'
title: '订单管理',
requiresAuth: true // 添加认证要求
},
},
{
@ -74,10 +80,25 @@ const routes: Array<RouteRecordRaw> = [
name: 'user',
component: () => import('@/views/user/Index.vue'),
meta: {
title: '用户管理'
title: '用户管理',
requiresAuth: true // 添加认证要求
},
},
}
]
},
// 登录和注册作为独立路由不在Layout中
{
path: '/login',
name: 'Login',
component: () => import('@/views/login/Index.vue'),
meta: { title: '登录' }
},
{
path: '/register',
name: 'Register',
component: () => import('@/views/register/Index.vue'),
meta: { title: '注册' }
}
]
@ -86,4 +107,23 @@ const router = createRouter({
routes
})
// 路由守卫
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token')
// 检查路由是否需要认证
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth && !token) {
// 如果需要认证但没有token跳转到登录页
next('/login')
} else if ((to.path === '/login' || to.path === '/register') && token) {
// 如果已登录但尝试访问登录/注册页,跳转到首页
next('/dashboard')
} else {
// 否则继续导航
next()
}
})
export default router

@ -1,165 +1,332 @@
<template>
<el-form style="margin: 20px 0px" label-width="80px" size="default">
<el-form-item>
<el-button style="padding: 0px 50px" @click="charts('0')"></el-button>
<el-button @click="charts('1')" style="padding: 0px 50px" type="primary" plain>月统计</el-button>
<el-button @click="charts('2')" style="padding: 0px 50px" type="success" plain>年统计</el-button>
<el-button style="padding: 0px 50px" @click="charts('0')" :type="activeChart === '0' ? 'primary' : ''">
日统计
</el-button>
<el-button @click="charts('1')" style="padding: 0px 50px" :type="activeChart === '1' ? 'primary' : ''">
月统计
</el-button>
<el-button @click="charts('2')" style="padding: 0px 50px" :type="activeChart === '2' ? 'primary' : ''">
年统计
</el-button>
</el-form-item>
</el-form>
<div ref="myChart" :style="{ width: '100%', height: '400px' }"></div>
<div ref="myChart1" :style="{ width: '100%', height: '350px' }"></div>
<el-alert v-if="errorMessage" :title="errorMessage" type="error" show-icon style="margin-bottom: 20px;"
@close="errorMessage = ''" />
<el-skeleton :rows="5" animated v-if="loading" />
<!-- 确保图表容器始终存在使用v-show -->
<div v-show="!loading" style="min-height: 800px;">
<div ref="myChart" :style="{ width: '100%', height: '400px' }"></div>
<div ref="myChart1" :style="{ width: '100%', height: '350px' }"></div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from "vue";
import { onMounted, reactive, ref, nextTick, onUnmounted } from "vue";
import useInstance from "@/hooks/useInstance";
import { getTotalApi } from '../../api/order/index'
// API
interface ApiResponse {
code: number;
data: {
names: string[];
values: number[];
};
message?: string;
}
const { global } = useInstance();
const myChart = ref<HTMLElement>();
const myChart1 = ref<HTMLElement>();
const myChart = ref<HTMLElement | null>(null);
const myChart1 = ref<HTMLElement | null>(null);
const loading = ref(false);
const errorMessage = ref("");
const activeChart = ref("0");
//
let echartInstance: any = null;
let echartInstance1: any = null;
let resizeObserver: ResizeObserver | null = null;
// 使 Promise
// 使 Promise
const wait = (ms: number, callback: () => void): void => {
setTimeout(callback, ms);
};
// DOM - 使 Promise
const ensureElementExists = (callback: () => void): void => {
let attempts = 0;
const checkElement = () => {
attempts++;
if (myChart.value && myChart1.value) {
callback();
} else if (attempts < 20) {
wait(50, checkElement);
} else {
console.warn("图表容器未找到,但继续执行");
callback();
}
};
checkElement();
};
//
const charts = async (type: string) => {
const echartInstance = global.$echarts.init(myChart.value);
const echartInstance1 = global.$echarts.init(myChart1.value);
let option = reactive({
title: {
text: "直方图",
},
xAxis: {
type: "category",
data: [],
axisLabel: {
//x
show: true,
interval: 0, //使x
try {
activeChart.value = type;
loading.value = true;
errorMessage.value = "";
//
const res = await getTotalApi(type) as ApiResponse;
if (!res || res.code !== 200) {
throw new Error(res?.message || "获取数据失败");
}
// DOM
await nextTick();
// 使DOM
ensureElementExists(() => {
//
if (!myChart.value || !myChart1.value) {
throw new Error("图表容器未找到");
}
initCharts(res, type);
});
} catch (error: any) {
console.error("图表渲染错误:", error);
errorMessage.value = "加载图表数据失败: " + (error.message || "未知错误");
loading.value = false;
}
};
//
const initCharts = (res: ApiResponse, type: string) => {
try {
//
if (echartInstance) {
echartInstance.dispose();
}
if (echartInstance1) {
echartInstance1.dispose();
}
echartInstance = global.$echarts.init(myChart.value!);
echartInstance1 = global.$echarts.init(myChart1.value!);
let option = {
title: {
text: type === '0' ? "日统计直方图" : type === '1' ? "月统计直方图" : "年统计直方图",
left: 'center'
},
xAxis: {
type: "category",
data: res.data.names || [],
axisLabel: {
show: true,
interval: 0,
rotate: 30 //
},
},
yAxis: {
type: "value",
name: '金额'
},
},
yAxis: {
type: "value",
},
series: [
{
data: [],
type: "bar",
itemStyle: {
normal: {
//
series: [
{
data: res.data.values || [],
type: "bar",
itemStyle: {
color: function (params: any) {
//
var colorList = [
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0",
"#FFA100",
"#ffc0cb",
"#CCCCCC",
"#BBFFAA",
"#749f83",
"#ca8622",
"#00A3E0", "#FFA100", "#ffc0cb", "#CCCCCC", "#BBFFAA",
"#749f83", "#ca8622", "#00A3E0", "#FFA100", "#ffc0cb"
];
return colorList[params.dataIndex];
return colorList[params.dataIndex % colorList.length];
},
},
},
],
tooltip: {
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 1,
textStyle: {
color: "#fff",
fontSize: "12",
},
formatter: function (params: any) {
return `${params[0].name}<br/>金额: ${params[0].value}`;
}
},
],
tooltip: {
// XY
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 1,
textStyle: {
//
color: "#fff",
fontSize: "12",
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
}
};
let option1 = {
title: {
text: type === '0' ? "日统计折线图" : type === '1' ? "月统计折线图" : "年统计折线图",
left: 'center'
},
},
});
let option1 = reactive({
title: {
text: "折线图",
},
xAxis: {
type: "category",
data: [],
axisLabel: {
//x
show: true,
interval: 0, //使x
xAxis: {
type: "category",
data: res.data.names || [],
axisLabel: {
show: true,
interval: 0,
rotate: 30
},
},
},
yAxis: {
type: "value",
},
series: [
{
data: [],
type: "line",
yAxis: {
type: "value",
name: '金额'
},
],
tooltip: {
// XY
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 1,
textStyle: {
//
color: "#fff",
fontSize: "12",
series: [
{
data: res.data.values || [],
type: "line",
smooth: true,
itemStyle: {
color: '#00A3E0'
},
lineStyle: {
width: 3
}
},
],
tooltip: {
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 1,
textStyle: {
color: "#fff",
fontSize: "12",
},
formatter: function (params: any) {
return `${params[0].name}<br/>金额: ${params[0].value}`;
}
},
},
});
//
let res = await getTotalApi(type)
if (res && res.data) {
console.log(res)
option.xAxis.data = res.data.names
option.series[0].data = res.data.values
option1.xAxis.data = res.data.names
option1.series[0].data = res.data.values
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
}
};
echartInstance.setOption(option);
echartInstance1.setOption(option1);
//
if (resizeObserver) {
resizeObserver.disconnect();
}
resizeObserver = new ResizeObserver(() => {
if (echartInstance) {
echartInstance.resize();
}
if (echartInstance1) {
echartInstance1.resize();
}
});
if (myChart.value) {
resizeObserver.observe(myChart.value);
}
if (myChart1.value) {
resizeObserver.observe(myChart1.value);
}
//
const resizeHandler = function () {
if (echartInstance) {
echartInstance.resize();
}
if (echartInstance1) {
echartInstance1.resize();
}
};
window.addEventListener('resize', resizeHandler);
// resizeHandler便
(window as any).__chartResizeHandler = resizeHandler;
} catch (error: any) {
console.error("图表初始化错误:", error);
errorMessage.value = "图表初始化失败: " + (error.message || "未知错误");
} finally {
loading.value = false;
}
echartInstance.setOption(option);
echartInstance1.setOption(option1);
};
onMounted(() => {
charts('0');
// 使setTimeoutDOM
setTimeout(() => {
charts('0');
}, 300); //
});
//
onUnmounted(() => {
if (echartInstance) {
echartInstance.dispose();
}
if (echartInstance1) {
echartInstance1.dispose();
}
//
if ((window as any).__chartResizeHandler) {
window.removeEventListener('resize', (window as any).__chartResizeHandler);
}
});
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
.chart-container {
padding: 20px;
height: 100%;
display: flex;
flex-direction: column;
}
.charts-wrapper {
display: flex;
flex-direction: column;
flex: 1;
gap: 20px;
}
.chart-item {
width: 100%;
flex: 1;
min-height: 300px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.chart-container {
padding: 10px;
}
.charts-wrapper {
gap: 15px;
}
}
</style>

@ -0,0 +1,108 @@
<template>
<div class="login-container">
<el-card class="login-card">
<h2 class="login-title">用户登录</h2>
<el-form :model="loginForm" :rules="loginRules" ref="loginFormRef" class="login-form">
<el-form-item prop="username">
<el-input v-model="loginForm.username" placeholder="请输入用户名" prefix-icon="User"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="loginForm.password" type="password" placeholder="请输入密码"
prefix-icon="Lock" show-password></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="login-btn" @click="handleLogin" :loading="loading">登录</el-button>
</el-form-item>
</el-form>
<div class="login-footer">
<span>还没有账号</span>
<el-link type="primary" @click="goRegister"></el-link>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ElMessage, type FormInstance } from 'element-plus'
import { useRouter } from 'vue-router'
import { loginApi } from '../../api/user'
const router = useRouter()
const loading = ref(false)
const loginFormRef = ref<FormInstance>()
const loginForm = reactive({
username: '',
password: ''
})
const loginRules = reactive({
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
})
const handleLogin = () => {
loginFormRef.value?.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const res = await loginApi(loginForm)
if (res && res.code === 200) {
ElMessage.success('登录成功')
// token
localStorage.setItem('token', res.data.token)
localStorage.setItem('user', JSON.stringify(res.data.user))
//
router.push('/dashboard')
} else {
ElMessage.error(res.msg || '登录失败')
}
} catch (error) {
ElMessage.error('登录失败,请稍后重试')
} finally {
loading.value = false
}
}
})
}
const goRegister = () => {
router.push('/register')
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f7fa;
}
.login-card {
width: 400px;
padding: 20px;
}
.login-title {
text-align: center;
margin-bottom: 30px;
color: #409EFF;
}
.login-form {
margin-top: 20px;
}
.login-btn {
width: 100%;
}
.login-footer {
text-align: center;
margin-top: 20px;
}
</style>

@ -60,11 +60,15 @@
<el-tag v-if="scope.row.status == '2'" size="default" effect="dark"
>已收货</el-tag
>
<el-tag v-if="scope.row.status == '3'" size="default" effect="light"
>已取消</el-tag
>
</template>
</el-table-column>
<el-table-column label="操作" width="200" align="center">
<el-table-column label="操作" width="250" align="center">
<template #default="scope">
<el-button type="primary" @click="sendOrder(scope.row.orderId)" :icon="Edit" size="default">发货</el-button>
<el-button type="danger" @click="deleteOrder(scope.row.orderId)" :icon="Delete" size="default">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -90,6 +94,7 @@
const {
tableList,
sendOrder,
deleteOrder, //
listParm,
resetBtn,
searchBtn,
@ -99,5 +104,4 @@
} = useOrderTable();
</script>
<style scoped></style>
<style scoped></style>

@ -0,0 +1,171 @@
<template>
<div class="register-container">
<el-card class="register-card">
<h2 class="register-title">用户注册</h2>
<el-form :model="registerForm" :rules="registerRules" ref="registerFormRef" class="register-form">
<el-form-item prop="name" label="姓名">
<el-input v-model="registerForm.name" placeholder="请输入真实姓名"></el-input>
</el-form-item>
<el-form-item prop="sex" label="性别">
<el-radio-group v-model="registerForm.sex">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="phone" label="手机号">
<el-input v-model="registerForm.phone" placeholder="请输入手机号"></el-input>
</el-form-item>
<el-form-item prop="email" label="邮箱">
<el-input v-model="registerForm.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item prop="username" label="用户名">
<el-input v-model="registerForm.username" placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item prop="password" label="密码">
<el-input v-model="registerForm.password" type="password" placeholder="请输入密码" show-password></el-input>
</el-form-item>
<el-form-item prop="confirmPassword" label="确认密码">
<el-input v-model="registerForm.confirmPassword" type="password" placeholder="请再次输入密码"
show-password></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" class="register-btn" @click="handleRegister" :loading="loading">注册</el-button>
</el-form-item>
</el-form>
<div class="register-footer">
<span>已有账号</span>
<el-link type="primary" @click="goLogin"></el-link>
</div>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { ElMessage, type FormInstance } from 'element-plus'
import { useRouter } from 'vue-router'
import { registerApi } from '../../api/user'
import type { FormRules } from 'element-plus'
import type { RegisterModel } from '../../api/user/userModel'
const router = useRouter()
const loading = ref(false)
const registerFormRef = ref<FormInstance>()
const registerForm = reactive<RegisterModel>({
name: '',
sex: '',
phone: '',
email: '',
username: '',
password: '',
confirmPassword: ''
})
const validatePass2 = (rule: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== registerForm.password) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
const registerRules = reactive<FormRules>({
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
],
sex: [
{ required: true, message: '请选择性别', trigger: 'change' }
],
phone: [
{ required: true, message: '请输入电话', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email' as any, message: '请输入正确的邮箱地址', trigger: 'blur' }
],
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 6, message: '密码长度不能少于6位', trigger: 'blur' }
],
confirmPassword: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{ validator: validatePass2, trigger: 'blur' }
]
})
const handleRegister = () => {
registerFormRef.value?.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const res = await registerApi(registerForm)
if (res && res.code === 200) {
ElMessage.success('注册成功')
//
router.push('/login')
} else {
ElMessage.error(res.msg || '注册失败')
}
} catch (error) {
ElMessage.error('注册失败,请稍后重试')
} finally {
loading.value = false
}
}
})
}
const goLogin = () => {
router.push('/login')
}
</script>
<style scoped>
.register-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f5f7fa;
padding: 20px 0;
}
.register-card {
width: 500px;
padding: 20px;
}
.register-title {
text-align: center;
margin-bottom: 30px;
color: #409EFF;
}
.register-form {
margin-top: 20px;
}
.register-btn {
width: 100%;
}
.register-footer {
text-align: center;
margin-top: 20px;
}
</style>

@ -2,42 +2,29 @@
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
//
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
],
"@/api/*": [
"src/api/*"
]
"@/*": ["src/*"],
"@/api/*": ["src/api/*"]
},
//
"lib": [
"ESNext",
"DOM",
"DOM.Iterable"
],
"types": [
"vite/client"
],
//
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["vite/client"],
"module": "ESNext",
"moduleResolution": "bundler",
//
"target": "ESNext",
"esModuleInterop": true,
"resolveJsonModule": true,
"strict": true,
"jsx": "preserve",
"downlevelIteration": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"vite-env.d.ts",
"vite.config.ts",
"src/api/**/*.ts"
]
}

@ -10,7 +10,7 @@ export default defineConfig(({ mode }) => {
return {
define: {
// 替换为全局变量
__APP_BASE_URL__: JSON.stringify("http://localhost:8089")
__APP_BASE_URL__: JSON.stringify("http://localhost:8089"),
},
plugins: [vue()],
server: {
@ -50,6 +50,4 @@ export default defineConfig(({ mode }) => {
chunkSizeWarningLimit: 1500
}
}
})
})
Loading…
Cancel
Save