Browse Source

vue3项目

e 10 months ago
parent
commit
6b1d6970f9

BIN
vue3/项目/vue3-project.zip


+ 24 - 0
vue3/项目/vue3-project/src/api/category.js

@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+
+const apiName = '/admin/product/category'
+// 根据父级id获取下级节点
+export const GetUserInfo = (parentId) => {
+  return request({
+    url: `${apiName}/findByParentId/${parentId}`,
+    method: 'get',
+  })
+}
+export const FindCategoryByParentId = parentId => {
+  return request({
+    url: `${apiName}/findByParentId/${parentId}`,
+    method: 'get',
+  })
+}
+// 导出
+export const ExportDate = () => {
+    return request({
+        url: `${apiName}/exportData`,
+        method: 'get',
+        responseType: 'blob'
+    })
+}

+ 42 - 0
vue3/项目/vue3-project/src/api/categoryBrand.js

@@ -0,0 +1,42 @@
+import request from '@/utils/request'
+
+const apiName = '/admin/product/categoryBrand'
+// 分页列表
+export const pageData = (page,limit,searchObj) => {
+    return request({
+        url: `${apiName}/${page}/${limit}`,
+        method: 'get',
+        params: searchObj,
+    })
+}
+// 根据分类的id获取品牌数据
+export const FindBrandByCategoryId = categoryId => {
+  return request({
+    url: `${apiName}/findBrandByCategoryId/${categoryId}`,
+    method: 'get',
+  })
+}
+
+// 添加 
+export const addSave = data => {
+  return request({
+    url: `${apiName}/save`,
+    method: 'post',
+    data
+  })
+}
+// 修改 
+export const updateSave = data => {
+  return request({
+    url: `${apiName}/updateById`,
+    method: 'put',
+    data
+  })
+}
+// 删除 
+export const delSave = id => {
+  return request({
+    url: `${apiName}/deleteById/${id}`,
+    method: 'delete'
+  })
+}

+ 18 - 0
vue3/项目/vue3-project/src/api/login.js

@@ -8,6 +8,24 @@ export const GetUserinfo = () => {
   })
 }
 
