- 弃用 service 请求,重新设计了 request 请求方案。

- 用户信息绑定方式更改为 userInfo
This commit is contained in:
icssoa
2025-08-27 19:27:52 +08:00
parent 2bab42954a
commit d4c7467f8b
25 changed files with 222 additions and 528 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,341 +0,0 @@
export type UserAddressEntity = {
/**
* ID
*/
id?: number;
/**
* 用户ID
*/
userId?: number;
/**
* 联系人
*/
contact?: string;
/**
* 手机号
*/
phone?: string;
/**
* 省
*/
province?: string;
/**
* 市
*/
city?: string;
/**
* 区
*/
district?: string;
/**
* 地址
*/
address?: string;
/**
* 是否默认
*/
isDefault?: boolean;
/**
* 创建时间
*/
createTime?: string;
/**
* 更新时间
*/
updateTime?: string;
/**
* 任意键值
*/
};
export type UserInfoEntity = {
/**
* ID
*/
id?: number;
/**
* 登录唯一ID
*/
unionid?: string;
/**
* 头像
*/
avatarUrl?: string;
/**
* 昵称
*/
nickName?: string;
/**
* 手机号
*/
phone?: string;
/**
* 性别
*/
gender?: number;
/**
* 状态
*/
status?: number;
/**
* 登录方式
*/
loginType?: number;
/**
* 密码
*/
password?: string;
/**
* 介绍
*/
description?: string;
/**
* 生日
*/
birthday?: string;
/**
* 省
*/
province?: string;
/**
* 市
*/
city?: string;
/**
* 区
*/
district?: string;
/**
* 创建时间
*/
createTime?: string;
/**
* 更新时间
*/
updateTime?: string;
/**
* 任意键值
*/
};
export type json = any;
export type PagePagination = {
size: number;
page: number;
total: number;
};
export interface PageResponse<T> {
pagination: PagePagination;
list: T[];
}
export type UserAddressPageResponse = {
pagination: PagePagination;
list: UserAddressEntity[];
};
export type BaseComm = {
/**
* 文件上传模式
*/
uploadMode(data?: any): Promise<any>;
/**
* 文件上传
*/
upload(data?: any): Promise<any>;
/**
* 参数配置
*/
param(data?: any): Promise<any>;
/**
* 实体信息与路径
*/
eps(data?: any): Promise<any>;
};
export type DictInfo = {
/**
* 获得所有字典类型
*/
types(data?: any): Promise<any>;
/**
* 获得字典数据
*/
data(data?: any): Promise<any>;
};
export type UserAddress = {
/**
* 默认地址
*/
default(data?: any): Promise<any>;
/**
* 删除
*/
delete(data?: any): Promise<any>;
/**
* 修改
*/
update(data?: any): Promise<any>;
/**
* 单个信息
*/
info(data?: any): Promise<UserAddressEntity>;
/**
* 列表查询
*/
list(data?: any): Promise<UserAddressEntity[]>;
/**
* 分页查询
*/
page(data?: any): Promise<UserAddressPageResponse>;
/**
* 新增
*/
add(data?: any): Promise<any>;
};
export type UserComm = {
/**
* 获取微信公众号配置
*/
wxMpConfig(data?: any): Promise<any>;
};
export type UserInfo = {
/**
* 更新用户密码
*/
updatePassword(data?: any): Promise<any>;
/**
* 更新用户信息
*/
updatePerson(data?: any): Promise<any>;
/**
* 绑定手机号
*/
bindPhone(data?: any): Promise<any>;
/**
* 绑定小程序手机号
*/
miniPhone(data?: any): Promise<any>;
/**
* 获取用户信息
*/
person(data?: any): Promise<any>;
/**
* 注销
*/
logoff(data?: any): Promise<any>;
};
export type UserLogin = {
/**
* 刷新token
*/
refreshToken(data?: any): Promise<any>;
/**
* 绑定小程序手机号
*/
miniPhone(data?: any): Promise<any>;
/**
* 一键手机号登录
*/
uniPhone(data?: any): Promise<any>;
/**
* 密码登录
*/
password(data?: any): Promise<any>;
/**
* 图片验证码
*/
captcha(data?: any): Promise<any>;
/**
* 验证码
*/
smsCode(data?: any): Promise<any>;
/**
* 微信APP授权登录
*/
wxApp(data?: any): Promise<any>;
/**
* 手机号登录
*/
phone(data?: any): Promise<any>;
/**
* 小程序登录
*/
mini(data?: any): Promise<any>;
/**
* 公众号登录
*/
mp(data?: any): Promise<any>;
};
export type DictKey = "brand" | "occupation";
export type BaseInterface = { comm: BaseComm };
export type DictInterface = { info: DictInfo };
export type UserInterface = {
address: UserAddress;
comm: UserComm;
info: UserInfo;
login: UserLogin;
};
export type Service = { base: BaseInterface; dict: DictInterface; user: UserInterface };

View File

@@ -12,7 +12,7 @@
"</template>", "</template>",
"", "",
"<script lang=\"ts\" setup>", "<script lang=\"ts\" setup>",
"import { service, router } from \"@/cool\";", "import { router } from \"@/cool\";",
"", "",
"</script>", "</script>",
"", "",
@@ -35,7 +35,7 @@
"", "",
"<script lang=\"ts\" setup>", "<script lang=\"ts\" setup>",
"import { ref } from \"vue\";", "import { ref } from \"vue\";",
"import { service, router } from \"@/cool\";", "import { router } from \"@/cool\";",
"", "",
"// 是否可见", "// 是否可见",
"const visible = ref(false);", "const visible = ref(false);",
@@ -90,7 +90,7 @@
"", "",
"<script lang=\"ts\" setup>", "<script lang=\"ts\" setup>",
"import { ref } from \"vue\";", "import { ref } from \"vue\";",
"import { usePager } from \"@/cool\";", "import { usePager, request } from \"@/cool\";",
"import { useUi } from \"@/uni_modules/cool-ui\";", "import { useUi } from \"@/uni_modules/cool-ui\";",
"", "",
"const ui = useUi();", "const ui = useUi();",
@@ -98,7 +98,7 @@
"const listViewRef = ref<ClListViewComponentPublicInstance | null>(null);", "const listViewRef = ref<ClListViewComponentPublicInstance | null>(null);",
"", "",
"const { refresh, listView, loading, loadMore } = usePager((params) => {", "const { refresh, listView, loading, loadMore } = usePager((params) => {",
" return service.$1.page(params);", " return request({ $1 });",
"});", "});",
"", "",
"async function onPull() {", "async function onPull() {",

View File

