Commit 08c9395f authored by 刘斌's avatar 刘斌

Initial commit

parents
# Local
.DS_Store
*.local
*.log*
# Dist
node_modules
dist/
# Profile
.rspack-profile-*/
# IDE
.vscode/*
!.vscode/extensions.json
.idea
{
"recommendations": ["Vue.volar"]
}
# AGENTS.md
You are an expert in JavaScript, Rsbuild, and web application development. You write maintainable, performant, and accessible code.
## Commands
- `pnpm run dev` - Start the dev server
- `pnpm run build` - Build the app for production
- `pnpm run preview` - Preview the production build locally
## Docs
- Rsbuild: https://rsbuild.rs/llms.txt
- Rspack: https://rspack.rs/llms.txt
## Tools
### Biome
- Run `pnpm run lint` to lint your code
- Run `pnpm run format` to format your code
# Rsbuild project
## Setup
Install the dependencies:
```bash
pnpm install
```
## Get started
Start the dev server, and the app will be available at [http://localhost:3000](http://localhost:3000).
```bash
pnpm run dev
```
Build the app for production:
```bash
pnpm run build
```
Preview the production build locally:
```bash
pnpm run preview
```
## Learn more
To learn more about Rsbuild, check out the following resources:
- [Rsbuild documentation](https://rsbuild.rs) - explore Rsbuild features and APIs.
- [Rsbuild GitHub repository](https://github.com/web-infra-dev/rsbuild) - your feedback and contributions are welcome!
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
},
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"formatter": {
"indentStyle": "space"
},
"javascript": {
"formatter": {
"quoteStyle": "single"
}
},
"css": {
"parser": {
"cssModules": true
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
}
}
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
VanButton: typeof import('vant/es')['Button']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanDatePicker: typeof import('vant/es')['DatePicker']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanPicker: typeof import('vant/es')['Picker']
VanPopup: typeof import('vant/es')['Popup']
VanUploader: typeof import('vant/es')['Uploader']
}
}
{
"name": "hr-mobile-view",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "rsbuild build",
"check": "biome check --write",
"dev": "rsbuild dev --open",
"format": "biome format --write",
"preview": "rsbuild preview"
},
"dependencies": {
"vant": "^4.9.21",
"vue": "^3.5.24"
},
"devDependencies": {
"@biomejs/biome": "2.3.2",
"@rsbuild/core": "^1.6.7",
"@rsbuild/plugin-less": "^1.5.0",
"@rsbuild/plugin-vue": "^1.2.0",
"@vant/auto-import-resolver": "^1.3.0",
"typescript": "^5.9.3",
"unplugin-auto-import": "^20.2.0",
"unplugin-vue-components": "^29.2.0"
}
}
This diff is collapsed.
import { defineConfig } from '@rsbuild/core';
import { pluginLess } from '@rsbuild/plugin-less';
import { pluginVue } from '@rsbuild/plugin-vue';
import { VantResolver } from '@vant/auto-import-resolver';
import AutoImport from 'unplugin-auto-import/rspack';
import Components from 'unplugin-vue-components/rspack';
// Docs: https://rsbuild.rs/config/
export default defineConfig({
plugins: [pluginVue(), pluginLess()],
tools: {
rspack: {
plugins: [
AutoImport({
dts: 'auto-imports.d.ts',
resolvers: [VantResolver()],
}),
Components({
dts: 'components.d.ts',
resolvers: [VantResolver()],
}),
],
},
},
});
<template>
<div class="page">
<van-form @submit="onSubmit">
<van-cell-group inset title="基本信息">
<van-field
v-model="form.name"
name="name"
label="姓名"
placeholder="请输入姓名"
:rules="[{ required: true, message: '请填写姓名' }]"
/>
<van-field
v-model="form.genderText"
name="gender"
label="性别"
placeholder="请选择性别"
readonly
is-link
:rules="[{ required: true, message: '请选择性别' }]"
@click="showGenderPicker = true"
/>
<van-field
v-model="form.birthDate"
name="birthDate"
label="出生日期"
placeholder="请选择出生日期"
readonly
is-link
:rules="[{ required: true, message: '请选择出生日期' }]"
@click="showBirthPicker = true"
/>
<van-field
v-model="form.age"
name="age"
type="digit"
label="年龄"
placeholder="请输入年龄"
:rules="ageRules"
/>
<van-field
v-model="form.nation"
name="nation"
label="民族"
placeholder="请输入民族"
/>
<van-field
v-model="form.nativePlace"
name="nativePlace"
label="籍贯"
placeholder="请输入籍贯"
/>
<van-field
v-model="form.maritalText"
name="maritalStatus"
label="婚姻状况"
placeholder="请选择婚姻状况"
readonly
is-link
@click="showMaritalPicker = true"
/>
<van-field
v-model="form.politicalText"
name="politicalStatus"
label="政治面貌"
placeholder="请选择政治面貌"
readonly
is-link
@click="showPoliticalPicker = true"
/>
<van-field name="photo" label="照片">
<template #input>
<van-uploader v-model="form.photoList" :max-count="1" />
</template>
</van-field>
<van-field
v-model="form.idNumber"
name="idNumber"
label="身份证号码"
placeholder="请输入身份证号码"
:rules="idRules"
/>
</van-cell-group>
<van-cell-group inset title="联系信息">
<van-field
v-model="form.phone"
name="phone"
type="tel"
label="手机号码"
placeholder="请输入手机号码"
:rules="phoneRules"
/>
<van-field
v-model="form.emergencyContact"
name="emergencyContact"
label="紧急联系人"
placeholder="请输入紧急联系人"
/>
<van-field
v-model="form.emergencyPhone"
name="emergencyPhone"
type="tel"
label="紧急联系人电话"
placeholder="请输入紧急联系人电话"
:rules="phoneRules"
/>
</van-cell-group>
<van-cell-group inset title="地址信息">
<van-field
v-model="form.address"
name="address"
label="家庭地址"
type="textarea"
rows="2"
autosize
placeholder="请输入家庭地址"
/>
<van-field
v-model="form.householdRegister"
name="householdRegister"
label="户口所在地"
type="textarea"
rows="2"
autosize
placeholder="请输入户口所在地"
/>
</van-cell-group>
<div class="actions">
<van-button round block type="primary" native-type="submit">提交</van-button>
</div>
</van-form>
<van-popup v-model:show="showGenderPicker" position="bottom">
<van-picker :columns="genderColumns" @confirm="onGenderConfirm" @cancel="showGenderPicker = false" />
</van-popup>
<van-popup v-model:show="showMaritalPicker" position="bottom">
<van-picker :columns="maritalColumns" @confirm="onMaritalConfirm" @cancel="showMaritalPicker = false" />
</van-popup>
<van-popup v-model:show="showPoliticalPicker" position="bottom">
<van-picker :columns="politicalColumns" @confirm="onPoliticalConfirm" @cancel="showPoliticalPicker = false" />
</van-popup>
<van-popup v-model:show="showBirthPicker" position="bottom">
<van-date-picker
v-model="birthValues"
title="选择日期"
@confirm="onBirthConfirm"
@cancel="showBirthPicker = false"
/>
</van-popup>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, watch } from 'vue';
const form = reactive({
name: '',
phone: '',
gender: '',
genderText: '',
photoList: [] as unknown[],
idNumber: '',
birthDate: '',
age: '' as number | '',
address: '',
nation: '',
nativePlace: '',
maritalStatus: '',
maritalText: '',
politicalStatus: '',
politicalText: '',
emergencyContact: '',
emergencyPhone: '',
householdRegister: '',
});
const phoneRules = [
{ required: true, message: '请填写手机号码' },
{ pattern: /^1\d{10}$/, message: '手机号格式错误' },
];
const idRules = [
{ required: true, message: '请填写身份证号码' },
{ pattern: /^(\d{15}|\d{17}[\dXx])$/, message: '身份证格式错误' },
];
const ageRules = [{ pattern: /^\d{1,3}$/, message: '年龄格式错误' }];
const showGenderPicker = ref(false);
const showMaritalPicker = ref(false);
const showPoliticalPicker = ref(false);
const showBirthPicker = ref(false);
const genderOptions = [
{ key: '0', value: '男' },
{ key: '1', value: '女' },
];
const maritalOptions = [
{ key: '1', value: '未婚' },
{ key: '2', value: '已婚' },
{ key: '3', value: '离异' },
];
const politicalOptions = [
{ key: '1', value: '党员' },
{ key: '2', value: '预备党员' },
{ key: '3', value: '群众' },
{ key: '4', value: '团员' },
];
const genderColumns = genderOptions.map((o) => ({
text: o.value,
value: o.key,
}));
const maritalColumns = maritalOptions.map((o) => ({
text: o.value,
value: o.key,
}));
const politicalColumns = politicalOptions.map((o) => ({
text: o.value,
value: o.key,
}));
const birthValues = ref<string[]>([]);
void [ageRules, genderColumns, maritalColumns, politicalColumns, birthValues];
function onGenderConfirm(payload: {
selectedOptions: { text: string; value: string }[];
}) {
const opt = payload.selectedOptions[0];
form.gender = opt.value;
form.genderText = opt.text;
showGenderPicker.value = false;
}
function onMaritalConfirm(payload: {
selectedOptions: { text: string; value: string }[];
}) {
const opt = payload.selectedOptions[0];
form.maritalStatus = opt.value;
form.maritalText = opt.text;
showMaritalPicker.value = false;
}
function onPoliticalConfirm(payload: {
selectedOptions: { text: string; value: string }[];
}) {
const opt = payload.selectedOptions[0];
form.politicalStatus = opt.value;
form.politicalText = opt.text;
showPoliticalPicker.value = false;
}
function onBirthConfirm(payload: { selectedValues: string[] }) {
const [y, m, d] = payload.selectedValues;
form.birthDate = `${y}-${m}-${d}`;
showBirthPicker.value = false;
}
watch(
() => form.birthDate,
(v) => {
if (!v) return;
const parts = v.split('-').map((x) => Number(x));
if (parts.length === 3) {
const now = new Date();
const birth = new Date(parts[0], parts[1] - 1, parts[2]);
let a = now.getFullYear() - birth.getFullYear();
const m = now.getMonth() - birth.getMonth();
const d = now.getDate() - birth.getDate();
if (m < 0 || (m === 0 && d < 0)) a--;
form.age = a;
}
},
);
function onSubmit() {
return;
}
void [
onGenderConfirm,
onMaritalConfirm,
onPoliticalConfirm,
onBirthConfirm,
onSubmit,
];
void [phoneRules, idRules];
</script>
<style scoped>
.page {
padding: 12px 12px 88px;
min-height: 100vh;
background: #f5f5f5;
}
.actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
padding: 12px;
background: var(--van-background-2);
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
}
:deep(.van-cell-group__title) {
font-size: 14px;
color: var(--van-text-color-2);
padding-left: 4px;
}
</style>
/// <reference types="@rsbuild/core/types" />
declare module '*.vue' {
import type { DefineComponent } from 'vue';
// biome-ignore lint/complexity/noBannedTypes: reason
const component: DefineComponent<{}, {}, any>;
export default component;
}
body {
margin: 0;
color: #fff;
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
background-image: linear-gradient(to bottom, #020917, #101725);
}
import { createApp } from 'vue';
import App from './App.vue';
import './index.css';
createApp(App).mount('#root');
{
"compilerOptions": {
"lib": ["DOM", "ES2020"],
"jsx": "preserve",
"target": "ES2020",
"noEmit": true,
"skipLibCheck": true,
"jsxImportSource": "vue",
"useDefineForClassFields": true,
/* modules */
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noUncheckedSideEffectImports": true,
/* type checking */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true
},
"include": ["src", "./auto-imports.d.ts", "components.d.ts"]
}
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