+// 登录接口
+export const Login = data => {
+  return request({
+    url:'/admin/system/index/login',
+    method: 'post',
+    data
+  })
+}
+
+// 验证码接口
+export const GenerateValidateCode = () => {
+  return request({
+    url: '/admin/system/index/generateValidateCode',
+    method: 'get',
+  })
+}
+
+
 //退出
 export const Logout = () => {
   return request({

+ 12 - 0
vue3/项目/vue3-project/src/api/order.js

@@ -0,0 +1,12 @@
+import request from '@/utils/request'
+
+const apiName = '/admin/order/orderInfo'
+
+// 订单接口
+export const GetOrderStatisticsData = params => {
+  return request({
+    url: `${apiName}/getOrderStatisticsData`,
+    method: 'get',
+    params,
+  })
+}

+ 1 - 1
vue3/项目/vue3-project/src/router/modules/order.js

@@ -1,5 +1,5 @@
 const Layout = () => import('@/layout/index.vue')
-const orderStatistics = () => import('@/views/order/orderStatistics.vue')
+const orderStatistics = () => import('@/views/order/index.vue')
 
 export default [
   {

+ 1 - 1
vue3/项目/vue3-project/src/utils/request.js

@@ -5,7 +5,7 @@ import { useApp } from '@/pinia/modules/app'
 
 const service = axios.create({
   //baseURL: 'http://127.0.0.1:8501',   // 后期需要将这个地址更改为后端真实服务地址
-  baseURL: 'http://192.168.18.22:8501',   // 后期需要将这个地址更改为后端真实服务地址
+  baseURL: 'https://9yeeydhohza8.hk1.xiaomiqiu123.top', // 后期需要将这个地址更改为后端真实服务地址
   timeout: 10000,
   withCredentials: true,
 })

+ 161 - 0
vue3/项目/vue3-project/src/views/login/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="login">
+    <div class="main">
+      <h1>四福电商后台管理系统</h1>
+      <el-form class="form" ref="ruleFormRef" :model="state.form" label-width="auto" style="max-width: 400px" :rules="state.rules">
+    <el-form-item prop="userName">
+      <el-input class="text" clearable prefix-icon="User" placeholder="请输入用户名" v-model="state.form.userName" />
+    </el-form-item>
+    <el-form-item prop="password">
+      <el-input class="text" clearable prefix-icon="Lock" show-password placeholder="请输入密码" v-model="state.form.password" />
+    </el-form-item>
+    <el-form-item prop="captcha">
+      <el-input class="text news" clearable prefix-icon="Lock" placeholder="请输入验证码" v-model="state.form.captcha" />
+      <img :src="state.imgSrc" class="pictures" alt="" @click="state.refreshMain">
+    </el-form-item>
+   
+    <el-form-item>
+      <el-button :loading="state.loading" type="primary" @click="state.onSubmit" large class="btn">登录</el-button>
+    </el-form-item>
+  </el-form>
+
+    </div>
+  </div>
+</template>
+
+<script setup name="login">
+import { reactive, ref, onMounted, watch } from 'vue'
+import { Login, GenerateValidateCode} from '@/api/login.js'
+import {useRouter, useRoute} from 'vue-router'
+import useLang from '@/i18n/useLang.js'
+import { ElMessage } from 'element-plus'
+import { useApp } from '@/pinia/modules/app.js'
+
+const { lang } = useLang()
+const router = useRouter()
+const route = useRoute()
+watch(()=>lang,()=>{
+  state.rules = getRules()
+})
+
+const getRules = () => ({
+  userName: [
+    { required: true, message: '请输入用户名', trigger: 'blur' }
+  ],
+  password: [
+    { required: true, message: '请输入密码', trigger: 'blur' }
+  ],
+  captcha: [
+    { required: true, message: '请输入验证码', trigger: 'blur' }
+  ]
+})
+// 进入页面显示验证码
+onMounted(()=>{
+  state.refreshMain()
+})
+let ruleFormRef = ref()
+const state = reactive({
+  form: {
+    userName: 'admin',
+    password: '111111',
+    captcha: '1',
+    codeKey: ''
+  },
+  loading: false,
+  rules:getRules(),
+  imgSrc:"",
+  refreshMain:async ()=>{
+    let {data} = await GenerateValidateCode()
+    state.imgSrc = data.codeValue
+    console.log(state.imgSrc)
+    state.form.codeKey = data.codeKey
+  },
+  onSubmit:() => {
+    
+    if(state.loading) {
+      return
+    }
+    ruleFormRef.value.validate(async (valid) => {
+      state.loading = true
+      if (valid) {
+        let {code, data, message} = await Login(state.form)
+        if(code == 200) {  
+          ElMessage({
+            message: message,
+            type: 'success',
+          })
+          const targetPath = decodeURIComponent(route.query.redirect)
+          console.log(targetPath)
+          if(targetPath.startsWith("http")) {
+            // 当前的url路径
+            window.location.href = targetPath;
+          } else if(targetPath.startsWith("/")){
+            // 内部页面
+            router.push(targetPath)
+          } else {
+            // 重新加载
+            router.push('/')
+          }
+          useApp().initToken(data);
+          state.loading = false
+        }
+      } else {
+        console.log('error submit!')
+      }
+  })
+  }
+})
+
+</script>
+
+<style scoped lang="scss">
+.login {
+  width: 100vw;
+  height: 100vh;
+  background:#2a3b4d;
+  .main {
+    width: 500px;
+    height: 500px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    margin-left: -250px;
+    margin-top: -250px;
+    h1 {
+      color: #fff;
+      text-align: center;
+    }
+    .form {
+      margin: 0 auto;
+    }
+    :deep{ 
+      .el-input__wrapper{
+      color: #fff;
+      box-shadow: 0 0 0 1px rgba(255,255,255,.2);
+      background: #000;
+    }
+  }
+    .text {
+      font-size: 16px;
+      :deep .el-input__inner {
+        color: #fff;
+        &::placeholder {
+          font-size: 14px;
+          color: rgba(255,255,255,.2);
+        }
+      }
+    }
+    .btn {
+      width: 400px;
+    }
+    .news {
+      width: 200px;
+    }
+    .pictures {
+      width: 140px;
+      height: 32px;
+      margin-left: 59px;
+    }
+  }
+}
+</style>

+ 82 - 0
vue3/项目/vue3-project/src/views/order/index.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="order">
+    <div class="main" ref="chat"></div>
+  </div>
+</template>
+
+<script setup name="order">
+import {GetOrderStatisticsData} from '@/api/order.js'
+import * as echarts from 'echarts'
+import { onMounted, ref } from 'vue'
+
+let chat = ref()
+
+let searchObj = ref({
+  createTimeBegin:"",
+  createTimeEnd:""
+})
+onMounted(async ()=>{
+  let {data} = await GetOrderStatisticsData(searchObj.value)
+  setOptionMain(data.amountList,data.dateList)
+})
+
+const setOptionMain = (amountList,dateList) => {
+  var myChart = echarts.init(chat.value);
+var option;
+
+option = {
+  title: {
+    text: '订单管理',
+    subtext: '订单详情统计'
+  },
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'shadow'
+    }
+  },
+  grid: {
+    left: '3%',
+    right: '4%',
+    bottom: '3%',
+    containLabel: true
+  },
+  xAxis: [
+    {
+      type: 'category',
+      data: dateList,
+      axisTick: {
+        alignWithLabel: true
+      }
+    }
+  ],
+  yAxis: [
+    {
+      type: 'value',
+      data: amountList
+    }
+  ],
+  series: [
+    {
+      name: '订单数量(单)',
+      type: 'bar',
+      barWidth: '60%',
+      data: [10, 52, 200, 334, 390, 330, 220]
+    }
+  ]
+};
+
+option && myChart.setOption(option);
+}
+
+
+
+</script>
+
+<style scoped>
+.main {
+  width: 900px;
+  height: 700px;
+  margin: 0 auto;
+}
+</style>

+ 71 - 0
vue3/项目/vue3-project/src/views/product/category.vue

@@ -0,0 +1,71 @@
+<template>
+  <div class="category">
+    <el-button type="success" size="small" class="btn" @click="handlerExport">导出</el-button>
+    <el-table
+      :data="list"
+      style="width: 100%"
+      row-key="id"
+      border
+      lazy
+      :load="getDate"
+      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
+    >
+      <el-table-column prop="name" label="分类名称" />
+      <el-table-column prop="orderNum" label="排序" />
+      <el-table-column prop="address" label="状态">
+        <template #default="scope">
+            {{scope.row.status == 1 ? "正常" : "停用"}}
+        </template>
+      </el-table-column>
+      <el-table-column prop="orderNum" label="创建时间" />
+      <el-table-column prop="imageUrl" label="图片">
+        <template #default="scope">
+            <img :src="scope.row.imageUrl" width="50" />
+        </template>
+      </el-table-column>
+    </el-table>
+  </div>
+</template>
+<script setup name="category">
+import { ref, onMounted } from 'vue'
+import { GetUserInfo, ExportDate } from '@/api/category.js'
+let list = ref([])
+// 初始化获取表格数据
+onMounted(async () => {
+  let {data} = await GetUserInfo(0)
+  list.value = data
+  console.log(list.value)
+})
+// 懒加载获取表格数据
+const getDate =async (row,treeNode,resolve) => {
+    let {data} = await GetUserInfo(row.id)
+    resolve(data)
+}
+// 导出
+const handlerExport = () => {
+    ExportDate().then(res => {
+        // 1.构造blob函数
+        const blob = new Blob([res])
+        // 2.创建a标签
+        const link = document.createElement('a')
+        // 3.配置路径
+        link.href = window.URL.createObjectURL(blob)
+        // 4.配置文件名称
+        link.download = '分类数据.xlsx'
+        // 5.点击a标签
+        link.click()
+    })
+}
+</script>
+<style scoped lang="scss">
+.category {
+  width: 99%;
+  margin: 0 auto;
+  padding: 10px;
+  background: #fff;
+  .btn {
+    margin-top: 15px;
+    margin-bottom: 15px;
+  }
+}
+</style>

+ 313 - 0
vue3/项目/vue3-project/src/views/product/categoryBrand.vue

@@ -0,0 +1,313 @@
+<template>
+  <div class="categoryBrand">
+    <div class="top">
+      <el-form label-width="auto">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="品牌">
+              <el-select
+                style="width:90%"
+                v-model="searchObj.brandId"
+                placeholder="请选择品牌"
+              >
+                <el-option
+                  v-for="(item, index) in list"
+                  :key="index"
+                  :label="item.name"
+                  :value="item.id"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="分类">
+              <el-cascader
+                v-model="categoryList"
+                style="width:90%"
+                :props="conProps"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-button size="small" type="primary" @click="handleSearch">
+            搜索
+          </el-button>
+          <el-button size="small" @click="handleReset">重置</el-button>
+        </el-row>
+      </el-form>
+    </div>
+    <div class="mid">
+      <el-button size="small" type="success" @click="handleAdd">添加</el-button>
+    </div>
+    <div class="bottom">
+      <el-table :data="tableData" style="width: 100%">
+        <el-table-column label="分类" prop="categoryName" />
+        <el-table-column label="品牌" prop="brandName" />
+        <el-table-column label="品牌图标" prop="logo">
+          <template #default="scope">
+            <img :src="scope.row.logo" width="50" />
+          </template>
+        </el-table-column>
+        <el-table-column label="创建时间" prop="createTime" />
+        <el-table-column align="right">
+          <template #default="scope">
+            <el-button
+              type="primary"
+              size="small"
+              @click="handleEdit(scope.row)"
+            >
+              修改
+            </el-button>
+            <el-button
+              size="small"
+              type="danger"
+              @click="handleDelete(scope.row)"
+            >
+              删除
+            </el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <el-pagination
+        :current-page="pageMain.page"
+        :page-size="pageMain.limit"
+        :page-sizes="[2, 10, 20, 30, 40]"
+        layout="sizes, prev, pager, next"
+        :total="total"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+      />
+    </div>
+    <!-- 弹框 -->
+    <el-dialog v-model="dialogFormVisible" :title="title" class="addDialog">
+      <el-form v-model="form1">
+        <el-form-item label="品牌">
+          <el-select
+            class="text"
+            v-model="form1.brandId"
+            placeholder="请选择品牌"
+          >
+            <el-option
+              v-for="(item, index) in list"
+              :key="index"
+              :label="item.name"
+              :value="item.id"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="分类">
+          <el-cascader
+            v-model="categoryForm"
+            style="width:90%"
+            :props="conProps1"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button @click="dialogFormVisible = false">取消</el-button>
+          <el-button type="primary" @click="submitForm">
+            提交
+          </el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+<script setup name="categoryBrand">
+import { pageData, addSave, delSave, updateSave } from '@/api/categoryBrand.js'
+import { GetUserInfo } from '@/api/category.js'
+import { FindAllBrand } from '@/api/brand.js'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import { ref, onMounted } from 'vue'
+
+const dialogFormVisible = ref(false)
+const form1 = ref({
+  id: '',
+  brandId: '',
+  categoryId: '',
+})
+let title = ref('')
+let list = ref([])
+let total = ref(0)
+let searchObj = ref({
+  brandId: '',
+  categoryId: '',
+})
+let categoryList = ref([])
+let categoryForm = ref([])
+let paramsPage = {
+  page: 1,
+  limit: 2,
+}
+let tableData = ref([])
+let pageMain = ref(paramsPage)
+onMounted(() => {
+  init()
+  getList()
+})
+// 品牌
+const init = async () => {
+  let { data } = await FindAllBrand()
+  list.value = data
+}
+// 分类
+const props = {
+  lazy: true,
+  value: 'id',
+  label: 'name',
+  leaf: 'leaf',
+  async lazyLoad(node, resolve) {
+    if (typeof node.value == 'undefined') {
+      node.value = 0
+    }
+    let { data } = await GetUserInfo(node.value)
+    data.forEach(ele => {
+      ele.leaf = !ele.hasChildren
+    })
+    resolve(data)
+  },
+}
+// 弹框中的分类
+const props1 = {
+  lazy: true,
+  value: 'id',
+  label: 'name',
+  leaf: 'leaf',
+  async lazyLoad(node, resolve) {
+    if (typeof node.value == 'undefined') {
+      node.value = 0
+    }
+    let { data } = await GetUserInfo(node.value)
+    data.forEach(ele => {
+      ele.leaf = !ele.hasChildren
+    })
+    resolve(data)
+  },
+}
+let conProps = ref(props)
+let conProps1 = ref(props1)
+
+// 搜索
+const handleSearch = () => {
+  if (categoryList.value.length === 3) {
+    searchObj.value.categoryId = categoryList.value[2]
+  }
+  getList()
+}
+// 表格
+const getList = async () => {
+  let { data } = await pageData(
+    pageMain.value.page,
+    pageMain.value.limit,
+    searchObj.value
+  )
+  tableData.value = data.list
+  total.value = data.total
+}
+// 切换条数
+const handleSizeChange = size => {
+  pageMain.value.limit = size
+  getList()
+}
+// 切换页数
+const handleCurrentChange = page => {
+  pageMain.value.page = page
+  getList()
+}
+// 重置
+const handleReset = () => {
+  searchObj.value = {
+    brandId: '',
+    categoryId: '',
+  }
+  getList()
+}
+// 添加
+const handleAdd = () => {
+  form1.value = {}
+  categoryForm.value = []
+  dialogFormVisible.value = true
+  title.value = '添加'
+}
+// 提交保存按钮
+const submitForm = () => {
+  if (categoryForm.value.length === 3) {
+    form1.value.categoryId = categoryForm.value[2]
+  }
+  if (form1.value.id) {
+    updateSave(form1.value).then(res => {
+      if (res.code == 200) {
+        ElMessage({
+          message: res.message,
+          type: 'success',
+        })
+        dialogFormVisible.value = false
+        getList()
+      }
+    })
+  } else {
+    addSave(form1.value).then(res => {
+      if (res.code == 200) {
+        ElMessage({
+          message: res.message,
+          type: 'success',
+        })
+        dialogFormVisible.value = false
+        getList()
+      }
+    })
+  }
+}
+// 修改
+const handleEdit = row => {
+  dialogFormVisible.value = true
+  title.value = '修改'
+  form1.value.brandId = row.brandId
+  form1.value.id = row.id
+  form1.value.categoryId = row.categoryId
+}
+// 删除
+const handleDelete = row => {
+  ElMessageBox.confirm('确认删除该数据?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  })
+    .then(() => {
+      delSave(row.id).then(res => {
+        if (res.code == 200) {
+          ElMessage({
+            message: res.message,
+            type: 'success',
+          })
+          getList()
+        }
+      })
+    })
+    .catch(() => {})
+}
+</script>
+<style scoped lang="scss">
+.categoryBrand {
+  padding: 10px;
+  .top {
+    width: 100%;
+    background: #fff;
+    padding: 10px;
+  }
+  .mid {
+    width: 100%;
+    background: #fff;
+    padding: 10px;
+    margin-top: 10px;
+  }
+  .addDialog {
+    width: 500px;
+    .text {
+      width: 80%;
+    }
+  }
+}
+</style>

+ 6 - 5
vue3/项目/vue3-project/vite.config.js

@@ -53,11 +53,12 @@ export default env => {
       port: 3001,
       open: true,
       proxy: {
-        '/api': {
-          target: 'http://192.168.18.22:8501', // 后端接口的域名
-          changeOrigin: true,
-          rewrite: path => path.replace(/^\/api/, ''),
-        },
+        //https://9yeeydhohza8.hk1.xiaomiqiu123.top 
+          '/api': {
+            target: 'http://192.168.18.22:8501', // 后端接口的域名
+            changeOrigin: true,
+            rewrite: path => path.replace(/^\/api/, ''),
+          },
       },
     },
     esbuild: false,