Commit a470cc27 authored by Zhang Xiaojie's avatar Zhang Xiaojie

feat:注册账号页面

parent e4bc3a73
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
import '@vue/runtime-core'
declare module '@vue/runtime-core' {
export interface GlobalComponents {
AButton: typeof import('ant-design-vue/es')['Button']
AInput: typeof import('ant-design-vue/es')['Input']
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
ApplyShop: typeof import('./src/components/applyShop/applyShop.vue')['default']
AStep: typeof import('ant-design-vue/es')['Step']
ASteps: typeof import('ant-design-vue/es')['Steps']
CompleteInfo: typeof import('./src/components/applyShop/completeInfo.vue')['default']
Logo: typeof import('./src/components/Logo.vue')['default']
ProgressBar: typeof import('./src/components/ProgressBar.vue')['default']
Register: typeof import('./src/components/applyShop/register.vue')['default']
SlgBtn: typeof import('./src/components/SlgBtn.vue')['default']
SlgInput: typeof import('./src/components/SlgInput.vue')['default']
}
}
export {}
...@@ -8,12 +8,17 @@ ...@@ -8,12 +8,17 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"ant-design-vue": "^3.2.5",
"axios": "^0.27.2", "axios": "^0.27.2",
"vue": "^3.2.25" "unplugin-vue-components": "^0.19.6",
"vue": "^3.2.25",
"vue-router": "4"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^2.3.3", "@vitejs/plugin-vue": "^2.3.3",
"autoprefixer": "^10.4.7", "autoprefixer": "^10.4.7",
"less": "^4.1.2",
"less-loader": "^11.0.0",
"postcss": "^8.4.14", "postcss": "^8.4.14",
"tailwindcss": "^3.0.24", "tailwindcss": "^3.0.24",
"typescript": "^4.5.4", "typescript": "^4.5.4",
......
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>
<template> <template>
<img alt="Vue logo" src="./assets/logo.png" /> <div>
<HelloWorld msg="Hello Vue 3 + TypeScript + Vite" /> <router-view></router-view>
</div>
</template> </template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
import request from "../utils/request";
import { ApplyProgessRes } from "../types";
const baseURL = '/api/malladmin'
export const sendVerifyCode = (params: { phone: number, type: number }) => {
return request<void>({
url: baseURL + '/sms/sendVerifyCode',
method: 'GET',
params: params
})
}
export const register = (data: { code: string, phone: string }) => {
return request<{ token: string }>({
url: baseURL + '/merchantApply/register',
method: 'POST',
data: data
})
}
export const getApplyProgressByPhoneAndToken = (data: { phone: string, token: string }) => {
return request<{ status: ApplyProgessRes }>({
url: baseURL + '/merchantApply/getApplyProgressByPhoneAndToken',
method: 'GET',
params: data
})
}
\ No newline at end of file
src/assets/logo.png

6.69 KB | W: | H:

src/assets/logo.png

14.1 KB | W: | H:

src/assets/logo.png
src/assets/logo.png
src/assets/logo.png
src/assets/logo.png
  • 2-up
  • Swipe
  • Onion skin
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VS Code</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>
<p>See <code>README.md</code> for more information.</p>
<p>
<a href="https://vitejs.dev/guide/features.html" target="_blank">
Vite Docs
</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
</p>
<button type="button" @click="count++">count is: {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test hot module replacement.
</p>
</template>
<style scoped>
a {
color: #42b983;
}
label {
margin: 0 0.5em;
font-weight: bold;
}
code {
background-color: #eee;
padding: 2px 4px;
border-radius: 4px;
color: #304455;
}
</style>
<template>
<div class=" flex items-center justify-center md:justify-start">
<img src="@/assets/logo.png" class=" w-14 h-14 ">
<div class=" text-mainPurple text-3xl font-semibold pl-2">上链购</div>
</div>
</template>
<script lang="ts" setup></script>
\ No newline at end of file
<template>
<div class=" flex w-full">
<div v-for="(i, index) in props.list" class=" flex items-center">
<div class=" rounded-full border-gray-500 border w-7 h-7 text-center leading-7"
:class="textClassObj(i.status)">
{{ index + 1 }}
</div>
<span class=" text-xl font-semibold ml-3">
{{ i.title }}
</span>
<div class=" h-skinny w-14 bg-textGray mx-2" v-if="index != props.list.length - 1"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface Props {
list: Array<{ title: string, status: number }>,
current: number
}
const props = withDefaults(defineProps<Props>(), {
})
const textClassObj = computed(()=>{
return (status:number)=>{
const current = status == props.current
// const
return{
'bg-mainPurple text-white':current,
'text-textGray border-textGray':!current
}
}
})
</script>
\ No newline at end of file
<template>
<button type="button" class=" text-center py-3 bg-mainPurple text-white rounded" @click="handleClick">
<slot></slot>
</button>
</template>
<script lang="ts" setup>
const emits = defineEmits(['clickBtn'])
const handleClick = () => {
emits('clickBtn')
}
</script>
\ No newline at end of file
<template>
<div>
<a-input-search v-if="props.model == 'action'" :value="textValue" @input="handleInput" :placeholder="placeholder" @search="handleAction">
<template #enterButton>
<a-button>{{actionText}}</a-button>
</template>
</a-input-search>
<a-input v-else :value="textValue" @input="handleInput" :placeholder="placeholder" />
</div>
</template>
<script lang="ts" setup>
interface Prop {
model?: 'action' | 'default',
actionText?: string,
placeholder?: string,
textValue:string
}
const props = withDefaults(defineProps<Prop>(), {
model: 'default'
})
const emits = defineEmits(['update:textValue', 'handleAction'])
const handleInput = (e: any) => {
emits('update:textValue', e.target.value)
}
const handleAction = () => {
emits('handleAction')
}
</script>
<style scoped>
:deep(.ant-input-group){
font-size: 1rem;
}
:deep(.ant-input){
padding: 0.875rem 1.875rem ;
}
:deep(.ant-input-search-button){
height: 52px;
}
</style>
<template>
<div>
完善信息
</div>
</template>
\ No newline at end of file
<template>
<div>
<SlgInput model="action" action-text="发送验证码" placeholder="请输入手机号" v-model:textValue="phone"
@handle-action="handleClick(BTN.SENDSMS)">
</SlgInput>
<SlgInput class=" mt-9" placeholder="请输入验证码" v-model:textValue="code"></SlgInput>
<SlgBtn class=" w-full mt-20" @click-btn="handleClick(BTN.NEXTSTEP)">下一步</SlgBtn>
<p class=" cursor-pointer pt-9 text-center pb-72">
<span class=" text-textGray">您提交入驻申请,即代表您同意 </span>
<span class=" text-mainPurple"
@click="handleClick(BTN.JUMP, 'https://adminslg.8n.cn/#/shopAgreement')">《上链购商户服务协议》</span>
<span class=" text-textGray"></span>
<span class="text-mainPurple"
@click="handleClick(BTN.JUMP, 'https://adminslg.8n.cn/#/privacy')">《上链购商户隐私协议》</span>
</p>
</div>
</template>
<script setup lang="ts">
import SlgInput from '@/components/SlgInput.vue';
import SlgBtn from '@/components/SlgBtn.vue';
import { sendVerifyCode, register } from '@/api'
import { ref } from 'vue'
import { message, Step } from 'ant-design-vue';
import { useRoute, useRouter } from 'vue-router';
enum BTN {
'SENDSMS',
'NEXTSTEP',
'JUMP'
}
/* form */
const phone = ref('')
const code = ref('')
const router = useRouter()
const route = useRoute()
const handleClick = async (type: BTN, url?: string) => {
if (type == BTN.SENDSMS) {
if (phone.value) {
await sendVerifyCode({ phone: +phone.value, type: 1 })
message.info({
content: "验证码已发送",
duration: 5
})
} else {
message.error({
content: "手机号不得为空",
duration: 5
})
}
}
else if (type == BTN.NEXTSTEP) {
if (!phone.value || !code.value) {
message.error({
content: "手机号和验证码不可为空",
duration: 5
})
return
}
else {
console.log(route.path);
const res = await register({ code: code.value, phone: phone.value })
router.push({ name:'ShopInfo',query: { token: res.data.token, phone: phone.value } })
}
}
else if (type == BTN.JUMP) {
window.open(url)
}
}
</script>
\ No newline at end of file
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import './index.css' import './index.css'
createApp(App).mount('#app') import {Steps,Input,Button} from 'ant-design-vue'
import 'ant-design-vue/dist/antd.less'
import myRouter from '@/router'
createApp(App).use(myRouter).use(Steps).use(Input).use(Button).mount('#app')
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
export const basicRoutes = [
{
path:'/',
name:'Index',
redirect: '/applyShop',
},
{
path:'/applyShop',
name:'ApplyShop',
component:()=>import ('@/views/index.vue')
},
{
path:'/shopInfo',
name:'ShopInfo',
component:()=>import ('@/views/index.vue')
}
] as RouteRecordRaw[]
const myRouter = createRouter({
history: createWebHashHistory(),
routes: basicRoutes
})
export default myRouter
/*
状态(0-正常 1-锁定 2-待完善 3-待签约 4-签约失败 5-待缴费 6-缴费失败 7.待设置密码)
*/
export enum ApplyProgessRes{
'success',
'locked',
'imcomplete',
'toSignUp',
'failSignUp',
'toPay',
'failPay',
'toSetPwd',
'notstart'=999
}
export enum ApplyProgess{
"register",
"completeInfo",
"check",
"setPwd",
"finished"
}
\ No newline at end of file
import Axios,{AxiosRequestConfig} from "axios";
import { message } from 'ant-design-vue';
const service = Axios.create({
timeout: 30000
})
// request interceptor
service.interceptors.request.use(
(config) => {
return config;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
// response interceptor
service.interceptors.response.use(
(response) => {
console.log(response);
const res = response.data;
if (res.code !== '00000') {
message.error({
content: res.msg || "Error",
duration: 5 * 1000,
});
return Promise.reject(new Error(res.msg || "Error"));
} else {
return res;
}
},
(error) => {
console.log("err" + error);
message.error({
content: error.response.data.msg || "Error",
duration: 5 ,
});
return Promise.reject(error);
}
);
interface iResponse<T = any> {
code: number;
data: T;
msg: string;
}
const request = <T = any>(config: AxiosRequestConfig) =>
service.request<any, iResponse<T>>(config);
export default request
\ No newline at end of file
<script setup lang="ts">
import { computed, defineAsyncComponent, onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { getApplyProgressByPhoneAndToken } from '@/api';
import Logo from '@/components/Logo.vue';
import { ApplyProgess, ApplyProgessRes } from '@/types';
/* handle progres */
const steps = [
{
title: '注册账号',
status: 0
},
{
title: '完善信息',
status: 1
},
{
title: '平台审核',
status: 2
},
{
title: '设置密码',
status: 3
},
{
title: '完成',
status: 4
},
]
/* get curret application status */
const route = useRoute()
const token = computed((): string => {
return route.query.token as unknown as string
})
const phone = computed((): string => {
return route.query.phone as unknown as string
})
const status = ref(999 as ApplyProgessRes)
onMounted(async () => {
console.log(111);
if (token.value && phone.value) {
const res = await getApplyProgressByPhoneAndToken({ phone: phone.value, token: token.value })
status.value = res.data.status
}
})
const current = computed(() => {
let stepStatus
switch (status.value) {
case 999:
stepStatus = ApplyProgess.register
break
case 2:
stepStatus = ApplyProgess.completeInfo
break
case 3:
stepStatus = ApplyProgess.completeInfo
break
case 5:
stepStatus = ApplyProgess.check
break
case 0:
stepStatus = ApplyProgess.setPwd
break
case 7:
stepStatus = ApplyProgess.check
break
case 4:
stepStatus = ApplyProgess.completeInfo
break
}
return stepStatus
})
/* switch board */
const Modeuls = import.meta.glob("../components/applyShop/**/**.vue");
const currentView = computed(() => {
let name
if (current.value == ApplyProgess.register) name = 'register'
else if (current.value == ApplyProgess.completeInfo) name = 'completeInfo'
const component = Modeuls[`../components/applyShop/${name}.vue`] as any;
return defineAsyncComponent(component)
})
</script>
<template>
<div class=" bg-bgPurple min-h-screen min-w-body">
<div class=" w-bodySet mx-auto pt-14">
<Logo />
<div class=" bg-white w-pcWidth rounded-slgRounded mt-5">
<p class=" text-4xl font-semibold text-center pt-14">商家入驻申请</p>
<div class="stepWrapper px-40">
<a-steps :current="1" size="default">
<a-step v-for="s in steps" :title="s.title" />
</a-steps>
</div>
<div class=" w-inputWidth mx-auto pt-20">
<component :is="currentView"></component>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.stepWrapper :deep(.anticon) {
vertical-align: 0.1rem;
}
.stepWrapper :deep(.anticon svg) {
width: 14px;
height: 14px;
}
.stepWrapper :deep(.ant-steps-item-icon) {
width: 28px;
height: 28px;
line-height: 28px;
border-radius: 28px;
}
.stepWrapper :deep(.ant-steps-item-title) {
color: #353535;
font-weight: 600;
line-height: 28px;
}
.stepWrapper :deep(.ant-steps-icon) {
line-height: 28px;
}
.stepWrapper :deep(.ant-steps-item-title::after) {
background-color: #C7C7C7;
}
.stepWrapper :deep(.ant-steps .ant-steps-item:not(.ant-steps-item-active) > .ant-steps-item-container[role='button'] .ant-steps-item-title) {
color: #353535;
}
.stepWrapper :deep(.ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after) {
background-color: #C7C7C7;
}
:deep(.ant-steps-item-wait > .ant-steps-item-container > .ant-steps-item-content > .ant-steps-item-title::after) {
background-color: #C7C7C7;
}
</style>
...@@ -4,7 +4,31 @@ module.exports = { ...@@ -4,7 +4,31 @@ module.exports = {
"./src/**/*.{vue,js,ts,jsx,tsx}", "./src/**/*.{vue,js,ts,jsx,tsx}",
], ],
theme: { theme: {
extend: {}, extend: {
colors: {
mainPurple: '#4C37D6',
secondaryPurple: '#D0C7FB',
bgPurple: '#E8E7FC',
textGray:'#C7C7C7',
btnGray:'#E0E0E0'
},
spacing: {
bodySet: '1535px',
pcWidth: '1200px',
skinny:'1px',
inputHeight:'3.125rem',
inputWidth:'41rem'
},
fontSize:{
'28px':'1.75rem'
},
minWidth: {
body: '1535px'
},
borderRadius:{
slgRounded:'1.25rem'
}
},
}, },
plugins: [], plugins: [],
} }
...@@ -10,9 +10,27 @@ ...@@ -10,9 +10,27 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["esnext", "dom"], "lib": [
"skipLibCheck": true "esnext",
"dom"
],
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
},
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": [
"references": [{ "path": "./tsconfig.node.json" }] "src/**/*.ts",
} "src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue"
],
"references": [
{
"path": "./tsconfig.node.json"
}
]
}
\ No newline at end of file
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue()] plugins: [
vue(),
Components({
resolvers: [AntDesignVueResolver()],
}),
],
resolve: {
alias:
[
{
find: '@', replacement: '/src'
},
],
},
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars:{
'@primary-color':' #4C37D6'
}
}
}
},
server: {
proxy: {
'^/api': {
target: "https://testadminnewapp.8n.cn/root",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
}
}
}) })
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment