feat: api创建

This commit is contained in:
zhangyh
2025-10-24 17:37:15 +08:00
parent 21384516ce
commit 5fe30c82c8
14 changed files with 197 additions and 86 deletions

12
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.0.0",
"hasInstallScript": true,
"dependencies": {
"@microsoft/fetch-event-source": "^2.0.1",
"axios": "^1.3.6",
"gsap": "^3.13.0",
"normalize.css": "^8.0.1",
@@ -581,6 +582,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@microsoft/fetch-event-source": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==",
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -8827,6 +8834,11 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@microsoft/fetch-event-source": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
},
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",

View File

@@ -14,6 +14,7 @@
"postinstall": "husky install"
},
"dependencies": {
"@microsoft/fetch-event-source": "^2.0.1",
"axios": "^1.3.6",
"gsap": "^3.13.0",
"normalize.css": "^8.0.1",

33
src/api/login.ts Normal file
View File

@@ -0,0 +1,33 @@
import request from '@/utils/request'
interface LoginParamsType {
name?: string // 姓名
email: string // 邮箱
password: string // 密码
operationType: 'REGISTER' | 'LOGIN' | 'FORGET_PWD'
verifyCode?: string // 验证码
}
export const precheckAndSendEmail = (data: LoginParamsType) => {
return request({
url: '/api/auth/precheckAndSendEmail',
method: 'post',
data
})
}
export const fetchLogin = (data: LoginParamsType) => {
return request({
url: '/api/auth/registerOrLogin',
method: 'post',
data
})
}
export const resetPassword = (data: LoginParamsType) => {
return request({
url: '/api/auth/forgotPwd',
method: 'post',
data
})
}

View File

@@ -7,3 +7,4 @@ store.use(createPersistedState())
export default store
export * from './modules/generate'
export * from './modules/overall'
export * from './modules/userInfo'

View File

@@ -3,40 +3,73 @@ import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useUserInfoStore = defineStore('userInfo', () => {
// state
const num = ref(0)
const name = ref('张三')
const token = ref('')
const state = ref({
userInfo: {},
customerId: '',
token: '',
generateParams: {
stylistId: '',
sex: ''
}
})
// getters
const getUserInfo = computed(() => ({
num: num.value,
name: name.value,
token: token.value
}))
const getUserInfo = computed(() => state.value.userInfo)
// actions
const setUserInfo = (data: any) => {
name.value = data.name
token.value = data.token
state.value.userInfo = data
}
const loginOut = () => {
const setCustomerId = (data: string) => {
state.value.customerId = data
}
const setToken = (data: string) => {
state.value.token = data
}
const getGenerateParams = () => {
return state.value.generateParams
}
const setGenerateParams = (data: any) => {
state.value.generateParams = data
}
const resetGenerateParams = () => {
state.value.customerId = ''
state.value.generateParams = {
stylistId: '',
sex: ''
}
}
const login = async (data: any) => {
return new Promise((resolve, reject) => {})
}
const logOut = () => {
// 处理退出登录的一些逻辑
return new Promise((rez) => {
rez('111')
return new Promise((resolve) => {
state.value.token = ''
state.value.userInfo = {}
state.value.customerId = ''
resetGenerateParams()
resolve('')
})
}
return {
// state
num,
name,
token,
// getters
state,
getUserInfo,
// actions
setToken,
setUserInfo,
loginOut
setCustomerId,
setGenerateParams,
getGenerateParams,
resetGenerateParams,
logOut,
login
}
})

View File

@@ -10,7 +10,7 @@ import { useOverallStore } from '@/stores'
// 创建axios实例
console.log(import.meta.env.VITE_APP_URL,123)
const service = axios.create({
baseURL: import.meta.env.VITE_APP_URL, // api的base_url
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
// baseURL: import.meta.env.VITE_APP_URL, // api的base_url
timeout: 20000, // 请求超时时间
})

View File

@@ -13,8 +13,7 @@
<div class="message-text">
{{ value.content }}
</div>
<!-- AI消息显示操作栏 -->
<div v-if="!isMyself" class="message-actions flex">
<!-- <div v-if="!isMyself" class="message-actions flex">
<SvgIcon
v-for="item in actionList"
:key="item.value"
@@ -22,7 +21,7 @@
size="39"
@click.stop="handleClickAction(item.value)"
/>
</div>
</div> -->
</div>
</div>
</template>

View File

@@ -1,7 +1,7 @@
<template>
<div class="chat-list" ref="chatListRef">
<div class="chat-message-item" v-for="message in list" :key="message.id">
<NoticeItem :value="message" @send-message="handleSendMessage" />
<NoticeItem :value="message" />
</div>
</div>
</template>

View File

@@ -8,7 +8,7 @@
</div>
<template v-else>
<div class="content flex-1" v-if="!isLoading">
<NoticeList ref="noticeListRef" :list="messageList" @send-message="handleSendMessage" />
<NoticeList ref="noticeListRef" :list="messageList" />
</div>
<div class="footer" v-if="!isLoading">
<InputArea @send-message="handleSendMessage" />
@@ -24,12 +24,14 @@ import HeaderTitle from '@/components/HeaderTitle.vue'
import NoticeList from './components/NoticeList.vue'
import InputArea from './components/InputArea.vue'
import GenerateLoading from './components/GenerateLoading.vue'
import { ref, onMounted, onActivated } from 'vue'
import { ref, onMounted, onUnmounted } from 'vue'
import { useRouter } from 'vue-router'
import { fetchEventSource } from '@microsoft/fetch-event-source'
const router = useRouter()
defineOptions({
name:'asistant'
name: 'asistant'
})
// 定义NoticeList组件引用类型
@@ -80,26 +82,38 @@ const messageList = ref<ChatMessage[]>([
}
])
onMounted(() => {
console.log('🚀 组件挂载 - onMounted 触发')
// handleSendMessage('123')
})
onMounted(() => {})
onActivated(() => {
console.log('🔄 缓存页面激活 - onActivated 触发')
console.log('当前消息数量:', messageList.value.length)
onUnmounted(() => {
abort.abort()
})
const handleSendMessage = (message: string): void => {
console.log('收到消息:', message)
messageList.value.push({
id: '1',
content: message,
userId: '1',
time: new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }),
thumb: ''
console.log('发送:', message)
handleFetchMessage()
}
const abort = new AbortController()
const handleFetchMessage = () => {
fetchEventSource('/api/sse', {
method: 'POST',
openWhenHidden: true,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),
signal: abort.signal,
onopen: async (res) => {
console.log('连接建立', res)
},
onmessage: (event) => {
console.log('收到消息', event)
},
onerror: (error) => {
console.log('错误', error)
},
onclose: () => {
console.log('连接关闭')
}
})
//
}
const handleContinue = () => {

View File

@@ -48,6 +48,7 @@ import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import { showToast } from 'vant'
import { google } from '@/assets/base64'
import { fetchLogin } from '@/api/login'
const router = useRouter()
@@ -108,23 +109,19 @@ const handleLogin = async () => {
isLoading.value = true
try {
// 模拟登录API调用
await new Promise((resolve) => setTimeout(resolve, 2000))
// 这里添加实际的登录API调用
// const response = await loginAPI(formData)
showToast('登录成功')
// 登录成功后跳转到主页或工作台
router.push('/stylist/customer')
} catch (error) {
console.error('登录失败:', error)
showToast('登录失败,请重试')
} finally {
isLoading.value = false
const response: any = await fetchLogin({ ...formData, operationType: 'LOGIN' } as any)
if (response.code === 200) {
console.log('登录成功', response)
// showToast('登录成功')
// router.push('/stylist/customer')
} else {
showToast(response.message)
}
// showToast('登录成功')
// 登录成功后跳转到主页或工作台
// router.push('/stylist/customer')
}
// 处理忘记密码

View File

@@ -16,7 +16,7 @@
</div>
<div class="login-container">
<form @submit.prevent="handleLogin" class="login-form">
<form @submit.prevent="handleConfirm" class="login-form">
<div class="input-group">
<input
type="text"
@@ -68,6 +68,7 @@ import { ref, reactive, computed } from 'vue'
import { useRouter } from 'vue-router'
import { showToast } from 'vant'
import { google } from '@/assets/base64'
import { fetchLogin } from '@/api/login'
const router = useRouter()
@@ -151,7 +152,7 @@ const goBack = () => {
}
// 处理登录
const handleLogin = async () => {
const handleConfirm = async () => {
if (!validateForm()) {
showToast('请检查输入信息')
return
@@ -159,22 +160,13 @@ const handleLogin = async () => {
isLoading.value = true
try {
// 模拟登录API调用
await new Promise((resolve) => setTimeout(resolve, 2000))
// 这里添加实际的登录API调用
// const response = await loginAPI(formData)
showToast('登录成功')
// 登录成功后跳转到主页或工作台
router.push('/workshop')
} catch (error) {
console.error('登录失败:', error)
showToast('登录失败,请重试')
} finally {
isLoading.value = false
const res:any = await fetchLogin({...formData, operationType: 'REGISTER'} as any)
if(res.code === 200) {
console.log('注册成功', res)
// showToast('注册成功')
// router.push('/stylist/customer')
} else {
showToast(res.message)
}
}

View File

@@ -26,11 +26,11 @@
<div class="glass-form">
<div class="form-field">
<label class="field-label">Customer Name</label>
<input type="text" placeholder="Name" class="form-input" />
<input v-model="customeData.name" type="text" placeholder="Name" class="form-input" />
</div>
<div class="form-field email">
<label class="field-label">Customer Email</label>
<input type="email" placeholder="Email" class="form-input" />
<input v-model="customeData.email" type="email" placeholder="Email" class="form-input" />
</div>
<button class="confirm-btn" @click="handleConfirm">Confirm</button>
</div>
@@ -42,6 +42,9 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { useUserInfoStore } from '@/stores'
import { showToast } from 'vant'
const userInfoStore = useUserInfoStore()
const router = useRouter()
type PageMode = 'form' | 'entry'
@@ -51,8 +54,20 @@ const handleChangeMode = (mode: PageMode) => {
pageMode.value = mode
}
const handleConfirm = () => {
console.log('handleConfirm')
const customeData = ref({
name: '',
email: ''
})
const handleConfirm = async () => {
if (customeData.value.name === '' || customeData.value.email === '') {
showToast('please input name and email')
return
}
// await 查找顾客ID
// userInfoStore.setCustomerId('')
router.push('/stylist/index')
}
</script>

View File

@@ -14,7 +14,7 @@
<van-icon name="arrow-left" color="#fff" size="40" />
</div>
<van-swipe touchable ref="swiperRef">
<van-swipe touchable ref="swiperRef" @change="handleChangeCurrent">
<van-swipe-item v-for="item in stylists" :key="item.id">
<div class="swiper-container" @click="handleClickStylist(item)">
<img :src="item.image" />
@@ -64,9 +64,10 @@
import { ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import Video from './components/Video.vue'
import { useUserInfoStore } from '@/stores'
const router = useRouter()
const userInfoStore = useUserInfoStore()
// stylist数据
const stylists = ref<any[]>([
{
@@ -94,11 +95,17 @@ const stylists = ref<any[]>([
image: '/src/assets/images/male.png'
}
])
const currentChoosed=ref('')
const swiperRef = ref<any>(null)
const showVideo = ref<boolean>(false)
const videoRef = ref<any>(null)
const handleChangeCurrent=(index:number)=>{
currentChoosed.value = stylists.value[index].id
}
const handleChangeSwiper = (type: 'next' | 'prev') => {
if (type === 'next') {
swiperRef.value.next()
@@ -113,7 +120,10 @@ const handleClickStylist = (item: any) => {
}
const handleContinue = () => {
// 跳转到下一个页面
const generateParams = userInfoStore.getGenerateParams()
generateParams.stylistId = currentChoosed.value
userInfoStore.setGenerateParams(generateParams)
router.push('/stylist/sex')
}

View File

@@ -18,7 +18,9 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import {useUserInfoStore} from '@/stores'
const router = useRouter()
const userInfoStore = useUserInfoStore()
const options = ref<any[]>([
{ label: 'Female', value: '1' },
@@ -26,7 +28,9 @@ const options = ref<any[]>([
])
const handleSelect = (value: string) => {
console.log(value)
const generateParams = userInfoStore.getGenerateParams()
generateParams.sex = value
userInfoStore.setGenerateParams(generateParams)
router.push('/stylist/dressfor')
}
</script>