@@ -15,13 +15,10 @@ export default {
console.log("App Show"); console.log("App Show");
// 根据业务情况判断是否要预先调用 // 根据业务情况判断是否要预先调用
// const { dict, user } = useStore(); const { user } = useStore();
// 获取用户信息,未登录不执行 // 获取用户信息,未登录不执行
// user.get(); user.get();
// 刷新字典数据
// dict.refresh(null);
}, },
onHide: function () { onHide: function () {
console.log("App Hide"); console.log("App Hide");

View File

@@ -59,7 +59,7 @@
import { computed, reactive, ref } from "vue"; import { computed, reactive, ref } from "vue";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
import { $t, t } from "@/locale"; import { $t, t } from "@/locale";
import { isDark, parse, service, type Response } from "@/cool"; import { isDark, parse, request, type Response } from "@/cool";
const props = defineProps({ const props = defineProps({
phone: String phone: String
@@ -144,18 +144,23 @@ async function getCaptcha() {
data: string; data: string;
}; };
await service.user.login await request({
.captcha({ url: "/app/user/login/captcha",
method: "POST",
data: {
color: isDark.value ? "#ffffff" : "#2c3142", color: isDark.value ? "#ffffff" : "#2c3142",
phone: props.phone, phone: props.phone,
width: 200, width: 200,
height: 70 height: 70
}) }
})
.then((res) => { .then((res) => {
const data = parse<Res>(res)!; if (res != null) {
const data = parse<Res>(res)!;
captchaId.value = data.captchaId; captchaId.value = data.captchaId;
captcha.img = data.data; captcha.img = data.data;
}
}) })
.catch((err) => { .catch((err) => {
ui.showToast({ ui.showToast({
@@ -173,12 +178,15 @@ async function send() {
if (code.value != "") { if (code.value != "") {
captcha.sending = true; captcha.sending = true;
await service.user.login await request({
.smsCode({ url: "/app/user/login/smsCode",
method: "POST",
data: {
phone: props.phone, phone: props.phone,
code: code.value, code: code.value,
captchaId: captchaId.value captchaId: captchaId.value
}) }
})
.then(() => { .then(() => {
ui.showToast({ ui.showToast({
message: t("短信已发送,请查收") message: t("短信已发送,请查收")

View File

@@ -16,7 +16,7 @@ type PagerResponse = {
}; };
// 分页回调函数类型 // 分页回调函数类型
type PagerCallback = (params: UTSJSONObject) => Promise<UTSJSONObject>; type PagerCallback = (params: UTSJSONObject) => Promise<any>;
// 分页器类 // 分页器类
export class Pager { export class Pager {
@@ -75,9 +75,6 @@ export class Pager {
this.size = pagination.size; this.size = pagination.size;
this.total = pagination.total; this.total = pagination.total;
// 更新加载完成状态
this.finished.value = this.list.value.length >= this.total;
// 更新列表数据 // 更新列表数据
if (data.page == 1) { if (data.page == 1) {
this.list.value = [...list]; this.list.value = [...list];
@@ -85,6 +82,9 @@ export class Pager {
this.list.value.push(...list); this.list.value.push(...list);
} }
// 更新加载完成状态
this.finished.value = this.list.value.length >= this.total;
resolve(res); resolve(res);
}) })
.catch((err) => { .catch((err) => {

View File

@@ -2,10 +2,12 @@ import { reactive } from "vue";
import { isNull } from "../utils"; import { isNull } from "../utils";
// #ifdef APP // #ifdef APP
// @ts-ignore
type Instance = ComponentPublicInstance | null; type Instance = ComponentPublicInstance | null;
// #endif // #endif
// #ifndef APP // #ifndef APP
// @ts-ignore
type Instance = any; type Instance = any;
// #endif // #endif

View File

@@ -1,6 +1,6 @@
import { ref } from "vue"; import { ref } from "vue";
import { assign, getUrlParam, storage } from "../utils"; import { assign, getUrlParam, storage } from "../utils";
import { service } from "../service"; import { request } from "../service";
import { t } from "@/locale"; import { t } from "@/locale";
import { config } from "@/config"; import { config } from "@/config";
@@ -62,20 +62,28 @@ export class Wx {
*/ */
getMpConfig() { getMpConfig() {
if (this.isWxBrowser()) { if (this.isWxBrowser()) {
service.user.comm request({
.wxMpConfig({ url: "/app/user/common/wxMpConfig",
method: "POST",
data: {
url: `${location.origin}${location.pathname}` url: `${location.origin}${location.pathname}`
}) }
.then((res) => { }).then((res) => {
if (res != null) {
wx.config({ wx.config({
debug: config.wx.debug, debug: config.wx.debug,
jsApiList: ["chooseWXPay"], jsApiList: res.jsApiList || ["chooseWXPay"],
...res appId: res.appId,
timestamp: res.timestamp,
nonceStr: res.nonceStr,
signature: res.signature,
openTagList: res.openTagList
}); });
// 合并配置到mpConfig // 合并配置到mpConfig
assign(this.mpConfig, res); assign(this.mpConfig, res);
}); }
});
} }
} }

View File

@@ -42,3 +42,4 @@ export * from "./store";
export * from "./theme"; export * from "./theme";
export * from "./upload"; export * from "./upload";
export * from "./utils"; export * from "./utils";
export * from "./types";

View File

@@ -1,4 +1,3 @@
import type { Service } from "../types";
import { isDev, ignoreTokens, config } from "@/config"; import { isDev, ignoreTokens, config } from "@/config";
import { locale, t } from "@/locale"; import { locale, t } from "@/locale";
import { isNull, isObject, parse, storage } from "../utils"; import { isNull, isObject, parse, storage } from "../utils";
@@ -43,7 +42,7 @@ const isIgnoreToken = (url: string) => {
* @param options 请求参数 * @param options 请求参数
* @returns Promise<T> * @returns Promise<T>
*/ */
export function request<T = any>(options: RequestOptions): Promise<T> { export function request(options: RequestOptions): Promise<any | null> {
let { url, method = "GET", data = {}, header = {}, timeout = 60000 } = options; let { url, method = "GET", data = {}, header = {}, timeout = 60000 } = options;
const { user } = useStore(); const { user } = useStore();
@@ -84,40 +83,43 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
// 401 无权限 // 401 无权限
if (res.statusCode == 401) { if (res.statusCode == 401) {
user.logout(); user.logout();
return reject({ message: t("无权限") } as Response); reject({ message: t("无权限") } as Response);
} }
// 502 服务异常 // 502 服务异常
if (res.statusCode == 502) { else if (res.statusCode == 502) {
return reject({ reject({
message: t("服务异常") message: t("服务异常")
} as Response); } as Response);
} }
// 404 未找到 // 404 未找到
if (res.statusCode == 404) { else if (res.statusCode == 404) {
return reject({ return reject({
message: `[404] ${url}` message: `[404] ${url}`
} as Response); } as Response);
} }
// 200 正常响应 // 200 正常响应
if (res.statusCode == 200) { else if (res.statusCode == 200) {
if (!isObject(res.data as any)) { if (res.data == null) {
resolve(res.data as T); resolve(null);
return; } else if (!isObject(res.data as any)) {
} resolve(res.data);
} else {
// 解析响应数据
const { code, message, data } = parse<Response>(
res.data ?? { code: 0 }
)!;
// 解析响应数据 switch (code) {
const { code, message, data } = parse<Response>(res.data ?? { code: 0 })!; case 1000:
resolve(data);
switch (code) { break;
case 1000: default:
resolve(data as T); reject({ message, code } as Response);
break; break;
default: }
reject({ message, code } as Response);
break;
} }
} else { } else {
reject({ message: t("服务异常") } as Response); reject({ message: t("服务异常") } as Response);
@@ -178,6 +180,3 @@ export function request<T = any>(options: RequestOptions): Promise<T> {
next(); next();
}); });
} }
// 服务对象(实际会在其他地方赋值)
export const service = {} as Service;

View File

@@ -1,6 +1,5 @@
import { reactive } from "vue"; import { reactive } from "vue";
import { service } from "../service"; import { request } from "../service";
import type { DictKey } from "../types";
import { forInObject, isNull, parse } from "../utils"; import { forInObject, isNull, parse } from "../utils";
// 字典项类型定义 // 字典项类型定义
@@ -40,7 +39,7 @@ export class Dict {
* @param key 字典key * @param key 字典key
* @returns 字典项数组 * @returns 字典项数组
*/ */
get(key: DictKey): DictItem[] { get(key: string): DictItem[] {
return this.find(key)?.list ?? new Array<DictItem>(); return this.find(key)?.list ?? new Array<DictItem>();
} }
@@ -50,7 +49,7 @@ export class Dict {
* @param value 字典项值 * @param value 字典项值
* @returns 字典项或null * @returns 字典项或null
*/ */
getItem(key: DictKey, value: any): DictItem | null { getItem(key: string, value: any): DictItem | null {
const item = this.get(key).find((e) => e.value == value); const item = this.get(key).find((e) => e.value == value);
if (isNull(item)) { if (isNull(item)) {
@@ -66,7 +65,7 @@ export class Dict {
* @param values 字典项值数组 * @param values 字典项值数组
* @returns 字典项数组 * @returns 字典项数组
*/ */
getItems(key: DictKey, values: any[]): DictItem[] { getItems(key: string, values: any[]): DictItem[] {
return values.map((e) => this.getItem(key, e)).filter((e) => !isNull(e)) as DictItem[]; return values.map((e) => this.getItem(key, e)).filter((e) => !isNull(e)) as DictItem[];
} }
@@ -76,7 +75,7 @@ export class Dict {
* @param value 字典项值 * @param value 字典项值
* @returns 字典项label字符串 * @returns 字典项label字符串
*/ */
getItemLabel(key: DictKey, value: any): string { getItemLabel(key: string, value: any): string {
const item = this.getItem(key, value); const item = this.getItem(key, value);
if (isNull(item) || isNull(item?.label)) { if (isNull(item) || isNull(item?.label)) {
@@ -90,8 +89,16 @@ export class Dict {
* 刷新字典数据 * 刷新字典数据
* @param types 可选指定需要刷新的字典key数组 * @param types 可选指定需要刷新的字典key数组
*/ */
async refresh(types?: DictKey[] | null): Promise<void> { async refresh(types?: string[] | null): Promise<void> {
const res = await service.dict.info.data({ types }); const res = await request({
url: "/app/dict/info/data",
method: "POST",
data: { types }
});
if (res == null) {
return;
}
// 遍历返回的字典数据 // 遍历返回的字典数据
forInObject(res, (arr, key) => { forInObject(res, (arr, key) => {
@@ -127,11 +134,3 @@ export class Dict {
// 单例字典对象 // 单例字典对象
export const dict = new Dict(); export const dict = new Dict();
/**
* 获取字典实例
* @returns Dict实例
*/
export function useDict() {
return dict;
}

View File

@@ -1,28 +1,21 @@
import { reactive } from "vue"; import { computed, ref } from "vue";
import type { UserInfoEntity } from "../types"; import { forInObject, isNull, isObject, parse, storage } from "../utils";
import { forInObject, isNull, parse, storage } from "../utils";
import { service } from "../service";
import { router } from "../router"; import { router } from "../router";
import { request } from "../service";
import type { UserInfo } from "@/types";
/**
* Token类型定义
* @property token 访问token
* @property expire token过期时间
* @property refreshToken 刷新token
* @property refreshExpire 刷新token过期时间
*/
export type Token = { export type Token = {
token: string; token: string; // 访问token
expire: number; expire: number; // token过期时间
refreshToken: string; refreshToken: string; // 刷新token
refreshExpire: number; refreshExpire: number; // 刷新token过期时间
}; };
export class User { export class User {
/** /**
* 用户信息,响应式对象属性结构见UserInfoEntity * 用户信息,响应式对象
*/ */
info = reactive<UserInfoEntity>({}); info = ref<UserInfo | null>(null);
/** /**
* 当前token字符串或null * 当前token字符串或null
@@ -40,7 +33,9 @@ export class User {
this.token = token == "" ? null : token; this.token = token == "" ? null : token;
// 初始化用户信息 // 初始化用户信息
this.set(userInfo!); if (userInfo != null && isObject(userInfo)) {
this.set(userInfo);
}
} }
/** /**
@@ -49,10 +44,11 @@ export class User {
*/ */
async get() { async get() {
if (this.token != null) { if (this.token != null) {
await service.user.info await request({
.person({}) url: "/app/user/info/person"
})
.then((res) => { .then((res) => {
if (!isNull(res)) { if (res != null) {
this.set(res); this.set(res);
} }
}) })
@@ -71,13 +67,8 @@ export class User {
return; return;
} }
// 先清空原有信息 // 设置
this.remove(); this.info.value = parse<UserInfo>(data)!;
// 逐项赋值到响应式info对象
forInObject(data, (value, key) => {
this.info[key] = value;
});
// 持久化到本地存储 // 持久化到本地存储
storage.set("userInfo", data, 0); storage.set("userInfo", data, 0);
@@ -87,43 +78,38 @@ export class User {
* 更新用户信息(本地与服务端同步) * 更新用户信息(本地与服务端同步)
* @param data 新的用户信息 * @param data 新的用户信息
*/ */
async update(data: UserInfoEntity) { async update(data: any) {
if (isNull(data) || this.isNull()) { if (isNull(data) || isNull(this.info.value)) {
return; return;
} }
const params = { ...data };
// 本地同步更新 // 本地同步更新
forInObject(params as any, (value, key) => { forInObject(data, (value, key) => {
this.info[key] = value; this.info.value![key] = value;
}); });
// 同步到服务端 // 同步到服务端
await service.user.info.updatePerson(params); await request({
} url: "/app/user/info/updatePerson",
method: "POST",
/** data
* 移除用户信息(仅清空本地响应式对象,不清除本地存储)
*/
remove() {
forInObject({ ...this.info } as any, (_, key) => {
// #ifdef APP
this.info[key] = null;
// #endif
// #ifndef APP
delete this.info[key];
// #endif
}); });
} }
/** /**
* 判断用户信息是否为空以id字段为准 * 移除用户信息
*/
remove() {
this.info.value = null;
storage.remove("userInfo");
}
/**
* 判断用户信息是否为空
* @returns boolean * @returns boolean
*/ */
isNull() { isNull() {
return isNull(this.info["id"]); return this.info.value == null;
} }
/** /**
@@ -164,16 +150,21 @@ export class User {
*/ */
refreshToken(): Promise<string> { refreshToken(): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
service.user.login request({
.refreshToken({ url: "/app/user/login/refreshToken",
method: "POST",
data: {
refreshToken: storage.get("refreshToken") refreshToken: storage.get("refreshToken")
}) }
})
.then((res) => { .then((res) => {
const token = parse<Token>(res); if (res != null) {
const token = parse<Token>(res);
if (token != null) { if (token != null) {
this.setToken(token); this.setToken(token);
resolve(token.token); resolve(token.token);
}
} }
}) })
.catch((err) => { .catch((err) => {
@@ -189,9 +180,6 @@ export class User {
export const user = new User(); export const user = new User();
/** /**
* 获取用户单例实例组合式API用法 * 用户信息,响应式对象
* @returns User
*/ */
export function useUser() { export const userInfo = computed(() => user.info.value);
return user;
}

View File

@@ -1,5 +1,3 @@
export * from "@/.cool/eps";
export type PushAnimationType = export type PushAnimationType =
| "auto" | "auto"
| "none" | "none"

View File

@@ -1,5 +1,5 @@
import { config } from "@/config"; import { config } from "@/config";
import { service } from "../service"; import { request } from "../service";
import { basename, extname, filename, parse, parseObject, pathJoin, uuid } from "../utils"; import { basename, extname, filename, parse, parseObject, pathJoin, uuid } from "../utils";
import { useStore } from "../store"; import { useStore } from "../store";
@@ -57,8 +57,11 @@ export type LocalUploadResponse = {
// 获取上传模式(本地/云端及云类型) // 获取上传模式(本地/云端及云类型)
async function getUploadMode(): Promise<UploadMode> { async function getUploadMode(): Promise<UploadMode> {
const res = await service.base.comm.uploadMode({}); const res = await request({
return parse<UploadMode>(res)!; url: "/app/base/comm/uploadMode"
});
return parse<UploadMode>(res!)!;
} }
/** /**
@@ -199,10 +202,13 @@ export async function uploadFile(
} }
// 获取云上传参数 // 获取云上传参数
service.base.comm request({
.upload(data) url: "/app/base/comm/upload",
method: "POST",
data
})
.then((res) => { .then((res) => {
const d = parse<CloudUploadResponse>(res)!; const d = parse<CloudUploadResponse>(res!)!;
switch (type) { switch (type) {
// 腾讯云COS // 腾讯云COS

View File

@@ -1,6 +1,6 @@
{ {
"name": "cool-unix", "name": "cool-unix",
"version": "8.0.17", "version": "8.0.18",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js", "build-ui": "node ./uni_modules/cool-ui/scripts/generate-types.js",
@@ -15,7 +15,7 @@
"@babel/parser": "^7.27.5", "@babel/parser": "^7.27.5",
"@babel/types": "^7.27.6", "@babel/types": "^7.27.6",
"@cool-vue/ai": "^1.1.6", "@cool-vue/ai": "^1.1.6",
"@cool-vue/vite-plugin": "^8.2.8", "@cool-vue/vite-plugin": "^8.2.9",
"@dcloudio/types": "^3.4.16", "@dcloudio/types": "^3.4.16",
"@types/node": "^24.0.15", "@types/node": "^24.0.15",
"@vue/compiler-sfc": "^3.5.16", "@vue/compiler-sfc": "^3.5.16",

View File

@@ -42,11 +42,11 @@ const data = ref<ClListViewItem[]>([]);
onReady(() => { onReady(() => {
ui.showLoading(); ui.showLoading();
request<UTSJSONObject[]>({ request({
url: "https://unix.cool-js.com/data/pca_flat.json" url: "https://unix.cool-js.com/data/pca_flat.json"
}) })
.then((res) => { .then((res) => {
data.value = useListView(res); data.value = useListView(res as UTSJSONObject[]);
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);

View File

@@ -22,7 +22,7 @@
<view class="flex flex-col justify-center items-center pt-6 pb-3"> <view class="flex flex-col justify-center items-center pt-6 pb-3">
<view class="relative overflow-visible" @tap="toEdit"> <view class="relative overflow-visible" @tap="toEdit">
<cl-avatar <cl-avatar
:src="user.info.avatarUrl" :src="userInfo?.avatarUrl"
:size="150" :size="150"
:pt="{ className: '!rounded-3xl', icon: { size: 60 } }" :pt="{ className: '!rounded-3xl', icon: { size: 60 } }"
> >
@@ -38,9 +38,9 @@
<view class="flex-1 flex flex-col justify-center items-center w-full" @tap="toEdit"> <view class="flex-1 flex flex-col justify-center items-center w-full" @tap="toEdit">
<cl-text :pt="{ className: '!text-xl mt-5 mb-1 font-bold' }">{{ <cl-text :pt="{ className: '!text-xl mt-5 mb-1 font-bold' }">{{
user.info.nickName ?? t("未登录") userInfo?.nickName ?? t("未登录")
}}</cl-text> }}</cl-text>
<cl-text color="info" v-if="!user.isNull()">{{ user.info.phone }}</cl-text> <cl-text color="info" v-if="!user.isNull()">{{ userInfo?.phone }}</cl-text>
</view> </view>
</view> </view>
@@ -242,7 +242,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { router, useStore } from "@/cool"; import { router, userInfo, useStore } from "@/cool";
import { t } from "@/locale"; import { t } from "@/locale";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
import Tabbar from "@/components/tabbar.uvue"; import Tabbar from "@/components/tabbar.uvue";

View File

@@ -73,7 +73,7 @@ import { t } from "@/locale";
import { computed, inject, ref, type PropType } from "vue"; import { computed, inject, ref, type PropType } from "vue";
import type { LoginForm } from "../../types"; import type { LoginForm } from "../../types";
import SmsBtn from "@/components/sms-btn.uvue"; import SmsBtn from "@/components/sms-btn.uvue";
import { isDark, parseClass, service, useRefs, type Response } from "@/cool"; import { isDark, parseClass, request, useRefs, type Response } from "@/cool";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
const props = defineProps({ const props = defineProps({
@@ -112,11 +112,14 @@ async function toLogin() {
loading.value = true; loading.value = true;
await service.user.login await request({
.phone({ url: "/app/user/login/phone",
method: "POST",
data: {
phone, phone,
smsCode smsCode
}) }
})
.then((res) => { .then((res) => {
emit("success", res); emit("success", res);
}) })

View File

@@ -74,7 +74,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { parse, router, service, upload, useStore, useWx, type Response, type Token } from "@/cool"; import {
parse,
request,
router,
upload,
userInfo,
useStore,
useWx,
type Response,
type Token
} from "@/cool";
import { t } from "@/locale"; import { t } from "@/locale";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
import { reactive, ref } from "vue"; import { reactive, ref } from "vue";
@@ -176,8 +186,11 @@ async function miniLogin() {
ui.showLoading(t("登录中")); ui.showLoading(t("登录中"));
await wx.miniLogin().then(async (data) => { await wx.miniLogin().then(async (data) => {
await service.user.login await request({
.mini(data) url: "/app/user/login/mini",
method: "POST",
data
})
.then(async (res) => { .then(async (res) => {
// 设置token // 设置token
user.setToken(parse<Token>(res)!); user.setToken(parse<Token>(res)!);
@@ -186,7 +199,7 @@ async function miniLogin() {
await user.get(); await user.get();
// 是否首次注册,根据业务情况调整判断逻辑 // 是否首次注册,根据业务情况调整判断逻辑
if (user.info.nickName == "微信用户") { if (userInfo.value?.nickName == "微信用户") {
// 打开编辑弹窗 // 打开编辑弹窗
editOpen(); editOpen();
} else { } else {
@@ -202,12 +215,13 @@ async function miniLogin() {
}); });
ui.hideLoading(); ui.hideLoading();
// #endif // #endif
} }
// 微信APP登录 // 微信APP登录
function appLogin() {} function appLogin() {
// 开发中
}
// 微信登录 // 微信登录
async function login() { async function login() {

View File

@@ -21,7 +21,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { router, useStore } from "@/cool"; import { router, userInfo, useStore } from "@/cool";
import { t } from "@/locale"; import { t } from "@/locale";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
import { ref } from "vue"; import { ref } from "vue";
@@ -47,6 +47,6 @@ async function confirm() {
} }
onReady(() => { onReady(() => {
content.value = user.info.description ?? ""; content.value = userInfo.value?.description ?? "";
}); });
</script> </script>

View File

@@ -35,7 +35,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { router, useStore } from "@/cool"; import { router, userInfo, useStore } from "@/cool";
import { t } from "@/locale"; import { t } from "@/locale";
import { useUi } from "@/uni_modules/cool-ui"; import { useUi } from "@/uni_modules/cool-ui";
import { ref } from "vue"; import { ref } from "vue";
@@ -75,6 +75,6 @@ async function confirm() {
// 页面加载时,设置输入框内容 // 页面加载时,设置输入框内容
onReady(() => { onReady(() => {
content.value = user.info.nickName ?? ""; content.value = userInfo.value?.nickName ?? "";
}); });
</script> </script>

View File

@@ -12,7 +12,7 @@
<!-- #endif --> <!-- #endif -->
<cl-avatar <cl-avatar
:src="user.info.avatarUrl" :src="userInfo?.avatarUrl"
:size="150" :size="150"
:pt="{ className: '!rounded-3xl', icon: { size: 60 } }" :pt="{ className: '!rounded-3xl', icon: { size: 60 } }"
@tap="uploadAvatar" @tap="uploadAvatar"
@@ -35,10 +35,10 @@
justify="start" justify="start"
@tap="router.to('/pages/user/edit-name')" @tap="router.to('/pages/user/edit-name')"
> >
<cl-text>{{ user.info.nickName }}</cl-text> <cl-text>{{ userInfo?.nickName }}</cl-text>
</cl-list-item> </cl-list-item>
<cl-list-item label="手机号" hoverable justify="start"> <cl-list-item label="手机号" hoverable justify="start">
<cl-text>{{ user.info.phone }}</cl-text> <cl-text>{{ userInfo?.phone }}</cl-text>
</cl-list-item> </cl-list-item>
</cl-list> </cl-list>
@@ -50,10 +50,10 @@
justify="start" justify="start"
@tap="router.to('/pages/user/edit-description')" @tap="router.to('/pages/user/edit-description')"
> >
<cl-text color="info" v-if="user.info.description == null">{{ <cl-text color="info" v-if="userInfo?.description == null">{{
t("介绍一下自己") t("介绍一下自己")
}}</cl-text> }}</cl-text>
<cl-text ellipsis v-else>{{ user.info.description }}</cl-text> <cl-text ellipsis v-else>{{ userInfo?.description }}</cl-text>
</cl-list-item> </cl-list-item>
</cl-list> </cl-list>
@@ -76,8 +76,8 @@
justify="start" justify="start"
@tap="open('birthday')" @tap="open('birthday')"
> >
<cl-text>{{ user.info.birthday }}</cl-text> <cl-text>{{ userInfo?.birthday }}</cl-text>
<cl-text color="info" v-if="user.info.birthday == null">{{ <cl-text color="info" v-if="userInfo?.birthday == null">{{
t("选择生日") t("选择生日")
}}</cl-text> }}</cl-text>
</cl-list-item> </cl-list-item>
@@ -98,7 +98,7 @@
<cl-select <cl-select
:title="t('选择性别')" :title="t('选择性别')"
:model-value="user.info.gender" :model-value="userInfo?.gender"
:ref="refs.set('gender')" :ref="refs.set('gender')"
:options="genderOptions" :options="genderOptions"
:show-trigger="false" :show-trigger="false"
@@ -107,7 +107,7 @@
<cl-select-date <cl-select-date
:title="t('选择生日')" :title="t('选择生日')"
:model-value="user.info.birthday" :model-value="userInfo?.birthday"
:ref="refs.set('birthday')" :ref="refs.set('birthday')"
type="date" type="date"
:end="today" :end="today"
@@ -127,7 +127,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { dayUts, router, upload, useRefs, useStore, type Response } from "@/cool"; import { dayUts, router, upload, useRefs, useStore, type Response, userInfo } from "@/cool";
import { t } from "@/locale"; import { t } from "@/locale";
import { useCascader, useUi, type ClSelectOption } from "@/uni_modules/cool-ui"; import { useCascader, useUi, type ClSelectOption } from "@/uni_modules/cool-ui";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
@@ -158,7 +158,7 @@ const genderOptions = ref<ClSelectOption[]>([
// 性别文本 // 性别文本
const genderText = computed(() => { const genderText = computed(() => {
return [t("保密"), t("男"), t("女")][user.info.gender!]; return [t("保密"), t("男"), t("女")][userInfo.value?.gender!];
}); });
// 性别改变 // 性别改变
@@ -188,7 +188,7 @@ const regionOptions = useCascader(pca);
// 地区文本 // 地区文本
const regionText = computed(() => { const regionText = computed(() => {
return [user.info.province, user.info.city, user.info.district] return [userInfo.value?.province, userInfo.value?.city, userInfo.value?.district]
.filter((e) => e != null) .filter((e) => e != null)
.join(" - "); .join(" - ");
}); });

10
pnpm-lock.yaml generated
View File

@@ -28,8 +28,8 @@ importers:
specifier: ^1.1.6 specifier: ^1.1.6
version: 1.1.6 version: 1.1.6
'@cool-vue/vite-plugin': '@cool-vue/vite-plugin':
specifier: ^8.2.8 specifier: ^8.2.9
version: 8.2.8 version: 8.2.9
'@dcloudio/types': '@dcloudio/types':
specifier: ^3.4.16 specifier: ^3.4.16
version: 3.4.16 version: 3.4.16
@@ -88,8 +88,8 @@ packages:
resolution: {integrity: sha512-+5vEnjuMHhmOlAlozasGMaSkx2TZ5p45nOuLzx88ZVyqO0dMYXUJ5I8eVR5XV7huYCLCw7dYwfVg5B03ngsYwg==} resolution: {integrity: sha512-+5vEnjuMHhmOlAlozasGMaSkx2TZ5p45nOuLzx88ZVyqO0dMYXUJ5I8eVR5XV7huYCLCw7dYwfVg5B03ngsYwg==}
hasBin: true hasBin: true
'@cool-vue/vite-plugin@8.2.8': '@cool-vue/vite-plugin@8.2.9':
resolution: {integrity: sha512-MoiNQt/9Dr8e+P39LIaCEz2Y0OvdDauK9mGseyUCEmyKFRuF5KEmTlDzr2ChW/Z7IQMvXZnj47wiAmyuEzxwLA==} resolution: {integrity: sha512-Dl/yW/JWWJNmChwMj5CFUV4qZRD5axXYZ1dqpuyBWDD1kWsvNY8PaL7VGDos3/8SpUsDYPXCv+yK/Fd32A6o9w==}
'@dcloudio/types@3.4.16': '@dcloudio/types@3.4.16':
resolution: {integrity: sha512-gJIr1OWtePTDDdjtp8Kh72S/ZGLunoSfHiUvRtXhBmAFNkDWuAKFO90hv62k3GYN/st04xUBQNtBfvhu/YHjww==} resolution: {integrity: sha512-gJIr1OWtePTDDdjtp8Kh72S/ZGLunoSfHiUvRtXhBmAFNkDWuAKFO90hv62k3GYN/st04xUBQNtBfvhu/YHjww==}
@@ -1376,7 +1376,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
'@cool-vue/vite-plugin@8.2.8': '@cool-vue/vite-plugin@8.2.9':
dependencies: dependencies:
'@vue/compiler-sfc': 3.5.17 '@vue/compiler-sfc': 3.5.17
axios: 1.10.0 axios: 1.10.0

17
types/index.ts Normal file
View File

@@ -0,0 +1,17 @@
export type UserInfo = {
unionid: string; // 用户唯一id
id: number; // 用户id
nickName: string; // 昵称
avatarUrl?: string; // 头像
phone: string; // 手机号
gender: number; // 性别
status: number; // 状态
description?: string; // 描述
loginType: number; // 登录类型
province?: string; // 省份
city?: string; // 城市
district?: string; // 区县
birthday?: string; // 生日
createTime: string; // 创建时间
updateTime: string; // 更新时间
};

View File

@@ -19,11 +19,7 @@ export default defineConfig({
proxy, proxy,
tailwind: { tailwind: {
enable: true enable: true
}, }
eps: {
dist: ".cool"
},
clean: true // 是否纯净版
}) })
], ],