完成基本的商城首页

This commit is contained in:
周添峰 2024-07-19 15:27:42 +08:00
parent 80c158ec7b
commit 1cb44d63a7
9 changed files with 229 additions and 42 deletions

View File

@ -27,3 +27,7 @@ export const useThirdLoginApi = (data: any) => {
export const useLogoutApi = () => {
return service.post('/sys/auth/logout')
}
export const userRegisterApi = (data: any) => {
return service.post('/sys/auth/register', data)
}

View File

@ -1,6 +1,6 @@
import service from '@/utils/request'
export const useT_bookApi = (id: number) => {
export const getBookDetails = (id: string) => {
return service.get('/maku/t_book/' + id)
}
@ -11,3 +11,30 @@ export const useT_bookSubmitApi = (dataForm: any) => {
return service.post('/maku/t_book', dataForm)
}
}
/*
*
* */
export const bookList = () => {
return service.get('maku/t_book/list')
}
/*
*
* */
export const bookSearchList = (name: string) => {
return service.get('/maku/t_book/list/search?name=' + name)
}
export interface bookEntity {
id: number
bookName: string
author: string
price: number
bookCover: string
introduction: string
description: string
store: number
createTime: string
updateTime: string
}

View File

@ -22,6 +22,7 @@ export default {
logoText: 'Maku Admin',
miniLogoText: 'MAKU',
username: 'Username',
register: 'Register',
password: 'Password',
captcha: 'Captcha',
mobileSignIn: 'Mobile SignIn',

View File

@ -26,6 +26,8 @@ export default {
captcha: '验证码',
signIn: '登录',
mobileSignIn: '手机登录',
register: '注册',
rePassword: '再次输入密码',
mobile: '手机号',
signOut: '退出',
profile: '个人中心',

View File

@ -1,6 +1,22 @@
<script setup lang="ts">
import { ref } from 'vue'
import { onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { bookEntity, getBookDetails } from '@/api/maku/t_book'
const router = useRouter()
const route = useRoute()
const bookInfo = ref<bookEntity>({
author: '',
bookCover: '',
bookName: '',
createTime: '',
description: '',
id: 0,
introduction: '',
price: 0,
store: 0,
updateTime: ''
})
const commentList = ref([
{
id: 'string',
@ -33,20 +49,29 @@ const commentList = ref([
children: {}
}
])
onMounted(async () => {
let id = route.query.id as string
if (id) {
const { data } = await getBookDetails(id)
bookInfo.value = data
}
})
</script>
<template>
<div class="details-main">
<div class="details-p">
<div class="img-show">
<img src="https://gw.alicdn.com/imgextra/i3/2215468931119/O1CN019pzVLv1K8Y4vdSOVw_!!2215468931119.jpg" />
<img :src="bookInfo.bookCover" alt="" />
</div>
<div class="text-right">
<h1>纯种银渐层幼猫活体宠物猫英国短毛猫银渐层英短银渐层银渐层猫咪</h1>
<h1>{{ bookInfo.bookName }}</h1>
<div class="text-price">
<span class="price-unit">¥</span>
<span class="price-count">300</span>
<span class="price-count">{{ bookInfo.price }}</span>
</div>
<div class="book-introduction">{{ bookInfo.introduction }}</div>
<div class="book-introduction">{{ bookInfo.description }}</div>
<div class="botton-group">
<button class="buy">立刻购买</button>
<button class="shopping-card">加入购物车</button>
@ -56,7 +81,7 @@ const commentList = ref([
<div style="width: 1000px">
<div class="user-comment">用户评论</div>
<div v-for="item in commentList" :key="item.id" class="user-comment-list">
<img :src="item.user.avatar" />
<img :src="item.user.avatar" alt="" />
<div style="margin-left: 15px">
<div style="font-size: 18px">{{ item.user.username }}</div>
<div style="font-size: 25px">{{ item.comment }}</div>
@ -181,4 +206,9 @@ const commentList = ref([
border-radius: 30px;
}
}
.book-introduction {
margin-top: 10px;
font-size: 20px;
}
</style>

View File

@ -1,46 +1,42 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useT_bookApi } from "../../../api/maku/t_book";
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { bookEntity, bookList, bookSearchList } from '@/api/maku/t_book'
const router = useRouter()
const books = ref<bookEntity[]>([])
const totalBooks = 5; // 5
const inputSearchValue = ref('')
// 5
const books = ref(Array(totalBooks).fill({}));
onMounted(async () => {
const res = await bookList()
books.value = res.data
})
// API
function getBook(index: number) {
useT_bookApi(index + 1).then(res => {
books.value[index] = res.data;
});
const handleSearch = async () => {
const res = await bookSearchList(inputSearchValue.value)
books.value = res.data
}
// 使
for (let i = 0; i < totalBooks; i++) {
getBook(i);
}
</script>
<template>
<div class="search-suggest-combobox">
<div class="input-search">
<input placeholder="马嘉祺" />
<button >搜索</button>
<input v-model="inputSearchValue" placeholder="马嘉祺" />
<button @click="handleSearch">搜索</button>
</div>
</div>
<div class="screen-outer">
<div class="tb-pick-content-item" v-for="book in books" :key="book.id">
<div class="img-wrapper">
<img :src="book.bookCover" style="width:100%; height:120%;" alt="Book Cover">
</div>
<div class="info-wrapper">{{ book.bookName }}</div>
<div class="price-wrapper">
<span class="price-unit">¥</span>
<span class="price-value">{{ book.price }}</span>
</div>
</div>
</div>
<div v-for="item in books" :key="item.id" class="tb-pick-content-item" @click="router.push(`/book/details?id=${item.id}`)">
<div class="img-wrapper">
<img :src="item.bookCover" style="width: 100%; height: 120%" alt="Book Cover" />
</div>
<div class="info-wrapper">{{ item.bookName }}</div>
<div class="price-wrapper">
<span class="price-unit">¥</span>
<span class="price-value">{{ item.price }}</span>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
@ -84,8 +80,7 @@ for (let i = 0; i < totalBooks; i++) {
}
.screen-outer {
transform:translate(10px);
transform: translate(10px);
background: #fff;
width: 1552px;
margin: 30px auto;

View File

@ -34,8 +34,8 @@ const loginFormRef = ref()
const captchaBase64 = ref()
const loginForm = reactive({
username: constant.env.PROD ? '' : 'admin',
password: constant.env.PROD ? '' : 'admin',
username: constant.env.PROD ? '' : '',
password: constant.env.PROD ? '' : '',
key: '',
captcha: ''
})

View File

@ -10,10 +10,10 @@
<div class="login-form">
<div class="login-title">
<el-button link :class="loginType === 'account' ? 'account' : ''" @click="loginSwitch('account')">{{ $t('app.signIn') }}</el-button>
<el-button link :class="loginType === 'mobile' ? 'account' : ''" @click="loginSwitch('mobile')">{{ $t('app.mobileSignIn') }}</el-button>
<el-button link :class="loginType === 'register' ? 'account' : ''" @click="loginSwitch('register')">{{ $t('app.register') }}</el-button>
</div>
<account v-if="loginType === 'account'" />
<mobile v-if="loginType === 'mobile'" />
<register v-if="loginType === 'register'" />
</div>
</div>
</template>
@ -23,6 +23,7 @@ import { ref } from 'vue'
import Account from './account.vue'
import Mobile from './mobile.vue'
import Third from './third.vue'
import Register from '@/views/login/register.vue'
//
const loginType = ref('account')

View File

@ -0,0 +1,127 @@
<template>
<el-form ref="registerFormRef" :model="registerForm" :rules="registerRules" @keyup.enter="onRegister">
<el-form-item prop="username">
<el-input v-model="registerForm.username" :prefix-icon="User" :placeholder="$t('app.username')"></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input v-model="registerForm.password" :prefix-icon="Lock" show-password :placeholder="$t('app.password')"></el-input>
</el-form-item>
<el-form-item prop="rePassword">
<el-input v-model="registerForm.rePassword" :prefix-icon="Lock" show-password :placeholder="$t('app.rePassword')"></el-input>
</el-form-item>
<el-form-item class="register-button">
<el-button type="primary" @click="onRegister()">{{ $t('app.signIn') }}</el-button>
</el-form-item>
</el-form>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import { User, Lock } from '@element-plus/icons-vue'
import { useUserStore } from '@/store/modules/user'
import { useCaptchaApi, useCaptchaEnabledApi, userRegisterApi } from '@/api/auth'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import constant from '@/utils/constant'
import { sm2Encrypt } from '@/utils/smCrypto'
import { ElNotification } from 'element-plus'
const userStore = useUserStore()
const router = useRouter()
const { t } = useI18n()
const registerFormRef = ref()
const captchaBase64 = ref()
const registerForm = reactive({
username: '',
password: '',
rePassword: ''
})
const registerRules = ref({
username: [{ required: true, message: t('required'), trigger: 'blur' }],
password: [{ required: true, message: t('required'), trigger: 'blur' }],
rePassword: [{ required: true, message: t('required'), trigger: 'blur' }]
})
//
const captchaVisible = ref(false)
onMounted(() => {
onCaptchaEnabled()
})
const onCaptchaEnabled = async () => {
const { data } = await useCaptchaEnabledApi()
captchaVisible.value = data
if (data) {
await onCaptcha()
}
}
const onCaptcha = async () => {
const { data } = await useCaptchaApi()
if (data.enabled) {
captchaVisible.value = true
}
captchaBase64.value = data.image
}
const onRegister = () => {
registerFormRef.value.validate((valid: boolean) => {
if (!valid) {
return false
}
if (registerForm.password != registerForm.rePassword) {
ElNotification({
title: '两次输入的密码不一样!',
type: 'error'
})
return
}
//
const registerData = {
username: registerForm.username,
password: sm2Encrypt(registerForm.password)
}
// TODO
//
// userRegisterApi(registerData).then(res => {
// ElNotification({
// title: '',
// type: 'success'
// })
// })
})
}
</script>
<style lang="scss" scoped>
.register-captcha {
:deep(.el-input) {
width: 200px;
}
}
.register-captcha img {
width: 150px;
height: 40px;
margin: 5px 0 0 10px;
cursor: pointer;
}
.register-button {
:deep(.el-button--primary) {
margin-top: 10px;
width: 100%;
height: 45px;
font-size: 18px;
letter-spacing: 8px;
}
}
</style>