Compare commits
89
Commits
71136a03a6
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bafde6e744 | ||
|
|
c7dbbfda16 | ||
|
|
fd78b504a6 | ||
|
|
a26fc1a4a7 | ||
|
|
ab812a2bc6 | ||
|
|
5d31c3658b | ||
|
|
3140db227c | ||
|
|
5f9a346960 | ||
|
|
7180e176eb | ||
|
|
e3a852cb43 | ||
|
|
0a51901807 | ||
|
|
8a879df4b4 | ||
|
|
18c7f7386d | ||
|
|
b5cc11ddd3 | ||
|
|
4a22470f38 | ||
|
|
6cdd8b90db | ||
|
|
cbc427e41c | ||
|
|
45a9478790 | ||
|
|
c6ce198c31 | ||
|
|
f4fe516224 | ||
|
|
80772749b2 | ||
|
|
0fa310e422 | ||
|
|
761a8fdaa4 | ||
|
|
ca69dfbe4b | ||
|
|
4042df6762 | ||
|
|
4e3a30b863 | ||
|
|
2831de027c | ||
|
|
08e3ba22c5 | ||
|
|
40f5ddf4a5 | ||
|
|
1fa822ed72 | ||
|
|
89848ba321 | ||
|
|
7fb1200528 | ||
|
|
b833a00d65 | ||
|
|
e8e9c84cdf | ||
|
|
1e99b3a082 | ||
|
|
efcc7d9603 | ||
|
|
54f8132cee | ||
|
|
ddbfac11c3 | ||
|
|
1de18aa228 | ||
|
|
799471090f | ||
|
|
ae9a961a42 | ||
|
|
db9ca707ae | ||
|
|
a7b2a673a9 | ||
|
|
d06ee397cf | ||
|
|
034744959f | ||
|
|
cf6df28e8c | ||
|
|
00d0ec8a9b | ||
|
|
56c645a75c | ||
|
|
8025b2abab | ||
|
|
c86aa03f01 | ||
|
|
22104881f1 | ||
|
|
f4c8df1950 | ||
|
|
1785e9309e | ||
|
|
da3659412d | ||
|
|
51367c48c9 | ||
|
|
41079458dc | ||
|
|
60531b339e | ||
|
|
9788e723a2 | ||
|
|
91726b87c5 | ||
|
|
6b37f0899d | ||
|
|
f4b1ef932d | ||
|
|
76e619b85d | ||
|
|
2cfc225b55 | ||
|
|
2cfa4bdc53 | ||
|
|
9e0a5d2512 | ||
|
|
589092ec62 | ||
|
|
1255ce8aa5 | ||
|
|
4dca51b0a3 | ||
|
|
8d9ad1ca51 | ||
|
|
e7cebcb00c | ||
|
|
dcade02e47 | ||
|
|
f7d44b9c27 | ||
|
|
d1a4f610d3 | ||
|
|
6b238c2d33 | ||
|
|
7c46a3487a | ||
|
|
38d13d33ce | ||
|
|
5d2d8cc9ff | ||
|
|
5af6f8c906 | ||
|
|
1e134f236c | ||
|
|
4816054b96 | ||
|
|
ea320f4e54 | ||
|
|
d44cd1516a | ||
|
|
2a1f4a2405 | ||
|
|
2532aa055c | ||
|
|
b16601baa6 | ||
|
|
8b1e9bcb41 | ||
|
|
dd9b2984b2 | ||
|
|
65b2d269c5 | ||
|
|
570e47698c |
@@ -0,0 +1,12 @@
|
||||
|
||||
changed 1 package, and audited 42 packages in 5s
|
||||
|
||||
7 packages are looking for funding
|
||||
run `npm fund` for details
|
||||
|
||||
3 high severity vulnerabilities
|
||||
|
||||
Some issues need review, and may require choosing
|
||||
a different dependency.
|
||||
|
||||
Run `npm audit` for details.
|
||||
@@ -1,481 +1,264 @@
|
||||
<script >
|
||||
import RootStore from "@xkit-yx/im-store-v2";
|
||||
/** esm 版本 */
|
||||
//@ts-ignore
|
||||
// import { V2NIMConst, NIM } from './esmNim.js'
|
||||
/** 常规版本*/
|
||||
import NIM from "nim-web-sdk-ng/dist/v2/NIM_UNIAPP_SDK";
|
||||
import { V2NIMConst } from "nim-web-sdk-ng/dist/esm/nim";
|
||||
|
||||
|
||||
import {
|
||||
customRedirectTo,
|
||||
customReLaunch,
|
||||
customSwitchTab,
|
||||
} from "@/utils/im/customNavigate";
|
||||
import { getMsgContentTipByType } from "@/utils/im/msg";
|
||||
import { STORAGE_KEY } from "@/utils/im/constants";
|
||||
import { isWxApp } from "@/utils/im/index";
|
||||
/** 国际化*/
|
||||
import { setLanguage } from "@/utils/im/i18n";
|
||||
import BASE_URL from "@/utils/config.js"
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
/** 推送插件 */
|
||||
const nimPushPlugin = uni.requireNativePlugin("NIMUniPlugin-PluginModule");
|
||||
/** 音视频通话插件 */
|
||||
const nimCallKit = (uni.$UIKitCallKit =
|
||||
uni.requireNativePlugin("netease-CallKit"));
|
||||
// #endif
|
||||
|
||||
let startByNotificationId = "";
|
||||
|
||||
<script>
|
||||
import version from '@/utils/version.js'
|
||||
export default {
|
||||
onLaunch() {
|
||||
// #ifdef APP-PLUS
|
||||
/** 关闭启动画面,锁定竖屏 */
|
||||
plus.navigator.closeSplashscreen();
|
||||
plus.screen.lockOrientation("portrait-primary");
|
||||
// #endif
|
||||
|
||||
// uni-app客户端获取push客户端标记,代码可以实现在App.vue中
|
||||
uni.getPushClientId({
|
||||
success: (res) => {
|
||||
let push_clientid = res.cid
|
||||
uni.setStorageSync("push_clientid", push_clientid)
|
||||
console.log('客户端推送标识cid:',push_clientid)
|
||||
},
|
||||
fail(err) {
|
||||
console.error("unipush: ", err)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
uni.onPushMessage((res)=>{
|
||||
console.log("收到推送消息:", res)
|
||||
uni.showModal({
|
||||
title: res.data.title,
|
||||
content: res.type,
|
||||
showCancel: false
|
||||
});
|
||||
})
|
||||
|
||||
/** 设置语言 (此处为了方便demo切换语言,将其存到本地,实际需根据业务情况设置)*/
|
||||
setLanguage(
|
||||
uni.getStorageSync("switchToEnglishFlag") == "en" ? "en" : "zh"
|
||||
);
|
||||
/** 已经登录了 不用走初始化逻辑*/
|
||||
globalData: {
|
||||
plAd: true,
|
||||
dotNumber: {},
|
||||
apiHost: "https://dev-app.igandan.com/app",
|
||||
//BASE_URL='https://dev-app.igandan.com/app'
|
||||
},
|
||||
onLaunch(options) {
|
||||
//uni.setStorageSync('apiHost', 'value')
|
||||
console.log("打印options");
|
||||
console.log(options);
|
||||
if (
|
||||
uni?.$UIKitStore?.connectStore?.connectStatus ===
|
||||
V2NIMConst.V2NIMConnectStatus.V2NIM_CONNECT_STATUS_CONNECTED
|
||||
options &&
|
||||
options.referrerInfo.extraData &&
|
||||
options.referrerInfo.extraData.token
|
||||
) {
|
||||
return;
|
||||
uni.setStorageSync(
|
||||
"AUTH_TOKEN_App",
|
||||
options.referrerInfo.extraData.token
|
||||
);
|
||||
uni.setStorageSync("userInfo", options.referrerInfo.extraData.userInfo);
|
||||
if(process.env.UNI_PLATFORM =="mp-weixin"){
|
||||
uni.setStorageSync("app_version",version);
|
||||
}else{
|
||||
let app_version=options.referrerInfo.extraData.app_version?options.referrerInfo.extraData.app_version:version;
|
||||
uni.setStorageSync("app_version",app_version);
|
||||
};
|
||||
|
||||
//getApp({allowDefault: true}).globalData.apiHost = options.referrerInfo.extraData.apiHost;
|
||||
}
|
||||
|
||||
let storage_token='';
|
||||
let storage_accid='';
|
||||
if (process.env.UNI_PLATFORM == "h5") {
|
||||
if (window.location.href.indexOf('dev') > -1) {
|
||||
storage_accid=uni.getStorageSync('AUTH_YX_ACCID_App');
|
||||
storage_token=uni.setStorageSync('AUTH_YX_TOKEN_App');
|
||||
} else {
|
||||
storage_accid=uni.getStorageSync('DEV_AUTH_YX_ACCID_App');
|
||||
storage_token=uni.getStorageSync('DEV_AUTH_YX_TOKEN_App');
|
||||
}
|
||||
} else if(process.env.UNI_PLATFORM == "mp-weixin") {
|
||||
const {
|
||||
envVersion
|
||||
} = uni.getAccountInfoSync().miniProgram;
|
||||
if (envVersion == "release") {
|
||||
storage_accid=uni.getStorageSync('AUTH_YX_ACCID_App');
|
||||
storage_token=uni.setStorageSync('AUTH_YX_TOKEN_App');
|
||||
} else {
|
||||
storage_accid=uni.getStorageSync('DEV_AUTH_YX_ACCID_App');
|
||||
storage_token=uni.getStorageSync('DEV_AUTH_YX_TOKEN_App');
|
||||
}
|
||||
}else{
|
||||
if (BASE_URL.indexOf('dev') == -1) {
|
||||
storage_accid=uni.getStorageSync('DEV_AUTH_YX_ACCID_App');
|
||||
storage_token=uni.getStorageSync('DEV_AUTH_YX_TOKEN_App');
|
||||
|
||||
} else {
|
||||
storage_accid=uni.getStorageSync('AUTH_YX_ACCID_App');
|
||||
storage_token=uni.setStorageSync('AUTH_YX_TOKEN_App');
|
||||
}
|
||||
}
|
||||
const account =storage_accid;
|
||||
const token = storage_token;
|
||||
const imOptions = {
|
||||
appkey: "885dea390870814acf3ba8558c717572", // 请填写你的appkey
|
||||
account: account,//"9ufkll2xo57km6224xe", // 请填写你的account
|
||||
token: token//"4918605da57e573cff93209df56f351d", // 请填写你的token
|
||||
};
|
||||
if (imOptions) {
|
||||
this.initNim(imOptions);
|
||||
} else {
|
||||
/** 未登录 跳转登录页 */
|
||||
// customRedirectTo({
|
||||
// url: isWxApp ? "/pages/index/index" : "/pages/Login/index",
|
||||
// });
|
||||
if (
|
||||
options &&
|
||||
options.referrerInfo.extraData &&
|
||||
options.referrerInfo.extraData.targetPath
|
||||
) {
|
||||
let src=options.referrerInfo.extraData.targetPath
|
||||
|
||||
if(src.indexOf('downLoadVideo') > -1 ){
|
||||
uni.navigateTo({
|
||||
url: src+'?from=mine',
|
||||
});
|
||||
}else{
|
||||
uni.navigateTo({
|
||||
url: src,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log("app传递登录信息onLaunch-------------------");
|
||||
try {
|
||||
// #ifdef APP
|
||||
uni.onNativeEventReceive((event, data) => {
|
||||
console.log("event", event);
|
||||
console.log("data", data);
|
||||
if (event.indexOf("clearToken") > -1) {
|
||||
uni.setStorageSync("AUTH_TOKEN_App", "");
|
||||
plus.runtime.quit();
|
||||
}
|
||||
if(event.indexOf("goPage") > -1){
|
||||
if(data.indexOf('downLoadVideo') > -1){
|
||||
uni.navigateTo({
|
||||
url: data+'?from=mine'
|
||||
});
|
||||
}else{
|
||||
uni.navigateTo({
|
||||
url: data,
|
||||
});
|
||||
}
|
||||
}
|
||||
if(event.indexOf('paySuccess') > -1){
|
||||
console.log('app.vue监听到成功支付');
|
||||
if(data.type=='GandanFile'){
|
||||
uni.$emit('paySuccess',{
|
||||
type:'GandanFile',
|
||||
});
|
||||
}else if(data.type=='BuyPoint'){
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
} catch (error) {
|
||||
console.log("app传递登录信息error-------------------");
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
// #ifdef APP-PLUS
|
||||
uni?.$UIKitNIM?.V2NIMSettingService?.setAppBackground(false);
|
||||
try {
|
||||
// #ifdef APP
|
||||
let checkTokenCallBackFlag = false;
|
||||
console.log("执行onshow");
|
||||
|
||||
// 点击通知栏推送监听
|
||||
nimPushPlugin.addOpenNotificationListener((res) => {
|
||||
if (typeof res == "object" && res?.sessionId && res?.sessionType) {
|
||||
// 当前登录账号id 具体获取根据您的业务逻辑调整
|
||||
const imOptions = uni.getStorageSync(STORAGE_KEY);
|
||||
// 会话类型
|
||||
const type = res?.sessionType;
|
||||
// 拼装会话ID
|
||||
startByNotificationId = `${imOptions.account}|${type}|${res?.sessionId}`;
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
onHide() {
|
||||
// #ifdef APP-PLUS
|
||||
uni?.$UIKitNIM?.V2NIMSettingService?.setAppBackground(true);
|
||||
// #endif
|
||||
|
||||
// 重置推送 startByNotificationId
|
||||
startByNotificationId = "";
|
||||
},
|
||||
methods: {
|
||||
initNim(opts) {
|
||||
/** 保存登录信息 demo 层逻辑 具体根据您的业务调整*/
|
||||
uni.setStorage({
|
||||
key: STORAGE_KEY,
|
||||
data: opts,
|
||||
});
|
||||
|
||||
/** 是否开启云端会话(此处为了方便demo切换云端/本地会话,将其存到本地,实际需根据业务情况设置)*/
|
||||
const enableV2CloudConversation =
|
||||
uni.getStorageSync("enableV2CloudConversation") === "on";
|
||||
|
||||
/** 初始化 nim sdk */
|
||||
//@ts-ignore
|
||||
const nim = (uni.$UIKitNIM = NIM.getInstance(
|
||||
uni.sendNativeEvent(
|
||||
"checkToken",
|
||||
{
|
||||
appkey: opts.appkey,
|
||||
needReconnect: true,
|
||||
debugLevel: "debug",
|
||||
apiVersion: "v2",
|
||||
enableV2CloudConversation: enableV2CloudConversation,
|
||||
msg: "checkToken",
|
||||
},
|
||||
{
|
||||
V2NIMLoginServiceConfig: {
|
||||
/**
|
||||
* 微信小程序需要使用单独的lbsUrls和linkUrl
|
||||
*/
|
||||
lbsUrls: isWxApp
|
||||
? ["https://lbs.netease.im/lbs/wxwebconf.jsp"]
|
||||
: ["https://lbs.netease.im/lbs/webconf.jsp"],
|
||||
linkUrl: isWxApp ? "wlnimsc0.netease.im" : "weblink.netease.im",
|
||||
/**
|
||||
* 使用固定设备ID,
|
||||
*/
|
||||
isFixedDeviceId: true,
|
||||
},
|
||||
}
|
||||
));
|
||||
|
||||
/** 初始化 im store */
|
||||
// @ts-ignore
|
||||
const store = (uni.$UIKitStore = new RootStore(
|
||||
// @ts-ignore
|
||||
nim,
|
||||
{
|
||||
// 添加好友是否需要验证
|
||||
addFriendNeedVerify: true,
|
||||
// 是否需要显示 p2p 消息、p2p会话列表消息已读未读,默认 false
|
||||
p2pMsgReceiptVisible: true,
|
||||
// 是否需要显示群组消息已读未读,默认 false
|
||||
teamMsgReceiptVisible: true,
|
||||
// 是否显示在线离线
|
||||
loginStateVisible: true,
|
||||
// 群组被邀请模式,默认需要验证
|
||||
teamAgreeMode:
|
||||
V2NIMConst.V2NIMTeamAgreeMode.V2NIM_TEAM_AGREE_MODE_NO_AUTH,
|
||||
// 发送消息前回调, 可对消息体进行修改,添加自定义参数
|
||||
// @ts-ignore
|
||||
sendMsgBefore: async (options) => {
|
||||
const pushContent = getMsgContentTipByType({
|
||||
text: options.msg.text,
|
||||
messageType: options.msg.messageType,
|
||||
});
|
||||
const yxAitMsg = options.serverExtension
|
||||
? options.serverExtension.yxAitMsg
|
||||
: { forcePushIDsList: "[]", needForcePush: false };
|
||||
|
||||
// 如果是 at 消息,需要走离线强推
|
||||
// @ts-ignore
|
||||
const { forcePushIDsList, needForcePush } = yxAitMsg
|
||||
? // @ts-ignore
|
||||
store.msgStore._formatExtAitToPushInfo(
|
||||
yxAitMsg,
|
||||
options.msg.text
|
||||
)
|
||||
: { forcePushIDsList: "[]", needForcePush: false };
|
||||
|
||||
const { conversationId } = options;
|
||||
const conversationType =
|
||||
nim.V2NIMConversationIdUtil.parseConversationType(conversationId);
|
||||
const targetId =
|
||||
nim.V2NIMConversationIdUtil.parseConversationTargetId(
|
||||
conversationId
|
||||
);
|
||||
|
||||
// 设置离线强推,厂商相关推送在此处配置
|
||||
// 具体参考文档 https://doc.yunxin.163.com/messaging2/guide/zc4MTg5MDY?platform=client#%E7%AC%AC%E4%B8%80%E6%AD%A5%E4%B8%8A%E4%BC%A0%E6%8E%A8%E9%80%81%E8%AF%81%E4%B9%A6
|
||||
const pushPayload = JSON.stringify({
|
||||
pushTitle: "", // 必填,推送消息标题
|
||||
notify_effect: "2", //可选项,预定义通知栏消息的点击行为。1:通知栏点击后打开app的Launcher Activity,2:通知栏点击后打开app的任一Activity(开发者还需要传入intent_uri),3:通知栏点击后打开网页(开发者还需要传入web_uri)
|
||||
intent_uri:
|
||||
"intent:#Intent;action=com.netease.nimlib.uniapp.push.NotificationClickActivity;component=com.netease.nim.demo/com.netease.nimlib.uniapp.push.NotificationClickActivity;launchFlags=0x04000000;i.sessionType=0;S.sessionId=cs1;end", //可选项,打开当前app的任一组件。
|
||||
hwField: {
|
||||
click_action: {
|
||||
//必填,消息点击行为
|
||||
type: 1, //必填,消息点击行为类型,取值如下:1:打开应用自定义页面 2:点击后打开特定URL 3:点击后打开应用
|
||||
// 自定义页面中intent的实现,请参见指定intent参数。当type为1时,字段intent和action至少二选一。scheme方式和指定activity方式都可以
|
||||
intent:
|
||||
"intent:#Intent;action=com.netease.nimlib.uniapp.push.NotificationClickActivity;component=com.netease.nim.demo/com.netease.nimlib.uniapp.push.NotificationClickActivity;launchFlags=0x04000000;i.sessionType=0;S.sessionId=cs1;end",
|
||||
},
|
||||
androidConfig: {
|
||||
category: "IM", //可选项,标识消息类型,用于标识高优先级透传场景,详见官方文档 AndroidConfig.category
|
||||
},
|
||||
},
|
||||
honorField: {
|
||||
notification: {
|
||||
// AndroidNotification
|
||||
clickAction: {
|
||||
//必填,消息点击行为
|
||||
type: 1, //必填,消息点击行为类型,取值如下:1:打开应用自定义页面 2:点击后打开特定URL 3:点击后打开应用
|
||||
//自定义页面中intent的实现,请参见指定intent参数。当type为1时,字段intent和action至少二选一。
|
||||
intent: "",
|
||||
},
|
||||
importance: "NORMAL", //可选项,Android通知消息分类,决定用户设备消息通知行为,取值如下:LOW:资讯营销类消息 NORMAL:服务与通讯类消息
|
||||
},
|
||||
},
|
||||
vivoField: {
|
||||
skipType: "4", //必填,点击跳转类型 1:打开APP首页 2:打开链接 3:自定义 4:打开app内指定页面,默认为1
|
||||
skipContent: "",
|
||||
classification: "1", //可选项,消息类型 0:运营类消息,1:系统类消息。默认为0
|
||||
category: "IM", // 可选项,二级分类
|
||||
},
|
||||
oppoField: {
|
||||
channel_id: "", //可选项,指定下发的通道ID
|
||||
category: "IM", //可选项,通道类别名
|
||||
notify_level: 2, //通知栏消息提醒等级,1-通知栏;2-通知栏+锁屏;16-通知栏+锁屏+横幅+震动+铃声
|
||||
click_action_type: "1", //点击通知栏后触发的动作类型。0(默认0.启动应用;1.跳转指定应用内页(action标签名);2.跳转网页;4.跳转指定应用内页(全路径类名);5.跳转Intent scheme URL: "",
|
||||
click_action_activity: "",
|
||||
action_parameters: "",
|
||||
},
|
||||
fcmFieldV1: {
|
||||
message: {
|
||||
android: {
|
||||
priority: "",
|
||||
data: {
|
||||
sessionType: "0",
|
||||
sessionId: "cs1",
|
||||
(ret) => {
|
||||
checkTokenCallBackFlag = true;
|
||||
console.log("check回调");
|
||||
console.log(ret);
|
||||
if (ret.code == 0) {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
showCancel: false,
|
||||
content: "您已退出登录!",
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
uni.sendNativeEvent(
|
||||
"goTabbarPage",
|
||||
{
|
||||
msg: "home",
|
||||
},
|
||||
notification: {
|
||||
click_action: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// IOS apns
|
||||
sessionId:
|
||||
conversationType == 1
|
||||
? uni.$UIKitStore.userStore.myUserInfo.accountId
|
||||
: targetId,
|
||||
sessionType: conversationType,
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
const pushConfig = {
|
||||
pushEnabled: true,
|
||||
pushNickEnabled: true,
|
||||
forcePush: needForcePush,
|
||||
forcePushContent: pushContent,
|
||||
forcePushAccountIds: forcePushIDsList,
|
||||
pushPayload,
|
||||
pushContent,
|
||||
};
|
||||
|
||||
return { ...options, pushConfig };
|
||||
},
|
||||
},
|
||||
"UniApp"
|
||||
));
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
/** 注册推送 实际根据您在推送厂商申请的证书进行配置,具体参考文档 https://doc.yunxin.163.com/messaging2/guide/zc4MTg5MDY?platform=client#%E7%AC%AC%E4%B8%80%E6%AD%A5%E4%B8%8A%E4%BC%A0%E6%8E%A8%E9%80%81%E8%AF%81%E4%B9%A6
|
||||
*/
|
||||
nim.V2NIMSettingService.setOfflinePushConfig(nimPushPlugin, {
|
||||
// miPush: {
|
||||
// appId: "",
|
||||
// appKey: "",
|
||||
// certificateName: "",
|
||||
// },
|
||||
// hwPush: {
|
||||
// appId: "",
|
||||
// certificateName: "",
|
||||
// },
|
||||
// oppoPush: {
|
||||
// appId: "",
|
||||
// appKey: "",
|
||||
// certificateName: "",
|
||||
// secret: "",
|
||||
// },
|
||||
// vivoPush: {
|
||||
// appId: "",
|
||||
// appKey: "",
|
||||
// certificateName: "",
|
||||
// },
|
||||
// fcmPush: {
|
||||
// certificateName: "",
|
||||
// },
|
||||
// mzPush: {
|
||||
// appId: "",
|
||||
// appKey: "",
|
||||
// certificateName: "",
|
||||
// },
|
||||
// apns: {
|
||||
// certificateName: "",
|
||||
// },
|
||||
});
|
||||
// #endif
|
||||
|
||||
/** nim sdk 登录 */
|
||||
nim.V2NIMLoginService.login(opts.account, opts.token).then(async () => {
|
||||
console.log("登录成功");
|
||||
nim.V2NIMLoginService.on('onKickedOffline', (res) => {
|
||||
console.log("被踢下线", res);
|
||||
});
|
||||
// #ifdef APP-PLUS
|
||||
/** 初始化音视频通话插件*/
|
||||
nimCallKit.initConfig(
|
||||
{
|
||||
appKey: opts.appkey, // 请填写你的appkey
|
||||
account: opts.account, // 请填写你的account
|
||||
token: opts.token, // 请填写你的token
|
||||
apnsCername: "",
|
||||
pkCername: "",
|
||||
},
|
||||
(ret) => {
|
||||
if (ret.code != 200) {
|
||||
// callkit init失败
|
||||
} else {
|
||||
|
||||
nimCallKit.login(
|
||||
{
|
||||
account: opts.account,
|
||||
token: opts.token,
|
||||
},
|
||||
function (ret) {
|
||||
if (ret.code != 200) {
|
||||
// 登录失败
|
||||
} else {
|
||||
// 登录成功
|
||||
|
||||
}
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
}
|
||||
);
|
||||
plus.runtime.quit();
|
||||
} else if (res.cancel) {
|
||||
console.log("用户点击取消");
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// #endif
|
||||
// 判断时手动点击唤起 还是 点击推送通知栏唤起,点击通知栏唤起直接跳转到聊天页面
|
||||
if (!startByNotificationId) {
|
||||
// customSwitchTab({
|
||||
// url: "/pages/Conversation/index",
|
||||
// });
|
||||
} else {
|
||||
if (startByNotificationId) {
|
||||
await uni.$UIKitStore.uiStore.selectConversation(
|
||||
startByNotificationId
|
||||
);
|
||||
|
||||
uni.navigateTo({
|
||||
url: `/pages/Chat/index?conversationId=${startByNotificationId}`,
|
||||
},
|
||||
});
|
||||
startByNotificationId = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
uni.removeStorageSync(STORAGE_KEY);
|
||||
try {
|
||||
nimCallKit.logout({}, (ret) => {
|
||||
if (ret.code != 200) {
|
||||
console.log("音视频通话插件退出失败");
|
||||
} else {
|
||||
console.log("音视频通话插件退出成功");
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("音视频通话插件退出失败", error);
|
||||
}
|
||||
// 退出登录
|
||||
uni.$UIKitNIM.V2NIMLoginService.logout().then((res) => {
|
||||
console.log("退出登录", res);
|
||||
uni.$UIKitStore.destroy();
|
||||
customReLaunch({
|
||||
url: "/pages/Login/index",
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
// setTimeout(function(){
|
||||
// console.log("执行 setTimeout")
|
||||
// if(!checkTokenCallBackFlag){
|
||||
// uni.showModal({
|
||||
// title: '提示',
|
||||
// showCancel: false,
|
||||
// content: '您已退出登录',
|
||||
// success: function (res) {
|
||||
// if (res.confirm) {
|
||||
// uni.sendNativeEvent('goTabbarPage', {
|
||||
// msg: 'home'
|
||||
// }, ret => {
|
||||
// console.log(ret);
|
||||
// })
|
||||
// } else if (res.cancel) {
|
||||
// console.log('用户点击取消');
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }, 1000)
|
||||
|
||||
|
||||
let main = plus.android.runtimeMainActivity();
|
||||
//为了防止快速点按返回键导致程序退出重写quit方法改为隐藏至后台
|
||||
plus.runtime.quit = function () {
|
||||
main.moveTaskToBack(false);
|
||||
};
|
||||
//重写toast方法如果内容为 ‘再按一次退出应用’ 就隐藏应用,其他正常toast
|
||||
plus.nativeUI.toast = function (str) {
|
||||
if (str == "再按一次退出应用") {
|
||||
main.moveTaskToBack(false);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: str,
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// uni.onNativeEventReceive((event, data) => {
|
||||
// console.log("app传递登录信息onshow-------------------");
|
||||
// console.log("event", event);
|
||||
// console.log("data", data);
|
||||
// if (event == "loginInfo") {
|
||||
// uni.setStorageSync("DEV_AUTH_YX_TOKEN_App", data.token);
|
||||
// uni.setStorageSync("userInfo", data.userInfo);
|
||||
// }else if(event == "showRedDot"){
|
||||
// console.log("showRedDot");
|
||||
// console.log(data);
|
||||
// getApp().globalData.dotNumber=data;
|
||||
// }
|
||||
// });
|
||||
// #endif
|
||||
} catch (error) {
|
||||
console.log("error");
|
||||
console.log(error);
|
||||
}
|
||||
},
|
||||
onHide() {},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
/*每个页面公共css */
|
||||
@import '@/uni_modules/uni-scss/index.scss';
|
||||
/* #ifndef APP-NVUE */
|
||||
@import '@/static/customicons.css';
|
||||
// 设置整个项目的背景色
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
<template>
|
||||
<GlobalDialog />
|
||||
</template>
|
||||
|
||||
/* #endif */
|
||||
.uni-nav-bar-text{
|
||||
font-weight: bold;
|
||||
font-size: 34rpx!important;
|
||||
}
|
||||
.example-info {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
padding: 10px;
|
||||
}
|
||||
.twoline{
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.oneline{
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.uni-navbar .uniui-left{
|
||||
font-weight: bold;
|
||||
font-size: 50rpx!important;
|
||||
}
|
||||
::-webkit-scrollbar { display: none; }
|
||||
.nav-right{
|
||||
margin-top: -20px;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
/*每个页面公共css */
|
||||
@import "@/uni_modules/uni-scss/index.scss";
|
||||
/* #ifndef APP-NVUE */
|
||||
@import "@/static/customicons.css";
|
||||
|
||||
// 设置整个项目的背景色
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.uni-navbar__header-btns-right {
|
||||
min-width: 120rpx;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
.uni-nav-bar-text {
|
||||
|
||||
font-size: 40rpx !important;
|
||||
}
|
||||
|
||||
.example-info {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.twoline {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.oneline {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.uni-navbar .uniui-left {
|
||||
font-weight: bold;
|
||||
font-size: 50rpx !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.status_bar {
|
||||
height: var(--status-bar-height);
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.navbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: calc(var(--status-bar-height) + 44px);
|
||||
z-index: 9999;
|
||||
}
|
||||
.share-content .share-item:last-child{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"prompt": "template"
|
||||
"prompt" : "none"
|
||||
}
|
||||
|
||||
+167
-6
@@ -1,4 +1,5 @@
|
||||
import {request} from '@/utils/request.js'
|
||||
|
||||
const api = {
|
||||
|
||||
expertWxLogin(jscode){
|
||||
@@ -119,11 +120,11 @@ const api = {
|
||||
},
|
||||
// 积分支付列表
|
||||
bonusPointsPayList(data) {
|
||||
return request('/expertAPI/bonusPointsPayList', data, 'post', false);
|
||||
return request('/expertAPI/bonusPointsPayList', data, 'post', true);
|
||||
},
|
||||
// 积分列表
|
||||
bonusPointsList(data) {
|
||||
return request('/expertAPI/bonusPointsList', data, 'post', false);
|
||||
return request('/expertAPI/bonusPointsList', data, 'post', true);
|
||||
},
|
||||
|
||||
getWelfarePage(data) {
|
||||
@@ -335,6 +336,9 @@ const api = {
|
||||
applyList(data){
|
||||
return request('/expertAPI/applyList', data, 'post', false);
|
||||
},
|
||||
patientListByGBKPage(data){
|
||||
return request('/expertAPI/patientListByGBKPage', data, 'post', false);
|
||||
},
|
||||
patientListByGBK(data){
|
||||
return request('/expertAPI/patientListByGBK', data, 'post', false);
|
||||
},
|
||||
@@ -411,6 +415,10 @@ const api = {
|
||||
bankCardList(data){
|
||||
return request('/expertPay/bankCardList', data, 'post', false);
|
||||
},
|
||||
|
||||
deleteBankCard(data){
|
||||
return request('/expertPay/deleteBankCard', data, 'post', false);
|
||||
},
|
||||
getIncomeTax(data){
|
||||
return request('/expertPay/getIncomeTax', data, 'post', false);
|
||||
},
|
||||
@@ -446,10 +454,10 @@ const api = {
|
||||
return request('/expertAPI/consultListHis', data, 'post', false);
|
||||
},
|
||||
listNewInterrogation(data){
|
||||
return request('/expertAPI/listNewInterrogation', data, 'post', false);
|
||||
return request('/expertAPI/listNewInterrogation', data, 'post', true);
|
||||
},
|
||||
listMyAnsweredInterrogation(data){
|
||||
return request('/expertAPI/listMyAnsweredInterrogation', data, 'post', false);
|
||||
return request('/expertAPI/listMyAnsweredInterrogation', data, 'post', true);
|
||||
},
|
||||
getInterrogation(data){
|
||||
return request('/expertAPI/getInterrogation', data, 'post', false);
|
||||
@@ -458,10 +466,10 @@ const api = {
|
||||
return request('/expertAPI/InterrogationPatientInfo', data, 'post', false);
|
||||
},
|
||||
updateInterrogationAnswer(data){
|
||||
return request('/expertAPI/updateInterrogationAnswer', data, 'post', false);
|
||||
return request('/expertAPI/updateInterrogationAnswerU', data, 'post', true);
|
||||
},
|
||||
addInterrogationAnswer(data){
|
||||
return request('/expertAPI/addInterrogationAnswer', data, 'post', false);
|
||||
return request('/expertAPI/addInterrogationAnswerU', data, 'post', true);
|
||||
},
|
||||
videoDetail(data){
|
||||
return request('/expertAPI/videoDetail', data, 'post', false);
|
||||
@@ -571,6 +579,159 @@ const api = {
|
||||
deleteConditionRecord(data){
|
||||
return request('/expertAPI/delConditionRecord', data, 'post', false);
|
||||
},
|
||||
consultDetail(data){
|
||||
return request('/expertAPI/consultDetail', data, 'post', false);
|
||||
},
|
||||
isConsultIng(data){
|
||||
return request('/expertAPI/isConsultIng', data, 'post', false);
|
||||
},
|
||||
resConsult(data){
|
||||
return request('/expertAPI/resConsult', data, 'post', false);
|
||||
},
|
||||
countConsult(data){
|
||||
return request('/expertAPI/countConsult', data, 'post', false);
|
||||
},
|
||||
closeConsult(data){
|
||||
return request('/expertAPI/closeConsult', data, 'post', false);
|
||||
},
|
||||
checkUser(data){
|
||||
return request('/expertAPI/checkUser', data, 'post', false);
|
||||
},
|
||||
ganDanFileDetials(data){
|
||||
return request('/expertAPI/ganDanFileDetials', data, 'post', false);
|
||||
},
|
||||
createGanDanFileOrder(data){
|
||||
return request('/expertPay/createGanDanFileOrder', data, 'post', false);
|
||||
},
|
||||
getOrderStatus(data){
|
||||
return request('/expertPay/getOrderStatus', data, 'post', false);
|
||||
},
|
||||
|
||||
getOrderStatus(data){
|
||||
return request('/expertPay/getOrderStatus', data, 'post', false);
|
||||
},
|
||||
getBalance(data){
|
||||
return request('/expertPay/getBalance', data, 'post', false);
|
||||
},
|
||||
payGanDanFile(data){
|
||||
return request('/expertPay/payGanDanFileOrder', data, 'post', false);
|
||||
},
|
||||
// discollection(data){
|
||||
// return request('/expert/discollection', data, 'post', false);
|
||||
// },
|
||||
// collection(data){
|
||||
// return request('/expert/collection', data, 'post', false);
|
||||
// },
|
||||
getTypeUuidByName(data){
|
||||
return request('/expertAPI/getTypeUuidByName', data, 'post', false);
|
||||
},
|
||||
videoByTypeNew(data){
|
||||
return request('/expertAPI/videoByTypeNew', data, 'post', false);
|
||||
},
|
||||
meetingHistoryList(data){
|
||||
return request('/expertAPI/meetingHistoryList', data, 'post', false);
|
||||
},
|
||||
|
||||
// 扫码登录相关API
|
||||
// 确认扫码登录
|
||||
confirmScanLogin(data){
|
||||
return request('/expertAPI/confirmScanLogin', data, 'post', false);
|
||||
},
|
||||
|
||||
// 取消扫码登录
|
||||
cancelScanLogin(data){
|
||||
return request('/expertAPI/cancelScanLogin', data, 'post', false);
|
||||
},
|
||||
|
||||
// 获取扫码登录状态
|
||||
getScanLoginStatus(data){
|
||||
return request('/expertAPI/getScanLoginStatus', data, 'post', false);
|
||||
},
|
||||
gethonorDetail(data){
|
||||
return request('/expertAPI/gethonorDetail', data, 'post', false);
|
||||
},
|
||||
checkVersion(data){
|
||||
return request('/expertAPI/checkVersion', data, 'post', false);
|
||||
},
|
||||
getIsAccount(data){
|
||||
return request('/expertAPI/getIsAccount', data, 'post', false);
|
||||
},
|
||||
patientVideoByJingHuaNew(data){
|
||||
return request('/expertAPI/patientVideoByJingHuaNew', data, 'post', false);
|
||||
},
|
||||
useWelfareNum(data){
|
||||
return request('/expertAPI/useWelfareNum', data, 'post', false);
|
||||
},
|
||||
deleteComment(data){
|
||||
return request('/expertAPI/deleteComment', data, 'post', false);
|
||||
},
|
||||
downloadGanDanFile(data){
|
||||
return request('/expertAPI/downloadGanDanFile', data, 'post', false,'application/json',{},'arraybuffer');
|
||||
},
|
||||
downloadGanDanFileV2(data){
|
||||
return request('/expertAPI/downloadGanDanFileV2', data, 'post', false);
|
||||
},
|
||||
feedBack(data){
|
||||
return request('/expertAPI/addFeedBack', data, 'post', false);
|
||||
},
|
||||
getPointUnitPrice(data){
|
||||
return request('/expertAPI/getPointUnitPrice', data, 'post', false);
|
||||
},
|
||||
welfareList(data){
|
||||
return request('/expertAPI/welfareList', data, 'post', false);
|
||||
},
|
||||
|
||||
getUGoods(data){
|
||||
return request('/expertAPI/getGoodsDetailU', data, 'post', false);
|
||||
},
|
||||
createGoodsOrder(data){
|
||||
return request('/expertAPI/createGoodsOrder', data, 'post', false);
|
||||
},
|
||||
useWelfareNum(data){
|
||||
return request('/expertAPI/useWelfareNum', data, 'post', false);
|
||||
},
|
||||
createBointsOrder(data){
|
||||
return request('/expertPay/createBointsOrder', data, 'post', false);
|
||||
},
|
||||
receiveWelfare(data){
|
||||
return request('/expertAPI/receiveWelfare', data, 'post', false);
|
||||
},
|
||||
getKePuCollection(data){
|
||||
return request('/expertAPI/getKePuCollection', data, 'post', false);
|
||||
},
|
||||
getRead(data){
|
||||
return request('/expertAPI/read', data, 'post', false);
|
||||
},
|
||||
getOutRead(data){
|
||||
return request('/expertAPI/outread', data, 'post', false);
|
||||
},
|
||||
getAgree(data){
|
||||
return request('/expertAPI/agree', data, 'post', false);
|
||||
},
|
||||
getDisagree(data){
|
||||
return request('/expertAPI/disagree', data, 'post', false);
|
||||
},
|
||||
getCollect(data){
|
||||
return request('/expertAPI/collection', data, 'post', false);
|
||||
},
|
||||
getDiscollect(data){
|
||||
return request('/expertAPI/discollection', data, 'post', false);
|
||||
},
|
||||
getGanDanFileOrder(data){
|
||||
return request('/expertPay/getGanDanFileOrder', data, 'post', false);
|
||||
},
|
||||
publishOutPatient(data){
|
||||
return request('/expertAPI/addGroupSendMsg4YunXin', data, 'post', false);
|
||||
},
|
||||
polularScienceArticleListIndexNew(data){
|
||||
return request('/expertAPI/polularScienceArticleListIndexNew', data, 'post', false);
|
||||
},
|
||||
getNewsDetail(data){
|
||||
return request('/expertAPI/newsDetial', data, 'post', false);
|
||||
},
|
||||
|
||||
//https://dev-app.igandan.com/app/expertPay/getGanDanFileOrder
|
||||
|
||||
}
|
||||
|
||||
export default api
|
||||
+16
-2
@@ -23,11 +23,25 @@ const goods_api = {
|
||||
createGoodsOrder(data) {
|
||||
return request('/expertAPI/createGoodsOrder', data, 'post', true);
|
||||
},
|
||||
|
||||
payGoodsOrder(data) {
|
||||
return request('/expertAPI/payGoodsOrder', data, 'post', true);
|
||||
},
|
||||
getGoodsOrderList(data) {
|
||||
return request('/expertAPI/goodsOrderList', data, 'post', true);
|
||||
},
|
||||
getUpanWelfareCount(data){
|
||||
return request('/expertAPI/getUpanWelfareCount', data, 'post', false);
|
||||
},
|
||||
getGoodsOrderDetail(data) {
|
||||
return request('/expertAPI/getGoodsOrder', data, 'post', true);
|
||||
},
|
||||
getOrderTrack(data) {
|
||||
return request('/expertAPI/getOrderTrack', data, 'post', true);
|
||||
},
|
||||
cancelGoodsOrder(data) {
|
||||
return request('/expertAPI/cancleGoodsOrder', data, 'post', true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default goods_api;
|
||||
@@ -22,6 +22,9 @@ const my_api = {
|
||||
|
||||
startpage() {
|
||||
return request('/expertAPI/startpage', {}, 'post', true);
|
||||
},
|
||||
addUniappCid(data) {
|
||||
return request('/expertAPI/addUniappCid', data, 'post', true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
:lazy-load="true"
|
||||
class="avatar-img"
|
||||
v-if="avatarUrl"
|
||||
:src="docUrl+avatarUrl.replaceAll('null','')"
|
||||
:src="docUrl+avatarUrl.replace('null','')"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<image
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<view v-show="visible" class="gd-mask" :class="alignClass" :style="maskStyle">
|
||||
<view
|
||||
class="gd-dialog"
|
||||
@touchstart="onTouchStart"
|
||||
@touchmove="onTouchMove"
|
||||
@touchend="onTouchEnd"
|
||||
>
|
||||
<view class="gd-title">{{ title }}</view>
|
||||
<scroll-view class="gd-content" scroll-y>
|
||||
<text class="gd-text">{{ content }}</text>
|
||||
</scroll-view>
|
||||
<!-- <view class="gd-footer">
|
||||
<view class="gd-btn gd-confirm" @click="handleConfirm">{{ confirmText }}</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
|
||||
|
||||
const visible = ref(false)
|
||||
const title = ref('消息通知')
|
||||
const content = ref('')
|
||||
const confirmText = ref('我知道了')
|
||||
const position = ref('center') // 'center' | 'top'
|
||||
const offsetTop = ref('20rpx')
|
||||
const autoHideTimer = ref(null)
|
||||
|
||||
const startY = ref(0)
|
||||
const hasSwipedUp = ref(false)
|
||||
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
function handleConfirm(){
|
||||
visible.value = false
|
||||
emit('confirm')
|
||||
}
|
||||
|
||||
function show(payload = {}){
|
||||
title.value = payload.title || '消息通知'
|
||||
content.value = payload.content || ''
|
||||
confirmText.value = payload.confirmText || '我知道了'
|
||||
position.value = payload.position === 'top' ? 'top' : 'center'
|
||||
offsetTop.value = payload.offsetTop || '20rpx'
|
||||
visible.value = true
|
||||
// 自动 5 秒后消失
|
||||
if (autoHideTimer.value) clearTimeout(autoHideTimer.value)
|
||||
autoHideTimer.value = setTimeout(() => {
|
||||
hide()
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
function hide(){
|
||||
visible.value = false
|
||||
if (autoHideTimer.value) {
|
||||
clearTimeout(autoHideTimer.value)
|
||||
autoHideTimer.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function onTouchStart(e){
|
||||
const touch = e.changedTouches ? e.changedTouches[0] : (e.touches ? e.touches[0] : null)
|
||||
if (!touch) return
|
||||
startY.value = touch.clientY || touch.pageY || 0
|
||||
hasSwipedUp.value = false
|
||||
}
|
||||
|
||||
function onTouchMove(e){
|
||||
const touch = e.changedTouches ? e.changedTouches[0] : (e.touches ? e.touches[0] : null)
|
||||
if (!touch) return
|
||||
const currentY = touch.clientY || touch.pageY || 0
|
||||
const deltaY = currentY - startY.value
|
||||
if (deltaY < -60) {
|
||||
hasSwipedUp.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function onTouchEnd(){
|
||||
if (hasSwipedUp.value) {
|
||||
hide()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
console.log('[GlobalDialog] mounted')
|
||||
uni.$on('global-dialog:show', show)
|
||||
uni.$on('global-dialog:hide', hide)
|
||||
// 便于全局手动触发测试
|
||||
// @ts-ignore
|
||||
uni.$showGlobalDialog = (payload = {}) => {
|
||||
console.log('[GlobalDialog] uni.$showGlobalDialog called', payload)
|
||||
uni.$emit('global-dialog:show', payload)
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
uni.$off('global-dialog:show', show)
|
||||
uni.$off('global-dialog:hide', hide)
|
||||
})
|
||||
|
||||
const alignClass = computed(() => position.value === 'top' ? 'is-top' : 'is-center')
|
||||
const maskStyle = computed(() => position.value === 'top' ? { paddingTop: offsetTop.value } : {})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.gd-mask{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
// 非模态:容器不截获事件
|
||||
pointer-events: none;
|
||||
}
|
||||
.gd-mask.is-top{
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
.gd-dialog{
|
||||
width: 600rpx;
|
||||
max-width: 90%;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
// 允许对话框自己接收事件(容器为非模态)
|
||||
pointer-events: auto;
|
||||
// 轻微上滑消失的过渡体验
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
.gd-title{
|
||||
padding: 28rpx 32rpx 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #111;
|
||||
text-align: left;
|
||||
}
|
||||
.gd-content{
|
||||
max-height: 420rpx;
|
||||
padding: 0 32rpx 24rpx;
|
||||
}
|
||||
.gd-text{
|
||||
font-size: 28rpx;
|
||||
line-height: 1.7;
|
||||
color: #333;
|
||||
}
|
||||
.gd-footer{
|
||||
padding: 16rpx 24rpx 24rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.gd-btn{
|
||||
min-width: 200rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
text-align: center;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.gd-confirm{
|
||||
background: #2979ff;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<!-- domId 是要截图的容器 id -->
|
||||
<view class="my-html2canvas" :prop="domId" :change:prop="h2cRender.watchDomId">
|
||||
<!-- 用于触发 renderjs 截图 -->
|
||||
<text :prop="expOver" :change:prop="h2cRender.watchExpOver"></text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
domId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expOver: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 业务层调用这个方法开始截图
|
||||
h2cRenderDom() {
|
||||
// #ifdef H5
|
||||
// H5 直接在当前环境(有 DOM)里跑 renderDom
|
||||
this.$emit('renderDomInH5')
|
||||
// #endif
|
||||
|
||||
// #ifndef H5
|
||||
// 非 H5(APP 等)通过 expOver 触发 renderjs 中的截图逻辑
|
||||
this.expOver++
|
||||
// #endif
|
||||
},
|
||||
// renderjs 截图完成后会 callMethod 回调到这里
|
||||
renderOver(base64) {
|
||||
this.$emit('renderOver', base64)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- renderjs 只能内联 -->
|
||||
<script module="h2cRender" lang="renderjs">
|
||||
import html2canvas from 'html2canvas'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
domIdValue: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async renderDom() {
|
||||
try {
|
||||
const el = document.getElementById(this.domIdValue)
|
||||
if (!el) {
|
||||
console.error('[MyHtml2canvas] dom 未找到,请检查 domId:', this.domIdValue)
|
||||
return
|
||||
}
|
||||
const canvas = await html2canvas(el, {
|
||||
width: el.offsetWidth,
|
||||
height: el.offsetHeight,
|
||||
x: 0,
|
||||
y: 0,
|
||||
useCORS: true,
|
||||
scale: 2
|
||||
})
|
||||
const base64 = canvas.toDataURL('image/png', 1)
|
||||
this.$ownerInstance.callMethod('renderOver', base64)
|
||||
} catch (err) {
|
||||
console.error('[MyHtml2canvas] html2canvas 失败:', err && err.message)
|
||||
}
|
||||
},
|
||||
// script 部分通过 :prop 传入 domId
|
||||
watchDomId(newVal) {
|
||||
this.domIdValue = newVal
|
||||
},
|
||||
// expOver 变化时触发渲染
|
||||
watchExpOver(newVal) {
|
||||
if (newVal !== 0) {
|
||||
this.renderDom()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.my-html2canvas {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 当父组件传递的prop属性数据发生变化的时候 ,生成海报图片-->
|
||||
<view :prop="domId" :change:prop="html2canvas.emitData" class="html2canvas">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base64ToPath } from '@/utils/image-tools.js';
|
||||
export default {
|
||||
props: {
|
||||
domId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("组件加载完成");
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 接收renderjs发回的数据
|
||||
async receiveRenderData(imgData) {
|
||||
let posterHeight=imgData.height;
|
||||
let posterWidth=imgData.width;
|
||||
let imgPath =await base64ToPath(imgData.imgVal, '.jpeg');
|
||||
this.$emit('renderFinish', {"posterPath":imgPath,"posterHeight":posterHeight,"posterWidth":posterWidth});
|
||||
uni.hideLoading();
|
||||
},
|
||||
showLoading() {
|
||||
uni.showLoading({
|
||||
title: "正在生成导出",
|
||||
icon: "none",
|
||||
mask: true,
|
||||
duration: 3000
|
||||
})
|
||||
},
|
||||
hideLoading() {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script module="html2canvas" lang="renderjs">
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("视图层渲染完成");
|
||||
},
|
||||
methods: {
|
||||
// 发送数据到逻辑层,下面这里最好是加一个settimeout延迟,因为主界面数据还没加载渲染完成
|
||||
emitData(domId) {
|
||||
this.$ownerInstance.callMethod('showLoading', true);
|
||||
const dom = document.getElementById('poster');
|
||||
console.log("dom",dom);
|
||||
let width= dom.offsetWidth;
|
||||
let height=dom.offsetHeight;
|
||||
let windowHeight= uni.getSystemInfoSync().windowHeight;
|
||||
let windowWidth=uni.getSystemInfoSync().windowWidth;
|
||||
html2canvas(dom, {
|
||||
width:width,
|
||||
height:height,
|
||||
//scale:2.5, // 缩放倍数
|
||||
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
|
||||
scrollX: 0,
|
||||
x:0,
|
||||
y:0,
|
||||
windowWidth:windowWidth,
|
||||
windowHeight:windowHeight,
|
||||
useCORS: true, //支持跨域,但好像没什么用
|
||||
}).then((canvas) => {
|
||||
let imgVal= canvas.toDataURL('image/png');
|
||||
this.$ownerInstance.callMethod('receiveRenderData',{imgVal:imgVal,height:height,width:width});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 当父组件传递的prop属性数据发生变化的时候 ,生成海报图片-->
|
||||
<view :prop="domId" :change:prop="html2canvas.emitData" class="html2canvas">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base64ToPath } from '@/utils/image-tools.js';
|
||||
export default {
|
||||
props: {
|
||||
domId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("组件加载完成");
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 接收renderjs发回的数据
|
||||
async receiveRenderData(imgData) {
|
||||
let posterHeight=imgData.height;
|
||||
let posterWidth=imgData.width;
|
||||
let imgPath =await base64ToPath(imgData.imgVal, '.jpeg');
|
||||
this.$emit('renderFinish', {"posterPath":imgPath,"posterHeight":posterHeight,"posterWidth":posterWidth});
|
||||
uni.hideLoading();
|
||||
},
|
||||
showLoading() {
|
||||
uni.showLoading({
|
||||
title: "正在生成导出",
|
||||
icon: "none",
|
||||
mask: true,
|
||||
duration: 3000
|
||||
})
|
||||
},
|
||||
hideLoading() {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script module="html2canvas" lang="renderjs">
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("视图层渲染完成");
|
||||
},
|
||||
methods: {
|
||||
// 发送数据到逻辑层,下面这里最好是加一个settimeout延迟,因为主界面数据还没加载渲染完成
|
||||
emitData(domId) {
|
||||
this.$ownerInstance.callMethod('showLoading', true);
|
||||
const dom = document.getElementById('poster');
|
||||
console.log("dom",dom);
|
||||
let width= dom.offsetWidth;
|
||||
let height=dom.offsetHeight;
|
||||
let windowHeight= uni.getSystemInfoSync().windowHeight;
|
||||
let windowWidth=uni.getSystemInfoSync().windowWidth;
|
||||
html2canvas(dom, {
|
||||
width:width,
|
||||
height:height,
|
||||
//scale:2.5, // 缩放倍数
|
||||
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
|
||||
scrollX: 0,
|
||||
x:0,
|
||||
y:0,
|
||||
windowWidth:windowWidth,
|
||||
windowHeight:windowHeight,
|
||||
useCORS: true, //支持跨域,但好像没什么用
|
||||
}).then((canvas) => {
|
||||
let imgVal= canvas.toDataURL('image/png');
|
||||
this.$ownerInstance.callMethod('receiveRenderData',{imgVal:imgVal,height:height,width:width});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@
|
||||
<view class="dialog-container" @click.stop>
|
||||
<!-- 弹窗标题 -->
|
||||
<view class="dialog-header">
|
||||
<text class="dialog-title">{{ title }}</text>
|
||||
<text class="dialog-title" :style="{ color: titleColor }">{{ title }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 弹窗内容 -->
|
||||
@@ -42,13 +42,13 @@
|
||||
|
||||
@click="oncancel"
|
||||
>
|
||||
<text class="btn-text">取消</text>
|
||||
<text class="btn-text">{{ cancelText }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="dialog-btn confirm"
|
||||
@click="onconfirm"
|
||||
>
|
||||
<text class="btn-text">确定</text>
|
||||
<text class="btn-text">{{ confirmText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -63,6 +63,10 @@
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
titleColor: {
|
||||
type: String,
|
||||
default: '#8B2316'
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '温馨提示'
|
||||
@@ -130,6 +134,8 @@
|
||||
}
|
||||
|
||||
.dialog-container {
|
||||
position: relative;
|
||||
z-index:100;
|
||||
background-color: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
width: 92%;
|
||||
|
||||
@@ -1,14 +1,68 @@
|
||||
<template>
|
||||
<view class="emptybox">
|
||||
<up-image :src="emptyImg" width="176rpx" height="204rpx" ></up-image>
|
||||
<text class="empty-text">暂无数据</text>
|
||||
<view class="empty-image-wrap" :style="imageWrapStyle">
|
||||
<up-image
|
||||
:src="emptyImage || emptyImg"
|
||||
:width="renderWidth"
|
||||
:height="renderHeight"
|
||||
:mode="imgMode"
|
||||
></up-image>
|
||||
</view>
|
||||
<text class="empty-text">{{ emptyDesc }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import { computed } from 'vue';
|
||||
import emptyImg from "@/static/icon_empty.png"
|
||||
const props = defineProps({
|
||||
emptyImage: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
imgWidth: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
imgHeight: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
emptyDesc: {
|
||||
type: String,
|
||||
default: '暂无数据'
|
||||
}
|
||||
})
|
||||
|
||||
const normalizeSize = (size) => {
|
||||
if (size === '' || size === null || size === undefined) return '';
|
||||
// 直传字符串(如 50%、206rpx、120px),数字交给 up-image 按组件规则处理
|
||||
return typeof size === 'string' ? size.trim() : size;
|
||||
};
|
||||
const isPercentSize = (size) => typeof size === 'string' && size.endsWith('%');
|
||||
|
||||
const imgWidth = computed(() => {
|
||||
const width = normalizeSize(props.imgWidth);
|
||||
const height = normalizeSize(props.imgHeight);
|
||||
if (width !== '') return width;
|
||||
if (height === '') return '206rpx';
|
||||
return '';
|
||||
});
|
||||
const imgHeight = computed(() => normalizeSize(props.imgHeight));
|
||||
const renderWidth = computed(() => (isPercentSize(imgWidth.value) ? '100%' : imgWidth.value));
|
||||
const renderHeight = computed(() => (isPercentSize(imgHeight.value) ? '100%' : imgHeight.value));
|
||||
const imageWrapStyle = computed(() => {
|
||||
const style = {};
|
||||
if (isPercentSize(imgWidth.value)) style.width = imgWidth.value;
|
||||
if (isPercentSize(imgHeight.value)) style.height = imgHeight.value;
|
||||
return style;
|
||||
});
|
||||
const imgMode = computed(() => {
|
||||
// 只传宽/高时按比例缩放,避免图片被拉伸
|
||||
if (imgWidth.value && !imgHeight.value) return 'widthFix';
|
||||
if (!imgWidth.value && imgHeight.value) return 'heightFix';
|
||||
return 'aspectFit';
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -21,6 +75,11 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.empty-image-wrap{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.empty-text{
|
||||
font-size: 30rpx;
|
||||
color:#999;
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
<template>
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
:left-icon="showLeft?'left':''"
|
||||
:title="title"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
const props=defineProps({
|
||||
showLeft:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
noticeBack:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
title:{
|
||||
type:String,
|
||||
default:''
|
||||
@@ -29,10 +38,21 @@
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.navbox{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height:(var(--status-bar-height)+44px);
|
||||
z-index: 9999;
|
||||
}
|
||||
.status_bar{
|
||||
height: var(--status-bar-height);
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file 拖动进度提示组件
|
||||
*/
|
||||
<template>
|
||||
<view class="plv-player-drag-tips">
|
||||
<view class="plv-player-drag-tips__box">
|
||||
<image class="plv-player-drag-tips__direction-img" :src="imgSrc"
|
||||
@error="imageError">
|
||||
</image>
|
||||
<text class="plv-player-drag-tips__time">
|
||||
{{changeTimeFormat}} / {{durationFormat}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import utils from '@/common/util.js';
|
||||
import backImg from '@/static/skin/back.png';
|
||||
import forwardImg from '@/static/skin/forward.png'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
currentTime: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
duration: {
|
||||
type: Number
|
||||
},
|
||||
|
||||
changeTime: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isForward: false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
watch: {
|
||||
changeTime(newValue, oldValue){
|
||||
this.isForward = newValue > oldValue;
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
timeFormatType() {
|
||||
this.duration >= 3600 ? 2 : 1;
|
||||
},
|
||||
|
||||
changeTimeFormat() {
|
||||
return utils.formatTimeByDuration(this.changeTime, this.timeFormatType);
|
||||
},
|
||||
|
||||
durationFormat() {
|
||||
return utils.formatTimeByDuration(this.duration, this.timeFormatType)
|
||||
},
|
||||
|
||||
imgSrc() {
|
||||
return this.isForward ? forwardImg : backImg;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.plv-player-drag-tips {
|
||||
width: 250rpx;
|
||||
height: 160rpx;
|
||||
background: rgba(0,0,0,.7);
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.plv-player-drag-tips__box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.plv-player-drag-tips__direction-img {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.plv-player-drag-tips__time {
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,271 @@
|
||||
<template>
|
||||
<view class="plv-player-gesture"
|
||||
@touchstart="touchstart"
|
||||
@touchmove="touchmove"
|
||||
@longpress="handleLongPress"
|
||||
@touchcancel="handleTouchCancel"
|
||||
@touchend="touchend">
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 屏幕宽度(物理像素)
|
||||
holeWidth: Number,
|
||||
// 视频总时长
|
||||
duration: Number,
|
||||
// 视频当前播放时间
|
||||
currentTime: Number
|
||||
},
|
||||
|
||||
computed: {
|
||||
halfWidth() {
|
||||
return parseInt(this.holeWidth / 2);
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
// 是否在左区域按下手势
|
||||
downLeft: false,
|
||||
// 滑动方向
|
||||
swipeDir: null
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.addHandler();
|
||||
},
|
||||
|
||||
methods:{
|
||||
addHandler() {
|
||||
// 增加父容器左右滑动监听
|
||||
let finalTime = -1;
|
||||
// 计算左右滑动seek进度
|
||||
const countTime = (position) => {
|
||||
const { holeWidth, duration, currentTime } = this;
|
||||
const precent = Math.abs(position) / holeWidth;
|
||||
const nowTime = currentTime || 0;
|
||||
const constSecond = duration < 60 ? duration : 60;
|
||||
let plusTime = parseInt(Math.abs(precent * constSecond));
|
||||
if (position < 0) plusTime = plusTime * -1;
|
||||
finalTime = nowTime + plusTime;
|
||||
finalTime = this.limit(finalTime, 0, duration);
|
||||
return finalTime;
|
||||
};
|
||||
|
||||
this.addGesture((type, position) => {
|
||||
switch (type) {
|
||||
// 下滑
|
||||
case -1:
|
||||
// console.log('//下滑');
|
||||
this.$emit('onGestureEvent', {
|
||||
type: this.downLeft ? 'LEFT_DOWN' : 'RIGHT_DOWN',
|
||||
position
|
||||
});
|
||||
break;
|
||||
// 上滑
|
||||
case -2:
|
||||
// console.log('//上滑');
|
||||
this.$emit('onGestureEvent', {
|
||||
type: this.downLeft ? 'LEFT_UP' : 'RIGHT_UP',
|
||||
position
|
||||
});
|
||||
break;
|
||||
// 左滑
|
||||
case 0:
|
||||
// console.log('//左滑');
|
||||
this.swipeDir = type;
|
||||
countTime(position);
|
||||
this.$emit('onGestureEvent', {
|
||||
type: 'SEEK_TIME_UPDATE',
|
||||
finalTime
|
||||
});
|
||||
break;
|
||||
// 右滑
|
||||
case 1:
|
||||
// console.log('//右滑');
|
||||
this.swipeDir = type;
|
||||
countTime(position);
|
||||
this.$emit('onGestureEvent', {
|
||||
type: 'SEEK_TIME_UPDATE',
|
||||
finalTime
|
||||
});
|
||||
break;
|
||||
// touchend for swipe
|
||||
case 3:
|
||||
if (this.swipeDir > -1) {
|
||||
this.$emit('onGestureEvent', {
|
||||
type: this.swipeDir ? 'SWIPE_RIGHT' : 'SWIPE_LEFT'
|
||||
});
|
||||
this.swipeDir = -1;
|
||||
}
|
||||
|
||||
if (finalTime > -1) {
|
||||
this.$emit('onGestureSeekTo', finalTime);
|
||||
finalTime = -1;
|
||||
}
|
||||
break;
|
||||
// doubleTap
|
||||
case 4:
|
||||
// console.log('>>>> 双击');
|
||||
this.$emit('onGestureEvent', {
|
||||
type: 'DOUBLE_CLICK'
|
||||
});
|
||||
break;
|
||||
// tap
|
||||
case 5:
|
||||
// console.log('>>>> 单击');
|
||||
this.handleClick();
|
||||
break;
|
||||
// longTap
|
||||
case 6:
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
addGesture(callback) {
|
||||
const { options } = this;
|
||||
let startX, startY, moveEndX, moveEndY, X, Y, position, hasType;
|
||||
let T, lastTap, isJustTouch = true;
|
||||
|
||||
|
||||
const excuteCb = (type) => {
|
||||
// type 手势类型 -2 上滑 -1 下滑 0 左滑 1 右滑 2 just touch 3 touchend 4 doubleTap 5 tap 6 longTap
|
||||
if (callback && typeof callback === 'function')
|
||||
callback(type, position);
|
||||
};
|
||||
|
||||
const YPlus = 20;
|
||||
const YReduce = YPlus * -1;
|
||||
const XPlus = 50;
|
||||
const XReduce = XPlus * -1;
|
||||
|
||||
const isXchange = () => {
|
||||
if (X > XPlus || X < XReduce) {
|
||||
position = X;
|
||||
hasType = 'X';
|
||||
isJustTouch = false;
|
||||
}
|
||||
|
||||
if (X > XPlus) excuteCb(1);
|
||||
// 左滑
|
||||
else if (X < XReduce) excuteCb(0);
|
||||
};
|
||||
|
||||
const isYchange = () => {
|
||||
if (Y > YPlus || Y < YReduce) {
|
||||
position = Y;
|
||||
hasType = 'Y';
|
||||
isJustTouch = false;
|
||||
}
|
||||
|
||||
if (Y > YPlus) excuteCb(-1);
|
||||
// 上滑
|
||||
else if (Y < YReduce) excuteCb(-2);
|
||||
};
|
||||
|
||||
const countDirect = () => {
|
||||
if (hasType) {
|
||||
hasType === 'X' ? isXchange() : isYchange();
|
||||
return;
|
||||
}
|
||||
isXchange();
|
||||
isYchange();
|
||||
};
|
||||
|
||||
this.handleTouch = (type, e) => {
|
||||
switch(type) {
|
||||
case 'start':
|
||||
startX = e.changedTouches[0].pageX;
|
||||
startY = e.changedTouches[0].pageY;
|
||||
T = Date.now();
|
||||
hasType = '';
|
||||
isJustTouch = true;
|
||||
this.downLeft = startX < this.halfWidth ? true : false;
|
||||
|
||||
break;
|
||||
case 'move':
|
||||
moveEndX = e.changedTouches[0].pageX;
|
||||
moveEndY = e.changedTouches[0].pageY;
|
||||
X = moveEndX - startX;
|
||||
Y = moveEndY - startY;
|
||||
countDirect();
|
||||
break;
|
||||
case 'end':
|
||||
if (isJustTouch)
|
||||
if (lastTap && Date.now() - lastTap <= 300)
|
||||
excuteCb(4);
|
||||
else if (Date.now() - T < 1000)
|
||||
excuteCb(5);
|
||||
else
|
||||
excuteCb(6);
|
||||
else
|
||||
excuteCb(3);
|
||||
|
||||
lastTap = Date.now();
|
||||
isJustTouch = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
handleClick() {
|
||||
this.$emit('onGestureClick');
|
||||
},
|
||||
|
||||
touchstart(e) {
|
||||
this.handleTouch('start', e);
|
||||
},
|
||||
|
||||
touchmove(e) {
|
||||
this.handleTouch('move', e);
|
||||
},
|
||||
|
||||
touchend(e) {
|
||||
this.handleTouch('end', e);
|
||||
this.$emit('onTouchEnd');
|
||||
},
|
||||
|
||||
handleTouchCancel() {
|
||||
this.$emit('onTouchCancel');
|
||||
},
|
||||
|
||||
handleLongPress() {
|
||||
this.$emit('onLongPress');
|
||||
},
|
||||
|
||||
/**
|
||||
* 控制最小值,最大值
|
||||
* @param num
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns {*}
|
||||
*/
|
||||
limit(num, min, max) {
|
||||
if (num < min) return min;
|
||||
if (num > max) return max;
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.plv-player-gesture {
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.plv-player-gesture__left {
|
||||
flex: 5;
|
||||
}
|
||||
|
||||
.plv-player-gesture__right {
|
||||
flex: 5;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<view v-if="isShow" class="plv-player-icon">
|
||||
<image class="plv-player-icon__img" :src="imgUrl"></image>
|
||||
<text class="plv-player-icon__text">{{ precent + '%' }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
imgUrl: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
precent: {
|
||||
type: 'Number',
|
||||
default: 100,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
precent(num) {
|
||||
if (!this.isShow) this.isShow = true;
|
||||
this.startClock();
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
startClock() {
|
||||
this.clearClock();
|
||||
|
||||
this.clock = setTimeout(() => {
|
||||
this.isShow = false;
|
||||
}, 1500);
|
||||
},
|
||||
|
||||
clearClock() {
|
||||
if (this.clock) clearTimeout(this.clock);
|
||||
this.clock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.plv-player-icon {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.plv-player-icon__img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.plv-player-icon__text {
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<view v-if="isShow" class="plv-player-volume-wrap">
|
||||
<image class="plv-player-volume__img" :src="value === 0 ? muteImgUrl : imgUrl "></image>
|
||||
<view class="plv-player-volume__progress">
|
||||
<view class="plv-player-volume__progress__played" :style="'flex:' + value"></view>
|
||||
<view class="plv-player-volume__progress_surplus" :style="'flex:' + valueLeft"></view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
imgUrl: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
muteImgUrl: {
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
value: {
|
||||
type: 'Number',
|
||||
default: 0.5,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
value(num) {
|
||||
if (!this.isShow) this.isShow = true;
|
||||
this.startClock();
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
valueLeft() {
|
||||
return 1 - this.value;
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isShow: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
startClock() {
|
||||
this.clearClock();
|
||||
|
||||
this.clock = setTimeout(() => {
|
||||
this.isShow = false;
|
||||
}, 1500);
|
||||
},
|
||||
|
||||
clearClock() {
|
||||
if (this.clock) clearTimeout(this.clock);
|
||||
this.clock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.plv-player-volume-wrap {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.plv-player-volume__img {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.plv-player-volume__progress {
|
||||
width: 260rpx;
|
||||
height: 8rpx;
|
||||
flex-direction: row;
|
||||
background-color: #09BB07;
|
||||
}
|
||||
|
||||
.plv-player-volume__progress__played {
|
||||
background-color: #007AFF;
|
||||
}
|
||||
|
||||
.plv-player-volume__progress_surplus {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
</style>
|
||||
@@ -5,7 +5,7 @@
|
||||
v-for="(item, index) in tabList"
|
||||
:key="index"
|
||||
@click="switchTab(index, item)"
|
||||
:class="{ active: currentTab === index }"
|
||||
:class="{ active: 2 === index }"
|
||||
>
|
||||
<!-- 图标容器 -->
|
||||
<view class="icon-container">
|
||||
@@ -33,11 +33,13 @@
|
||||
<!-- <view class="active-indicator" v-if="currentTab === index"></view> -->
|
||||
</view>
|
||||
</view>
|
||||
<GlobalDialog />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, nextTick } from 'vue';
|
||||
import { onShow, onLoad } from "@dcloudio/uni-app";
|
||||
import GlobalDialog from "@/components/GlobalDialog.vue"
|
||||
import home from '@/static/home_nor.png'
|
||||
import homeOn from '@/static/home_sel.png'
|
||||
import classroom from "@/static/classroom.png"
|
||||
@@ -70,7 +72,7 @@
|
||||
activeColor: '#007aff',
|
||||
badge: 0,
|
||||
showRedDot: false,
|
||||
pagePath: '/pages/index/index'
|
||||
pagePath: '/pages/index/index?from=push'
|
||||
},
|
||||
{
|
||||
icon: classroom,
|
||||
@@ -119,32 +121,56 @@
|
||||
if (currentTab.value === index) return;
|
||||
|
||||
// 更新当前tab
|
||||
currentTab.value = index;
|
||||
|
||||
// 清除红点
|
||||
if (item.showRedDot) {
|
||||
item.showRedDot = false;
|
||||
//currentTab.value = index;
|
||||
let msg="home"
|
||||
if(index == 0){
|
||||
msg="home"
|
||||
}else if(index == 1){
|
||||
msg="patientClass"
|
||||
}else if(index == 2){
|
||||
msg="live"
|
||||
}else if(index == 3){
|
||||
msg="education"
|
||||
}else if(index == 4){
|
||||
msg="mine"
|
||||
}
|
||||
|
||||
try{
|
||||
uni.sendNativeEvent('goTabbarPage', {
|
||||
msg: msg
|
||||
},ret => {
|
||||
|
||||
console.log(ret);
|
||||
})
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
}
|
||||
plus.runtime.quit()
|
||||
// 清除红点
|
||||
// if (item.showRedDot) {
|
||||
// item.showRedDot = false;
|
||||
// }
|
||||
|
||||
// 页面跳转
|
||||
uni.redirectTo({
|
||||
url: item.pagePath,
|
||||
fail: () => {
|
||||
// 如果页面不存在,使用navigateTo
|
||||
uni.navigateTo({
|
||||
url: item.pagePath,
|
||||
fail: () => {
|
||||
// uni.redirectTo({
|
||||
// url: item.pagePath,
|
||||
// fail: () => {
|
||||
// // 如果页面不存在,使用navigateTo
|
||||
// uni.navigateTo({
|
||||
// url: item.pagePath,
|
||||
// fail: () => {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
// 触发父组件事件
|
||||
emit('tabChange', {
|
||||
index,
|
||||
item
|
||||
});
|
||||
// emit('tabChange', {
|
||||
// index,
|
||||
// item
|
||||
// });
|
||||
|
||||
};
|
||||
|
||||
// 设置徽章数量
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<view class="top-tip" v-if="visible">
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="content">
|
||||
{{ content }}
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const visible = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
const open = () => {
|
||||
visible.value = true
|
||||
}
|
||||
const close = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
close
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.top-tip{
|
||||
position: fixed;
|
||||
top: 180rpx;
|
||||
left: 40rpx;
|
||||
right:40rpx;
|
||||
padding: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
z-index: 99999999999;
|
||||
.title{
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
|
||||
}
|
||||
.content{
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
margin-top: 25rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* 本模块封装了Android、iOS的应用权限判断、打开应用权限设置界面、以及位置系统服务是否开启
|
||||
*/
|
||||
|
||||
var isIos
|
||||
// #ifdef APP-PLUS
|
||||
isIos = (plus.os.name == "iOS")
|
||||
// #endif
|
||||
|
||||
// 判断推送权限是否开启
|
||||
function judgeIosPermissionPush() {
|
||||
var result = false;
|
||||
var UIApplication = plus.ios.import("UIApplication");
|
||||
var app = UIApplication.sharedApplication();
|
||||
var enabledTypes = 0;
|
||||
if (app.currentUserNotificationSettings) {
|
||||
var settings = app.currentUserNotificationSettings();
|
||||
enabledTypes = settings.plusGetAttribute("types");
|
||||
console.log("enabledTypes1:" + enabledTypes);
|
||||
if (enabledTypes == 0) {
|
||||
console.log("推送权限没有开启");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("已经开启推送功能!")
|
||||
}
|
||||
plus.ios.deleteObject(settings);
|
||||
} else {
|
||||
enabledTypes = app.enabledRemoteNotificationTypes();
|
||||
if (enabledTypes == 0) {
|
||||
console.log("推送权限没有开启!");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("已经开启推送功能!")
|
||||
}
|
||||
console.log("enabledTypes2:" + enabledTypes);
|
||||
}
|
||||
plus.ios.deleteObject(app);
|
||||
plus.ios.deleteObject(UIApplication);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断定位权限是否开启
|
||||
function judgeIosPermissionLocation() {
|
||||
var result = false;
|
||||
var cllocationManger = plus.ios.import("CLLocationManager");
|
||||
var status = cllocationManger.authorizationStatus();
|
||||
result = (status != 2)
|
||||
console.log("定位权限开启:" + result);
|
||||
// 以下代码判断了手机设备的定位是否关闭,推荐另行使用方法 checkSystemEnableLocation
|
||||
/* var enable = cllocationManger.locationServicesEnabled();
|
||||
var status = cllocationManger.authorizationStatus();
|
||||
console.log("enable:" + enable);
|
||||
console.log("status:" + status);
|
||||
if (enable && status != 2) {
|
||||
result = true;
|
||||
console.log("手机定位服务已开启且已授予定位权限");
|
||||
} else {
|
||||
console.log("手机系统的定位没有打开或未给予定位权限");
|
||||
} */
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断麦克风权限是否开启
|
||||
function judgeIosPermissionRecord() {
|
||||
var result = false;
|
||||
var avaudiosession = plus.ios.import("AVAudioSession");
|
||||
var avaudio = avaudiosession.sharedInstance();
|
||||
var permissionStatus = avaudio.recordPermission();
|
||||
console.log("permissionStatus:" + permissionStatus);
|
||||
if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
|
||||
console.log("麦克风权限没有开启");
|
||||
} else {
|
||||
result = true;
|
||||
console.log("麦克风权限已经开启");
|
||||
}
|
||||
plus.ios.deleteObject(avaudiosession);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断相机权限是否开启
|
||||
function judgeIosPermissionCamera() {
|
||||
var result = false;
|
||||
var AVCaptureDevice = plus.ios.import("AVCaptureDevice");
|
||||
var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');
|
||||
console.log("authStatus:" + authStatus);
|
||||
if (authStatus == 3) {
|
||||
result = true;
|
||||
console.log("相机权限已经开启");
|
||||
} else {
|
||||
console.log("相机权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(AVCaptureDevice);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断相册权限是否开启
|
||||
function judgeIosPermissionPhotoLibrary() {
|
||||
var result = false;
|
||||
var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
|
||||
var authStatus = PHPhotoLibrary.authorizationStatus();
|
||||
console.log("authStatus:" + authStatus);
|
||||
if (authStatus == 3) {
|
||||
result = true;
|
||||
console.log("相册权限已经开启");
|
||||
} else {
|
||||
console.log("相册权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(PHPhotoLibrary);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断通讯录权限是否开启
|
||||
function judgeIosPermissionContact() {
|
||||
var result = false;
|
||||
var CNContactStore = plus.ios.import("CNContactStore");
|
||||
var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
|
||||
if (cnAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("通讯录权限已经开启");
|
||||
} else {
|
||||
console.log("通讯录权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(CNContactStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断日历权限是否开启
|
||||
function judgeIosPermissionCalendar() {
|
||||
var result = false;
|
||||
var EKEventStore = plus.ios.import("EKEventStore");
|
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);
|
||||
if (ekAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("日历权限已经开启");
|
||||
} else {
|
||||
console.log("日历权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(EKEventStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 判断备忘录权限是否开启
|
||||
function judgeIosPermissionMemo() {
|
||||
var result = false;
|
||||
var EKEventStore = plus.ios.import("EKEventStore");
|
||||
var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);
|
||||
if (ekAuthStatus == 3) {
|
||||
result = true;
|
||||
console.log("备忘录权限已经开启");
|
||||
} else {
|
||||
console.log("备忘录权限没有开启");
|
||||
}
|
||||
plus.ios.deleteObject(EKEventStore);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Android权限查询
|
||||
function requestAndroidPermission(permissionID) {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.android.requestPermissions(
|
||||
[permissionID], // 理论上支持多个权限同时查询,但实际上本函数封装只处理了一个权限的情况。有需要的可自行扩展封装
|
||||
function(resultObj) {
|
||||
var result = 0;
|
||||
for (var i = 0; i < resultObj.granted.length; i++) {
|
||||
var grantedPermission = resultObj.granted[i];
|
||||
console.log('已获取的权限:' + grantedPermission);
|
||||
result = 1
|
||||
}
|
||||
for (var i = 0; i < resultObj.deniedPresent.length; i++) {
|
||||
var deniedPresentPermission = resultObj.deniedPresent[i];
|
||||
console.log('拒绝本次申请的权限:' + deniedPresentPermission);
|
||||
result = 0
|
||||
}
|
||||
for (var i = 0; i < resultObj.deniedAlways.length; i++) {
|
||||
var deniedAlwaysPermission = resultObj.deniedAlways[i];
|
||||
console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);
|
||||
result = -1
|
||||
}
|
||||
resolve(result);
|
||||
// 若所需权限被拒绝,则打开APP设置界面,可以在APP设置界面打开相应权限
|
||||
// if (result != 1) {
|
||||
// gotoAppPermissionSetting()
|
||||
// }
|
||||
},
|
||||
function(error) {
|
||||
console.log('申请权限错误:' + error.code + " = " + error.message);
|
||||
resolve({
|
||||
code: error.code,
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// 使用一个方法,根据参数判断权限
|
||||
function judgeIosPermission(permissionID) {
|
||||
if (permissionID == "location") {
|
||||
return judgeIosPermissionLocation()
|
||||
} else if (permissionID == "camera") {
|
||||
return judgeIosPermissionCamera()
|
||||
} else if (permissionID == "photoLibrary") {
|
||||
return judgeIosPermissionPhotoLibrary()
|
||||
} else if (permissionID == "record") {
|
||||
return judgeIosPermissionRecord()
|
||||
} else if (permissionID == "push") {
|
||||
return judgeIosPermissionPush()
|
||||
} else if (permissionID == "contact") {
|
||||
return judgeIosPermissionContact()
|
||||
} else if (permissionID == "calendar") {
|
||||
return judgeIosPermissionCalendar()
|
||||
} else if (permissionID == "memo") {
|
||||
return judgeIosPermissionMemo()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 跳转到**应用**的权限页面
|
||||
function gotoAppPermissionSetting() {
|
||||
if (isIos) {
|
||||
var UIApplication = plus.ios.import("UIApplication");
|
||||
var application2 = UIApplication.sharedApplication();
|
||||
var NSURL2 = plus.ios.import("NSURL");
|
||||
// var setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
|
||||
var setting2 = NSURL2.URLWithString("app-settings:");
|
||||
application2.openURL(setting2);
|
||||
|
||||
plus.ios.deleteObject(setting2);
|
||||
plus.ios.deleteObject(NSURL2);
|
||||
plus.ios.deleteObject(application2);
|
||||
} else {
|
||||
// console.log(plus.device.vendor);
|
||||
var Intent = plus.android.importClass("android.content.Intent");
|
||||
var Settings = plus.android.importClass("android.provider.Settings");
|
||||
var Uri = plus.android.importClass("android.net.Uri");
|
||||
var mainActivity = plus.android.runtimeMainActivity();
|
||||
var intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
mainActivity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查系统的设备服务是否开启
|
||||
// var checkSystemEnableLocation = async function () {
|
||||
function checkSystemEnableLocation() {
|
||||
if (isIos) {
|
||||
var result = false;
|
||||
var cllocationManger = plus.ios.import("CLLocationManager");
|
||||
var result = cllocationManger.locationServicesEnabled();
|
||||
console.log("系统定位开启:" + result);
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
return result;
|
||||
} else {
|
||||
var context = plus.android.importClass("android.content.Context");
|
||||
var locationManager = plus.android.importClass("android.location.LocationManager");
|
||||
var main = plus.android.runtimeMainActivity();
|
||||
var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
|
||||
var result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
|
||||
console.log("系统定位开启:" + result);
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// module.exports = {
|
||||
// judgeIosPermission: judgeIosPermission,
|
||||
// requestAndroidPermission: requestAndroidPermission,
|
||||
// checkSystemEnableLocation: checkSystemEnableLocation,
|
||||
// gotoAppPermissionSetting: gotoAppPermissionSetting
|
||||
// }
|
||||
export default {judgeIosPermission,requestAndroidPermission,checkSystemEnableLocation,gotoAppPermissionSetting}
|
||||
@@ -1,5 +1,9 @@
|
||||
|
||||
// ES6模块化引入
|
||||
//import VConsole from 'vconsole'
|
||||
import App from './App'
|
||||
import uviewPlus, { setConfig } from 'uview-plus'
|
||||
//const vConsole = new VConsole();
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import './uni.promisify.adaptor'
|
||||
|
||||
+100
-41
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name" : "肝胆相照专家端",
|
||||
"name" : "肝胆相照专家版",
|
||||
"appid" : "__UNI__89F511F",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"versionName" : "4.2.7",
|
||||
"versionCode" : 427,
|
||||
"transformPx" : false,
|
||||
"app-plus" : {
|
||||
/* 5+App特有相关 */
|
||||
"runmode" : "liberate",
|
||||
"usingComponents" : true,
|
||||
"nvueCompiler" : "uni-app",
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
@@ -16,18 +17,28 @@
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
"compatible" : {
|
||||
"ignoreVersion" : true
|
||||
},
|
||||
"useragent" : {
|
||||
"value" : "gdxz",
|
||||
"concatenate" : true
|
||||
},
|
||||
"modules" : {
|
||||
"OAuth" : {},
|
||||
"Payment" : {},
|
||||
"Share" : {},
|
||||
"Webview-x5" : {},
|
||||
"UIWebview" : {},
|
||||
"Push" : {}
|
||||
"VideoPlayer" : {},
|
||||
"OAuth" : {},
|
||||
"Barcode" : {},
|
||||
"Camera" : {},
|
||||
"Payment" : {}
|
||||
},
|
||||
/* 模块配置 */
|
||||
"distribute" : {
|
||||
/* 应用发布信息 */
|
||||
"android" : {
|
||||
"hasTaskAffinity" : true,
|
||||
/* android打包配置 */
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
@@ -46,19 +57,31 @@
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
],
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
|
||||
"minSdkVersion" : 21,
|
||||
"targetSdkVersion" : 30
|
||||
},
|
||||
"ios" : {
|
||||
"dSYMs" : false,
|
||||
"idfa" : false
|
||||
"idfa" : false,
|
||||
"urlschemewhitelist" : [ "weixin", "wechat" ],
|
||||
"permission" : {
|
||||
"NSPhotoLibraryUsageDescription" : "需要访问相册以选择图片",
|
||||
"NSCameraUsageDescription" : "需要访问相机以拍照"
|
||||
}
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"sdkConfigs" : {
|
||||
"oauth" : {
|
||||
"weixin" : {
|
||||
"appid" : "wxbf3658f5e674667c",
|
||||
"appsecret" : "c4505a04a9910c65efea8e11ffc93f92",
|
||||
"UniversalLinks" : "https://doc.igandan.com/gdxzExpert/"
|
||||
},
|
||||
"univerify" : {},
|
||||
"sina" : {
|
||||
"appkey" : "2071931330",
|
||||
"redirect_uri" : "http://sns.whalecloud.com/sina2/callback",
|
||||
"UniversalLinks" : ""
|
||||
}
|
||||
},
|
||||
"payment" : {
|
||||
@@ -73,68 +96,104 @@
|
||||
"weixin" : {
|
||||
"appid" : "wxbf3658f5e674667c",
|
||||
"UniversalLinks" : "https://doc.igandan.com/gdxzExpert/"
|
||||
},
|
||||
"sina" : {
|
||||
"appkey" : "2071931330",
|
||||
"redirect_uri" : "http://sns.whalecloud.com/sina2/callback",
|
||||
"UniversalLinks" : "https://doc.igandan.com/gdxzExpert/"
|
||||
}
|
||||
},
|
||||
"speech" : {},
|
||||
"push" : {
|
||||
"unipush" : {
|
||||
"version" : "2",
|
||||
"offline" : false,
|
||||
"hms" : {},
|
||||
"oppo" : {},
|
||||
"vivo" : {},
|
||||
"mi" : {},
|
||||
"meizu" : {},
|
||||
"honor" : {},
|
||||
"icons" : {
|
||||
"small" : {
|
||||
"xxhdpi" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/72.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"push" : {}
|
||||
},
|
||||
"splashscreen" : {
|
||||
"androidStyle" : "common",
|
||||
"useOriginalMsgbox" : true,
|
||||
"useOriginalMsgbox" : false,
|
||||
"iosStyle" : "common"
|
||||
},
|
||||
"icons" : {
|
||||
"android" : {
|
||||
"hdpi" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/72.png",
|
||||
"xhdpi" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/96.png",
|
||||
"xxhdpi" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/144.png",
|
||||
"xxxhdpi" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/192.png"
|
||||
"hdpi" : "D:/uniapp/专家版图标/72.png",
|
||||
"xhdpi" : "D:/uniapp/专家版图标/96.png",
|
||||
"xxhdpi" : "D:/uniapp/专家版图标/144.png",
|
||||
"xxxhdpi" : "D:/uniapp/专家版图标/192.png"
|
||||
},
|
||||
"ios" : {
|
||||
"appstore" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/1024.png",
|
||||
"appstore" : "D:/uniapp/专家版图标/1024.png",
|
||||
"iphone" : {
|
||||
"app@2x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/120.png",
|
||||
"app@3x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/180.png",
|
||||
"spotlight@2x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/80.png",
|
||||
"spotlight@3x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/120.png",
|
||||
"settings@2x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/58.png",
|
||||
"settings@3x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/87.png",
|
||||
"notification@2x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/40.png",
|
||||
"notification@3x" : "D:/haomi/Documents/WeChat Files/wxid_x5u4rycntnkq21/FileStorage/File/2025-09/专家版图标/专家版图标/60.png"
|
||||
"app@2x" : "D:/uniapp/专家版图标/120.png",
|
||||
"app@3x" : "D:/uniapp/专家版图标/180.png",
|
||||
"spotlight@2x" : "D:/uniapp/专家版图标/80.png",
|
||||
"spotlight@3x" : "D:/uniapp/专家版图标/120.png",
|
||||
"settings@2x" : "D:/uniapp/专家版图标/58.png",
|
||||
"settings@3x" : "D:/uniapp/专家版图标/87.png",
|
||||
"notification@2x" : "D:/uniapp/专家版图标/40.png",
|
||||
"notification@3x" : "D:/uniapp/专家版图标/60.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"nativePlugins" : {
|
||||
"NIMUniPlugin" : {
|
||||
"PUSH_VIVO_APPID" : "100034326",
|
||||
"PUSH_VIVO_APPKEY" : "e789634c1f76c8f184b1def1101ce824",
|
||||
"PUSH_HONOR_APPID" : "900782424",
|
||||
"__plugin_info__" : {
|
||||
"name" : "NIMUniPlugin",
|
||||
"description" : "uni消息推送插件",
|
||||
"platforms" : "Android,iOS",
|
||||
"url" : "",
|
||||
"android_package_name" : "",
|
||||
"ios_bundle_id" : "",
|
||||
"isCloud" : false,
|
||||
"bought" : -1,
|
||||
"pid" : "",
|
||||
"parameters" : {
|
||||
"PUSH_VIVO_APPID" : {
|
||||
"des" : "厂商VIVO-app_id",
|
||||
"key" : "com.vivo.push.app_id",
|
||||
"value" : ""
|
||||
},
|
||||
"PUSH_VIVO_APPKEY" : {
|
||||
"des" : "厂商VIVO-app_key",
|
||||
"key" : "com.vivo.push.api_key",
|
||||
"value" : ""
|
||||
},
|
||||
"PUSH_HONOR_APPID" : {
|
||||
"des" : "厂商HONOR-app_id",
|
||||
"key" : "com.hihonor.push.app_id",
|
||||
"value" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PLV-MediaPlayer" : {
|
||||
"__plugin_info__" : {
|
||||
"name" : "Polyv播放器插件",
|
||||
"description" : "该插件封装了保利威底层播放器,是云直播和云点播插件必须的附属插件",
|
||||
"platforms" : "Android,iOS",
|
||||
"url" : "https://ext.dcloud.net.cn/plugin?id=4798",
|
||||
"android_package_name" : "",
|
||||
"android_package_name" : "cn.shangyu.gdxzExpert",
|
||||
"ios_bundle_id" : "cn.shangyu.gdxzExport",
|
||||
"isCloud" : true,
|
||||
"bought" : 1,
|
||||
"pid" : "4798",
|
||||
"parameters" : {}
|
||||
}
|
||||
},
|
||||
"PLV-VodUniPlugin" : {
|
||||
"__plugin_info__" : {
|
||||
"name" : "polyv保利威视频云点播插件",
|
||||
"description" : "polyv保利威视频云点播软件组件,支持聊天弹幕、视频加密、多码率、去广告等,还支持视频多维数据统计,适用于教学录播、产品介绍片、视频门户等",
|
||||
"platforms" : "Android,iOS",
|
||||
"url" : "https://ext.dcloud.net.cn/plugin?id=2802",
|
||||
"android_package_name" : "cn.shangyu.gdxzExpert",
|
||||
"ios_bundle_id" : "cn.shangyu.gdxzExport",
|
||||
"isCloud" : true,
|
||||
"bought" : 1,
|
||||
"pid" : "2802",
|
||||
"parameters" : {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{"agcgw":{"url":"connect-drcn.dbankcloud.cn","backurl":"connect-drcn.hispace.hicloud.com","websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn","websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com"},"agcgw_all":{"SG":"connect-dra.dbankcloud.cn","SG_back":"connect-dra.hispace.hicloud.com","CN":"connect-drcn.dbankcloud.cn","CN_back":"connect-drcn.hispace.hicloud.com","RU":"connect-drru.hispace.dbankcloud.ru","RU_back":"connect-drru.hispace.dbankcloud.cn","DE":"connect-dre.dbankcloud.cn","DE_back":"connect-dre.hispace.hicloud.com"},"websocketgw_all":{"SG":"connect-ws-dra.hispace.dbankcloud.cn","SG_back":"connect-ws-dra.hispace.dbankcloud.com","CN":"connect-ws-drcn.hispace.dbankcloud.cn","CN_back":"connect-ws-drcn.hispace.dbankcloud.com","RU":"connect-ws-drru.hispace.dbankcloud.ru","RU_back":"connect-ws-drru.hispace.dbankcloud.cn","DE":"connect-ws-dre.hispace.dbankcloud.cn","DE_back":"connect-ws-dre.hispace.dbankcloud.com"},"client":{"cp_id":"890086000102014306","product_id":"9105163812218585677","client_id":"178572405214545024","client_secret":"B90774CD63B8A6AB5C2C587DC9D7C4C666EF53A19DBA70C4D549C6302ED6CFBE","project_id":"9105163812218585677","app_id":"10526652","api_key":"CV58Raxnpwbfazn6iLPkESUy7KoiUzZ5iTv8lFg/WuexwYZceAK6F9BjRf0HVmT+039dGKt5yecdkRdQ4FCHsmLZ1Zvh","package_name":"cn.shangyu.gdxzExpert"},"oauth_client":{"client_id":"10526652","client_type":1},"app_info":{"app_id":"10526652","package_name":"cn.shangyu.gdxzExpert"},"service":{"analytics":{"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn","collector_url_ru":"datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com","collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn","resource_id":"p1","channel_id":""},"ml":{"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"},"cloudstorage":{"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg":"https://ops-dra.agcstorage.link","storage_url_de":"https://ops-dre.agcstorage.link","storage_url_cn":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru_back":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg_back":"https://agc-storage-dra.cloud.huawei.asia","storage_url_de_back":"https://agc-storage-dre.cloud.huawei.eu","storage_url_cn_back":"https://agc-storage-drcn.cloud.huawei.com.cn"},"search":{"url":"https://search-drcn.cloud.huawei.com"},"edukit":{"edu_url":"edukit.cloud.huawei.com.cn","dh_url":"edukit.cloud.huawei.com.cn"}},"region":"CN","configuration_version":"3.0","appInfos":[{"package_name":"cn.shangyu.gdxzExpert","client":{"app_id":"10526652"},"app_info":{"package_name":"cn.shangyu.gdxzExpert","app_id":"10526652"},"oauth_client":{"client_type":1,"client_id":"10526652"}}]}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"developer_id":"109999967097",
|
||||
"app_id":"900782424",
|
||||
"package_name":"cn.shangyu.gdxzExpert",
|
||||
"version":"1.0"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>files</key>
|
||||
<dict>
|
||||
<key>Info.plist</key>
|
||||
<data>
|
||||
MxazSmkOgOArGHG40O8L+mZ4ULU=
|
||||
</data>
|
||||
</dict>
|
||||
<key>files2</key>
|
||||
<dict/>
|
||||
<key>rules</key>
|
||||
<dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^version.plist$</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>rules2</key>
|
||||
<dict>
|
||||
<key>.*\.dSYM($|/)</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>11</real>
|
||||
</dict>
|
||||
<key>^(.*/)?\.DS_Store$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>2000</real>
|
||||
</dict>
|
||||
<key>^.*</key>
|
||||
<true/>
|
||||
<key>^.*\.lproj/</key>
|
||||
<dict>
|
||||
<key>optional</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1000</real>
|
||||
</dict>
|
||||
<key>^.*\.lproj/locversion.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>1100</real>
|
||||
</dict>
|
||||
<key>^Base\.lproj/</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>1010</real>
|
||||
</dict>
|
||||
<key>^Info\.plist$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^PkgInfo$</key>
|
||||
<dict>
|
||||
<key>omit</key>
|
||||
<true/>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^embedded\.provisionprofile$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
<key>^version\.plist$</key>
|
||||
<dict>
|
||||
<key>weight</key>
|
||||
<real>20</real>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "NIMUniPlugin",
|
||||
"id": "NIMUniPlugin",
|
||||
"version": "1.1.3",
|
||||
"git": "3ff8678",
|
||||
"buildAt": "7/21/2025, 10:17:00 AM",
|
||||
"description": "uni消息推送插件",
|
||||
"_dp_type": "nativeplugin",
|
||||
"_dp_nativeplugin": {
|
||||
"android": {
|
||||
"plugins": [
|
||||
{
|
||||
"type": "module",
|
||||
"name": "NIMUniPlugin-PluginModule",
|
||||
"class": "com.netease.nimlib.uniapp.push.PushModule"
|
||||
}
|
||||
],
|
||||
"hooksClass": "com.netease.nimlib.uniapp.push.PushModule",
|
||||
"integrateType": "aar",
|
||||
"dependencies": [
|
||||
"com.huawei.hms:push:6.9.0.300",
|
||||
"com.meizu.flyme.internet:push-internal:4.2.3",
|
||||
"com.google.android.gms:play-services-base:18.2.0",
|
||||
"com.google.firebase:firebase-messaging:23.1.2",
|
||||
"com.google.firebase:firebase-core:21.1.1",
|
||||
"com.google.code.gson:gson:2.6.2",
|
||||
"commons-codec:commons-codec:1.6",
|
||||
"com.netease.nimlib:basesdk:9.16.1",
|
||||
"com.netease.nimlib:push:9.16.1"
|
||||
],
|
||||
"compileOptions": {
|
||||
"sourceCompatibility": "1.8",
|
||||
"targetCompatibility": "1.8"
|
||||
},
|
||||
"abis": [
|
||||
"armeabi-v7a",
|
||||
"arm64-v8a",
|
||||
"x86"
|
||||
],
|
||||
"minSdkVersion": "21",
|
||||
"useAndroidX": true,
|
||||
"parameters": {
|
||||
"PUSH_VIVO_APPID": {
|
||||
"des": "厂商VIVO-app_id",
|
||||
"key": "com.vivo.push.app_id"
|
||||
},
|
||||
"PUSH_VIVO_APPKEY": {
|
||||
"des": "厂商VIVO-app_key",
|
||||
"key": "com.vivo.push.api_key"
|
||||
},
|
||||
"PUSH_HONOR_APPID": {
|
||||
"des": "厂商HONOR-app_id",
|
||||
"key": "com.hihonor.push.app_id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ios": {
|
||||
"plugins": [
|
||||
{
|
||||
"type": "module",
|
||||
"name": "NIMUniPlugin-PluginModule",
|
||||
"class": "NIMPluginModule"
|
||||
}
|
||||
],
|
||||
"hooksClass": "NIMPluginProxy",
|
||||
"integrateType": "framework",
|
||||
"deploymentTarget": "9.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -12,12 +12,16 @@
|
||||
"@xkit-yx/utils": "^0.7.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"html2canvas": "^1.4.1",
|
||||
"image-tools": "^1.4.0",
|
||||
"js-base64": "^3.7.8",
|
||||
"js-md5": "^0.8.3",
|
||||
"mobx": "^6.6.1",
|
||||
"nim-web-sdk-ng": "^10.9.30",
|
||||
"nim-web-sdk-ng": "^10.9.50",
|
||||
"pinyin": "^4.0.0",
|
||||
"uview-plus": "^3.4.73"
|
||||
"uni-packing-wgt": "^1.2.3",
|
||||
"uniapp-video-player": "^1.3.0",
|
||||
"uview-plus": "^3.4.73",
|
||||
"vconsole": "^3.15.1"
|
||||
}
|
||||
}
|
||||
|
||||
+1689
-1230
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -30,7 +30,7 @@
|
||||
import { onShow, onLoad, onPageScroll } from "@dcloudio/uni-app";
|
||||
import my_api from '@/api/my_api.js'
|
||||
import docUrl from "@/utils/docUrl.js";
|
||||
|
||||
const app = getApp()
|
||||
// 广告数据
|
||||
const adData = ref({
|
||||
path: '',
|
||||
@@ -59,7 +59,9 @@
|
||||
|
||||
// 如果有广告图片,开始倒计时
|
||||
if (res.data.path) {
|
||||
|
||||
startCountdown();
|
||||
|
||||
} else {
|
||||
// 没有广告,直接跳转到首页
|
||||
navigateToHome();
|
||||
@@ -81,7 +83,9 @@
|
||||
countdown.value--;
|
||||
if (countdown.value <= 0) {
|
||||
clearInterval(timer);
|
||||
navigateToHome();
|
||||
if(app.globalData.plAd){
|
||||
navigateToHome();
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<uni-nav-bar title="继续教育" fixed color="#8B2316" height="140rpx" :border="false" backgroundColor="#eeeeee"></uni-nav-bar>
|
||||
<navBar :title="'继续教育'"></navBar>
|
||||
<view class="page">
|
||||
<!-- 课程列表 -->
|
||||
<view class="course-list">
|
||||
@@ -103,21 +103,22 @@
|
||||
import xueyuanImg from "@/static/ganbingxueyuan.png"
|
||||
import newerImg from "@/static/xinshoujiaocheng.png"
|
||||
import navTo from '@/utils/navTo.js';
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
// 方法
|
||||
// 方法
|
||||
const goToCourse = (courseType) => {
|
||||
console.log('进入课程:', courseType);
|
||||
|
||||
|
||||
// 根据课程类型进行不同的处理
|
||||
switch(courseType) {
|
||||
case 'course':
|
||||
navTo({
|
||||
url: '/pages_course/course/course'
|
||||
uni.sendNativeEvent('goCourse',{
|
||||
msg: 'course'
|
||||
})
|
||||
break;
|
||||
case 'video':
|
||||
navTo({
|
||||
url: '/pages_app/video/video'
|
||||
url: '/pages_app/video/video?from=education'
|
||||
})
|
||||
break;
|
||||
case 'ppt':
|
||||
@@ -166,9 +167,8 @@ $padding-small: 10px;
|
||||
|
||||
.page {
|
||||
background-color: $gray-bg;
|
||||
min-height: calc(100vh - 140rpx);
|
||||
|
||||
padding-bottom: 120rpx;
|
||||
min-height: calc(100vh - var(--status-bar-height) - 44px);
|
||||
margin-top:calc(var(--status-bar-height) + 44px);
|
||||
}
|
||||
|
||||
// 课程列表
|
||||
|
||||
+1029
-553
File diff suppressed because it is too large
Load Diff
+1468
-1130
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<navBar :showLeft="false" :title="'加载中...'"></navBar>
|
||||
<view class="loading-page"></view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted,ref} from 'vue';
|
||||
import { onLoad,onUnload,onHide,onShow } from '@dcloudio/uni-app';
|
||||
import navBar from '@/components/navBar/navBar.vue';
|
||||
const timer=ref(null);
|
||||
const count=ref(0);
|
||||
const countDown=()=>{
|
||||
if(timer.value){
|
||||
return
|
||||
}
|
||||
timer.value=setInterval(()=>{
|
||||
count.value++;
|
||||
if(count.value>=8){
|
||||
clearInterval(timer.value);
|
||||
plus.runtime.quit();
|
||||
}
|
||||
},1000);
|
||||
}
|
||||
onShow(() => {
|
||||
uni.showLoading({
|
||||
title: '加载中...',
|
||||
mask: true
|
||||
});
|
||||
countDown()
|
||||
});
|
||||
|
||||
onUnload(() => {
|
||||
uni.hideLoading();
|
||||
if(timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
});
|
||||
onHide(() => {
|
||||
uni.hideLoading();
|
||||
if(timer.value){
|
||||
clearInterval(timer.value);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.loading-page{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<uni-nav-bar title="肝胆会议" fixed color="#8B2316" height="140rpx" :border="false" backgroundColor="#eeeeee"></uni-nav-bar>
|
||||
<navBar :title="'肝胆会议'"></navBar>
|
||||
<view class="page">
|
||||
<!-- 筛选标签栏 -->
|
||||
<view class="filter-bar">
|
||||
@@ -146,6 +146,7 @@
|
||||
import timeImg from "@/static/play_long.png"
|
||||
import api from '@/api/api';
|
||||
import docUrl from '@/utils/docUrl';
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
// 弹窗状态
|
||||
const isTimePopupShow = ref(false);
|
||||
const isLocationPopupShow = ref(false);
|
||||
|
||||
+181
-23
@@ -1,20 +1,23 @@
|
||||
<template>
|
||||
<uni-nav-bar title="我的" fixed color="#8B2316" height="140rpx" :border="false"
|
||||
backgroundColor="#eeeeee"></uni-nav-bar>
|
||||
<navBar :title="'我的'" :showLeft="false"></navBar>
|
||||
<view class="page">
|
||||
|
||||
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card"
|
||||
:style="{'background-image': `url(${myInfoBackGround || '/static/big_background_my.png'})`, 'background-size':'cover','background-repeat':'no-repeat'}">
|
||||
<view class="user-info" @click="goToPage('myInfo')">
|
||||
<image class="avatar" :src="avatar" mode="aspectFill"></image>
|
||||
<view class="user-info">
|
||||
<image class="avatar" :src="avatar" mode="aspectFill" @click="goToPage('myInfo')"></image>
|
||||
<view class="user-info-content">
|
||||
<text class="username">{{username}}</text>
|
||||
<scroll-view class="honor_box" scroll-x="true" show-scrollbar="false">
|
||||
<view class="honor_wrap">
|
||||
<view class="honor_item" v-for="item in honor_list" :key="item.id">
|
||||
<image class="honor_image" src="/static/wdsc.png" mode="aspectFill"></image>
|
||||
<view class="honor_item" v-if="ranking > 0">
|
||||
<image class="honor_image" :src="suifangImg" mode="aspectFill"></image>
|
||||
<text class="honor_text">随访达人|排名{{ranking}}</text>
|
||||
</view>
|
||||
<view class="honor_item" v-for="item in honor_list" :key="item.id" @click="getHonorDetail(item.id)">
|
||||
<image class="honor_image" :src="rongyu" mode="aspectFill"></image>
|
||||
<text class="honor_text">{{ item.nick_name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -101,9 +104,9 @@
|
||||
<!-- 账户明细 -->
|
||||
<view class="section">
|
||||
<view class="section-title">账户明细</view>
|
||||
<up-scroll-list indicatorActiveColor="#8B2316" indicatorWidth="40rpx" indicatorBarWidth="20rpx"
|
||||
<up-scroll-list :indicator="isAccount" indicatorActiveColor="#8B2316" indicatorWidth="40rpx" indicatorBarWidth="20rpx"
|
||||
class="account-grid">
|
||||
<view class="account-item" @click="goToPage('myAccount')">
|
||||
<view class="account-item" @click="goToPage('myAccount')" v-if="isAccount">
|
||||
<up-image :src="wdzzImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>我的账户</text>
|
||||
</view>
|
||||
@@ -115,11 +118,11 @@
|
||||
<up-image :src="wdflImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>我的福利</text>
|
||||
</view>
|
||||
<view class="account-item" @click="goToPage('myFlower')">
|
||||
<view class="account-item" @click="goToPage('myFlower')" v-if="isAccount">
|
||||
<up-image :src="wdxhImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>我的鲜花</text>
|
||||
</view>
|
||||
<view class="account-item" @click="goToPage('pptDetail')">
|
||||
<view class="account-item" @click="goToPage('pptDetail')" v-if="isAccount">
|
||||
<up-image :src="kjmxImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>课件明细</text>
|
||||
</view>
|
||||
@@ -149,8 +152,8 @@
|
||||
<text>通知已{{notice_on?'开':'关'}}</text>
|
||||
</view>
|
||||
<view class="operation-item" @click="showVersion">
|
||||
<up-image :src="versionImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>V{{version}}</text>
|
||||
<up-image :src="hasNewVersion?versionImgOn:versionImg" width="48rpx" height="48rpx"></up-image>
|
||||
<text>{{hasNewVersion?'有新版本':'V'+version}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -175,7 +178,7 @@
|
||||
|
||||
<!-- 常用银行卡 -->
|
||||
<view class="sectioncell bank-section">
|
||||
<view class="bank-item" @click="goToPage('bankCard')">
|
||||
<view class="bank-item" @click="goToPage('bankCard')" v-if="isAccount">
|
||||
<view class="bank-icon">
|
||||
<up-image :src="cyyhk" width="48rpx" height="48rpx"></up-image>
|
||||
</view>
|
||||
@@ -194,10 +197,12 @@
|
||||
<view class="settings-icon">
|
||||
<up-image :src="settingImg" width="48rpx" height="48rpx"></up-image>
|
||||
</view>
|
||||
<view class="settings-content">
|
||||
<view class="settings-content flex-row" >
|
||||
<text class="settings-title">设置与帮助</text>
|
||||
<text v-if="hasNewVersion && isIos" class="new-version">有新版本</text>
|
||||
</view>
|
||||
<view class="settings-arrow">
|
||||
|
||||
<uni-icons type="forward" size="16" color="#ccc"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
@@ -234,6 +239,29 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</up-overlay>
|
||||
<up-overlay :show="showHonor" >
|
||||
<view class="honorwrap">
|
||||
<view class="honorbox">
|
||||
<image :src="docUrl+honnor_detail.img" class="honor_image"></image>
|
||||
<uni-icons type="close" class="close_honor" size="24" color="#fff" @click="showHonor=false"></uni-icons>
|
||||
<view class="content">
|
||||
<view class="content_title">
|
||||
{{honnor_detail.title}}
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="row_item" v-for="item in honnor_detail.honorlist" :key="item.id">
|
||||
{{ item.nick_name }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="content_content">
|
||||
{{honnor_detail.note}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</up-overlay>
|
||||
</template>
|
||||
@@ -242,12 +270,18 @@
|
||||
import unidialog from '@/components/dialog/dialog.vue'
|
||||
import signImg from "@/static/sign_in_bng_big.png"
|
||||
import CustomTabbar from '@/components/tabBar/tabBar.vue';
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
import {
|
||||
ref,reactive
|
||||
} from 'vue';
|
||||
import {
|
||||
onShow
|
||||
} from "@dcloudio/uni-app";
|
||||
const showHonor=ref(false);
|
||||
import docUrl from "@/utils/docUrl.js"
|
||||
import honnorExpert from "@/static/zixunexpert.png"
|
||||
import honnorYingxiong from "@/static/yingxiongbanglog.png"
|
||||
import rongyu from "@/static/yxb.png"
|
||||
import version from '@/utils/version.js'
|
||||
import hzshImg from "@/static/hzsh.png"
|
||||
import hzfzImg from "@/static/hzfz.png"
|
||||
@@ -269,8 +303,9 @@
|
||||
import ghsjhImg from "@/static/ghsjh.png"
|
||||
import tzykImg from "@/static/xxtx.png"
|
||||
import versionImg from "@/static/fxxbb.png"
|
||||
import versionImgOn from "@/static/fxbb.png"
|
||||
import jifenImg from "@/static/point_buy.png"
|
||||
|
||||
import suifangImg from "@/static/suifang.png"
|
||||
import fulicard from "@/static/fulicard.png"
|
||||
import fpgl from "@/static/fpgl.png"
|
||||
import cyyhk from "@/static/cyhhk.png"
|
||||
@@ -279,6 +314,7 @@
|
||||
import my_api from '@/api/my_api.js'
|
||||
import navTo from "@/utils/navTo"
|
||||
import linkUrl from "@/utils/docUrl"
|
||||
|
||||
// 响应式数据
|
||||
const isLargeFont = ref(false);
|
||||
const hasSign = ref(false)
|
||||
@@ -298,8 +334,25 @@
|
||||
const totalPoints = ref(0)
|
||||
const sign_in = ref(0)
|
||||
const honor_list = ref([])
|
||||
const ranking = ref(0)
|
||||
|
||||
const notice_on = ref(false)
|
||||
const hasNewVersion = ref(false)
|
||||
const checkVersion=()=>{
|
||||
api.checkVersion().then(res=>{
|
||||
if(res.code==80002){
|
||||
hasNewVersion.value=true
|
||||
}
|
||||
})
|
||||
}
|
||||
const isAccount = ref(false);
|
||||
const getIsAccount=()=>{
|
||||
api.getIsAccount().then(res=>{
|
||||
if(res.code==1){
|
||||
isAccount.value=res.is_account==0?false:true;
|
||||
}
|
||||
})
|
||||
}
|
||||
const goNews=()=>{
|
||||
let url=docUrl+signInfo.news.path;
|
||||
// #ifdef H5
|
||||
@@ -376,6 +429,7 @@
|
||||
totalPoints.value = data.total_points || 0
|
||||
sign_in.value = data.sign_in || 0
|
||||
honor_list.value = data.honor_list || []
|
||||
ranking.value = data.ranking || 0
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取我的信息失败', e)
|
||||
@@ -469,7 +523,7 @@
|
||||
url="/pages_app/changeMobile/changeMobile"
|
||||
break;
|
||||
case 'benefitExchange':
|
||||
url="/pages_app/myWelfareCard/myWelfareCard"
|
||||
url="/pages_app/myWelfareCard/myWelfareCard?from=my"
|
||||
break;
|
||||
case 'bankCard':
|
||||
url="/pages_app/idcardAuth/bankCardList"
|
||||
@@ -629,7 +683,16 @@ const switchPushPermissions = () => {
|
||||
showCancel: false
|
||||
});
|
||||
};
|
||||
|
||||
const honnor_detail=ref({});
|
||||
const getHonorDetail=async(id)=>{
|
||||
const res = await api.gethonorDetail({
|
||||
id:id
|
||||
})
|
||||
if (res.code == 1 ) {
|
||||
honnor_detail.value = res.data;
|
||||
showHonor.value = true;
|
||||
}
|
||||
}
|
||||
const onStatsClick = (key) => {
|
||||
let url = '';
|
||||
switch (key) {
|
||||
@@ -661,13 +724,23 @@ const switchPushPermissions = () => {
|
||||
isBoundWechat.value = res.data
|
||||
}
|
||||
}
|
||||
const isBoundWechat = ref(false)
|
||||
const isBoundWechat = ref(false);
|
||||
const isIos = ref(false);
|
||||
onShow(() => {
|
||||
console.log('我的页面显示');
|
||||
getUserInfoFromStorage() // 先从storage获取用户信息
|
||||
fetchMyInfo() // 然后从API获取最新数据
|
||||
getIsBoundWechat()
|
||||
isNoticeOn()
|
||||
isNoticeOn();
|
||||
checkVersion();
|
||||
getIsAccount();
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
console.log(systemInfo)
|
||||
if(systemInfo.osName == 'ios'){
|
||||
isIos.value = true;
|
||||
}else{
|
||||
isIos.value = false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -691,11 +764,91 @@ const switchPushPermissions = () => {
|
||||
|
||||
.page {
|
||||
background-color: $gray-bg;
|
||||
height: calc(100vh - 140rpx);
|
||||
margin-top:calc(var(--status-bar-height) + 44px);
|
||||
height: calc(100vh - var(--status-bar-height) - 44px);
|
||||
overflow-y: scroll;
|
||||
padding-bottom: 100rpx;
|
||||
}
|
||||
|
||||
.flex-row{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.new-version{
|
||||
background:#8B2316;
|
||||
color:#fff;
|
||||
font-size: 24rpx;
|
||||
margin-right: 10rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
.honorwrap{
|
||||
width:100%;
|
||||
height:100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.honorbox{
|
||||
|
||||
width:80%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
min-height:200rpx;
|
||||
background:linear-gradient(to bottom, #54049b, #da4ee2);
|
||||
border-radius: 20rpx;
|
||||
padding: 20rpx;
|
||||
.row{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr); /* 创建两列,每列等宽 */
|
||||
gap: 20px;
|
||||
.row_item{
|
||||
font-size: 26rpx;
|
||||
color: #da4ee2;
|
||||
margin-right: 20rpx;
|
||||
text-align: center;
|
||||
padding: 10rpx 20rpx;
|
||||
background:#fff;
|
||||
white-space: nowrap;
|
||||
border-radius: 10rpx;
|
||||
border:1rpx solid #da4ee2;
|
||||
}
|
||||
}
|
||||
.close_honor{
|
||||
position: absolute;
|
||||
top:20rpx;
|
||||
right:20rpx;
|
||||
}
|
||||
.honor_image{
|
||||
width:269rpx;
|
||||
height:213rpx;
|
||||
position: absolute;
|
||||
top:-76rpx;
|
||||
left:50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.content{
|
||||
margin-top:73rpx;
|
||||
background:#fff;
|
||||
border-radius: 5rpx;
|
||||
padding: 20rpx;
|
||||
.content_title{
|
||||
font-weight: bold;
|
||||
padding: 35rpx 0 20rpx;
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
color: #da4ee2;
|
||||
}
|
||||
.content_content{
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
margin-top: 20rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.signwrap{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -777,7 +930,6 @@ const switchPushPermissions = () => {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 10rpx;
|
||||
|
||||
}
|
||||
|
||||
.user-info-content {
|
||||
@@ -785,6 +937,7 @@ const switchPushPermissions = () => {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10rpx;
|
||||
margin-left: 10rpx;
|
||||
|
||||
.username {
|
||||
color: $white;
|
||||
@@ -825,6 +978,11 @@ const switchPushPermissions = () => {
|
||||
.honor_text {
|
||||
font-size: 24rpx;
|
||||
color: $white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.bar_rank{
|
||||
padding:0 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<uni-nav-bar title="患教学堂" fixed color="#8B2316" height="140rpx" :border="false" backgroundColor="#eeeeee"></uni-nav-bar>
|
||||
<navBar :title="'患教学堂'" :showLeft="false"></navBar>
|
||||
<view class="page">
|
||||
<!-- 顶部标题栏 -->
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
<view class="tab-item" :class="{ active: activeTab === 0 }" @click="switchTab(0)">
|
||||
患教文库
|
||||
</view>
|
||||
<view class="bar"></view>
|
||||
<view class="tab-item" :class="{ active: activeTab === 1 }" @click="switchTab(1)">
|
||||
患教视频
|
||||
</view>
|
||||
<view class="tab-item" :class="{ active: activeTab === 2 }" @click="switchTab(2)">
|
||||
<!-- <view class="tab-item" :class="{ active: activeTab === 2 }" @click="switchTab(2)">
|
||||
常见问题
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 筛选栏 -->
|
||||
@@ -51,7 +52,7 @@
|
||||
:class="{ active: tag.selected }"
|
||||
@click="toggleTag(index)"
|
||||
>
|
||||
{{ tag.DES }}
|
||||
{{ tag.NAME }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -74,20 +75,20 @@
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<view class="article-item" v-for="(article, index) in articleList" :key="article.uuid || index" @click="goToDetail(article)">
|
||||
<image class="article-image" :src="article.image" mode="aspectFill"></image>
|
||||
<image class="article-image" :src="article.image"></image>
|
||||
<view class="article-content">
|
||||
<view class="article-title">{{ article.title }}</view>
|
||||
<view class="article-meta">
|
||||
<view class="date-tag" v-if="article.isToday">今日</view>
|
||||
<view class="date" v-else>{{ article.date }}</view>
|
||||
<view class="stats">
|
||||
<view class="stat-item">
|
||||
<view class="stat-item readnum">
|
||||
<uni-icons type="eye" size="12" color="#999"></uni-icons>
|
||||
<text>{{ article.views }}</text>
|
||||
<text>{{ formatNumber(article.views) }}</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<uni-icons type="hand-up" size="13" color="#999"></uni-icons>
|
||||
<text>{{ article.likes }}</text>
|
||||
<text>{{ formatNumber(article.likes) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -107,8 +108,9 @@
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="articleList.length === 0 && !loading">
|
||||
<uni-icons type="article" size="80" color="#cccccc"></uni-icons>
|
||||
<text class="empty-text">暂无文章</text>
|
||||
<empty :emptyDesc="'暂无患教信息'"></empty>
|
||||
<!-- <uni-icons type="article" size="80" color="#cccccc"></uni-icons>
|
||||
<text class="empty-text">暂无文章</text> -->
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
@@ -120,7 +122,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import {onShow,onLoad,onBackPress } from "@dcloudio/uni-app";
|
||||
import CustomTabbar from '@/components/tabBar/tabBar.vue';
|
||||
import upImg from "@/static/cb_up.png"
|
||||
import downImg from "@/static/cb_up.png"
|
||||
@@ -129,9 +131,24 @@
|
||||
import api from "@/api/api.js"
|
||||
import docUrl from '@/utils/docUrl.js';
|
||||
import navTo from '@/utils/navTo.js';
|
||||
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
import formatNumber from '@/utils/formatNumber.js';
|
||||
const type=ref(1)
|
||||
|
||||
onBackPress(() => {
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
});
|
||||
onLoad(() => {
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "患教文库",
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
})
|
||||
// 分页相关状态
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
@@ -147,7 +164,8 @@
|
||||
// 重置分页状态
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
polularScienceArticleListByKeywordsNew(true);
|
||||
articleList.value = [];
|
||||
polularScienceArticleListByKeywordsNew(false);
|
||||
};
|
||||
const loadGuideTags = async () => {
|
||||
try {
|
||||
@@ -195,9 +213,9 @@
|
||||
// 判断是否还有更多数据
|
||||
hasMore.value = newData.length >= pageSize.value;
|
||||
|
||||
if (!isRefresh) {
|
||||
currentPage.value++;
|
||||
}
|
||||
// if (!isRefresh) {
|
||||
// currentPage.value++;
|
||||
// }
|
||||
|
||||
console.log('文章数据加载成功:', articleList.value);
|
||||
}
|
||||
@@ -240,9 +258,18 @@
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date) => {
|
||||
const today = new Date();
|
||||
const year = date.getFullYear();
|
||||
const currentYear = today.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
return `${month}-${day}`;
|
||||
|
||||
// 如果年份是今年,只显示月日,否则显示年月日
|
||||
if (year === currentYear) {
|
||||
return `${month}-${day}`;
|
||||
} else {
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
};
|
||||
// 筛选标签数据
|
||||
const filterTags = ref([]);
|
||||
@@ -255,12 +282,12 @@
|
||||
|
||||
if(index==1){
|
||||
navTo({
|
||||
url: '/pages_app/patientVideo/patientVideo'
|
||||
url: '/pages_app/patientVideo/patientVideo?from=patientClass'
|
||||
})
|
||||
}else if(index==2){
|
||||
let url=encodeURIComponent('https://wx.igandan.com/wxPatient/index.htm#/problem?link=share&fromtype=doctor')
|
||||
navTo({
|
||||
url: '/pages_app/webview/webview?url='+url
|
||||
url: '/pages_app/webview/webview?url='+url+'&title='+'常见问题'
|
||||
})
|
||||
}
|
||||
};
|
||||
@@ -270,15 +297,15 @@
|
||||
// 跳转到详情页
|
||||
if (article.path) {
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/webview/webview?url=${encodeURIComponent(docUrl+article.path)}&title=${encodeURIComponent(article.title)}`
|
||||
url: `/pages_app/webview/webviewClass?url=${encodeURIComponent(docUrl+article.path+'?fromtype=doctor')}&title=患教详情&uuid=${article.uuid}&sharetitle=${article.title}&summary=${article.summary}&type=huanjiao&imgPath=${encodeURIComponent(article.image)}&tags=${article.tags}`
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到搜索页面
|
||||
const goToSearch = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/search/search'
|
||||
uni.sendNativeEvent('goHomeSearch',{
|
||||
msg: 'patientClass'
|
||||
});
|
||||
};
|
||||
|
||||
@@ -296,6 +323,7 @@
|
||||
// 上拉加载更多
|
||||
const onLoadMore = async () => {
|
||||
if (!hasMore.value || loading.value) return;
|
||||
currentPage.value++
|
||||
await polularScienceArticleListByKeywordsNew(false);
|
||||
};
|
||||
|
||||
@@ -319,7 +347,19 @@
|
||||
};
|
||||
|
||||
const toggleTag = (index) => {
|
||||
filterTags.value[index].selected = !filterTags.value[index].selected;
|
||||
const tag = filterTags.value[index];
|
||||
// 若当前为未选中状态,且已选满3个,则禁止再选
|
||||
if (!tag.selected) {
|
||||
const selectedCount = filterTags.value.filter(t => t.selected).length;
|
||||
if (selectedCount >= 3) {
|
||||
uni.showToast({
|
||||
title: '最多选择3个标签',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
tag.selected = !tag.selected;
|
||||
};
|
||||
|
||||
const resetFilter = () => {
|
||||
@@ -333,25 +373,26 @@
|
||||
// 检查是否有选中的标签
|
||||
const hasSelected = filterTags.value.some(tag => tag.selected);
|
||||
isFilterActive.value = hasSelected;
|
||||
|
||||
let words='';
|
||||
// 执行筛选逻辑
|
||||
if (hasSelected) {
|
||||
const selectedTags = filterTags.value.filter(tag => tag.selected).map(tag => tag.DES);
|
||||
const selectedTags = filterTags.value.filter(tag => tag.selected).map(tag => tag.NAME);
|
||||
console.log('选中的标签:', selectedTags);
|
||||
keywords.value = selectedTags.join(',');
|
||||
words = selectedTags.join(',');
|
||||
} else {
|
||||
keywords.value = '';
|
||||
words = '';
|
||||
}
|
||||
|
||||
keywords.value = words;
|
||||
// 重置分页状态
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
|
||||
articleList.value = [];
|
||||
showFilter.value = false;
|
||||
polularScienceArticleListByKeywordsNew(true);
|
||||
polularScienceArticleListByKeywordsNew(false);
|
||||
};
|
||||
|
||||
onShow(() => {
|
||||
|
||||
polularScienceArticleListByKeywordsNew(true);
|
||||
loadGuideTags();
|
||||
});
|
||||
@@ -369,14 +410,14 @@ $gray-dark: #666;
|
||||
$text-color: #333;
|
||||
|
||||
// 尺寸变量
|
||||
$border-radius: 8px;
|
||||
$border-radius-small: 6px;
|
||||
$padding: 15px;
|
||||
$padding-small: 10px;
|
||||
$border-radius: 16rpx;
|
||||
$border-radius-small: 12rpx;
|
||||
$padding: 30rpx;
|
||||
$padding-small: 20rpx;
|
||||
|
||||
.page {
|
||||
background-color: $gray-bg;
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
display: flex;
|
||||
overflow-y: hidden;
|
||||
flex-direction: column;
|
||||
@@ -385,19 +426,25 @@ $padding-small: 10px;
|
||||
.top{
|
||||
width:100%;
|
||||
position: fixed;
|
||||
top:140rpx;
|
||||
top:calc(var(--status-bar-height) + 44px);
|
||||
}
|
||||
// 选项卡
|
||||
.tabs {
|
||||
background-color: $white;
|
||||
display: flex;
|
||||
border-bottom: 1px solid $gray-light;
|
||||
|
||||
align-items: center;
|
||||
border-bottom: 2rpx solid $gray-light;
|
||||
.bar{
|
||||
width: 2rpx;
|
||||
height: 98rpx;
|
||||
background-color: $gray-light;
|
||||
|
||||
}
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
padding: $padding 0;
|
||||
font-size: 16px;
|
||||
font-size: 32rpx;
|
||||
color: $gray-dark;
|
||||
position: relative;
|
||||
|
||||
@@ -411,8 +458,8 @@ $padding-small: 10px;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 30px;
|
||||
height: 2px;
|
||||
width: 60rpx;
|
||||
height: 4rpx;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -425,25 +472,25 @@ $padding-small: 10px;
|
||||
padding: $padding-small $padding;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid $gray-light;
|
||||
border-bottom: 2rpx solid $gray-light;
|
||||
|
||||
.search-box {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
gap: 10rpx;
|
||||
|
||||
.search-text {
|
||||
font-size: 14px;
|
||||
font-size: 28rpx;
|
||||
color: $gray-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 1px;
|
||||
height: 16px;
|
||||
background-color: $gray-medium;
|
||||
width: 2rpx;
|
||||
height: 32rpx;
|
||||
background-color: $gray-light;
|
||||
margin: 0 $padding;
|
||||
}
|
||||
|
||||
@@ -452,8 +499,8 @@ $padding-small: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
font-size: 14px;
|
||||
gap: 6rpx;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
@@ -466,23 +513,24 @@ $padding-small: 10px;
|
||||
// 文章列表
|
||||
.article-list {
|
||||
position: fixed;
|
||||
height:calc(100vh - 450rpx);
|
||||
top: 342rpx;
|
||||
// height:calc(100vh - var(--status-bar-height) - 44px - 207rpx);
|
||||
top: calc(var(--status-bar-height) + 44px + 188rpx);
|
||||
|
||||
padding-bottom: 130rpx;
|
||||
bottom: 128rpx;
|
||||
.article-item {
|
||||
background-color: $white;
|
||||
margin-bottom: $padding-small;
|
||||
border-radius: $border-radius;
|
||||
padding: $padding;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
|
||||
|
||||
.article-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
width: 260rpx;
|
||||
height: 160rpx;
|
||||
border-radius: $border-radius-small;
|
||||
flex-shrink: 0;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.article-content {
|
||||
@@ -492,7 +540,7 @@ $padding-small: 10px;
|
||||
justify-content: space-between;
|
||||
|
||||
.article-title {
|
||||
font-size: 16px;
|
||||
font-size: 32rpx;
|
||||
color: $text-color;
|
||||
line-height: 1.4;
|
||||
margin-bottom: $padding-small;
|
||||
@@ -506,32 +554,40 @@ $padding-small: 10px;
|
||||
|
||||
.article-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.date-tag {
|
||||
background-color: $primary-color;
|
||||
color: $white;
|
||||
font-size: 12px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 24rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 6rpx;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 12px;
|
||||
width: 125rpx;
|
||||
font-size: 24rpx;
|
||||
color: $gray-medium;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: flex;
|
||||
gap: $padding;
|
||||
|
||||
margin-left: 50rpx;
|
||||
.readnum{
|
||||
width:100rpx;
|
||||
}
|
||||
.stat-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
font-size: 12px;
|
||||
gap: 10rpx;
|
||||
|
||||
font-size: 24rpx;
|
||||
color: $gray-medium;
|
||||
text{
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -591,8 +647,8 @@ $padding-small: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
font-size: 12px;
|
||||
gap: 4rpx;
|
||||
font-size: 24rpx;
|
||||
color: $gray-medium;
|
||||
|
||||
&.active {
|
||||
@@ -600,7 +656,7 @@ $padding-small: 10px;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 10px;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +675,7 @@ $padding-small: 10px;
|
||||
z-index: 9999;
|
||||
|
||||
.filter-content {
|
||||
margin-top:329rpx;
|
||||
margin-top:calc(var(--status-bar-height) + 44px + 188rpx);;
|
||||
|
||||
background-color: $white;
|
||||
// border-radius: 20rpx 20rpx 0 0;
|
||||
@@ -630,17 +686,21 @@ $padding-small: 10px;
|
||||
.filter-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 60rpx;
|
||||
max-height: 65vh;
|
||||
overflow-y: auto;
|
||||
|
||||
.tag-item {
|
||||
background-color: #f8f8f8;
|
||||
color: $gray-dark;
|
||||
padding: 8rpx 24rpx;
|
||||
padding: 8rpx 0rpx;
|
||||
width:152rpx;
|
||||
margin:8rpx;
|
||||
text-align:center;
|
||||
border-radius: 30rpx;
|
||||
font-size: 26rpx;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
border: 2rpx solid #efefef;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { onShow, onLoad } from "@dcloudio/uni-app";
|
||||
|
||||
// 页面加载
|
||||
onLoad(() => {
|
||||
console.log('登录页面加载完成');
|
||||
// #ifdef APP
|
||||
|
||||
console.log('一键登录');
|
||||
uni.login({
|
||||
provider: 'univerify',
|
||||
univerifyStyle: {
|
||||
"fullScreen": true, // 是否全屏显示,默认值: false
|
||||
"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff
|
||||
"backgroundImage": "", // 全屏显示的背景图片,默认值:"" (仅支持本地图片,只有全屏显示时支持)
|
||||
"icon": {
|
||||
"path": "static/xxx.png", // 自定义显示在授权框中的logo,仅支持本地图片 默认显示App logo
|
||||
"width": "60px", //图标宽度 默认值:60px
|
||||
"height": "60px" //图标高度 默认值:60px
|
||||
},
|
||||
"closeIcon": {
|
||||
"path": "static/xxx.png", // 自定义显示在授权框中的logo,仅支持本地图片
|
||||
"width": "60px", //图标宽度 默认值:60px (HBuilderX 4.0+ 仅iOS支持)
|
||||
"height": "60px" //图标高度 默认值:60px (HBuilderX 4.0+ 仅iOS支持)
|
||||
},
|
||||
"phoneNum": {
|
||||
"color": "#202020" // 手机号文字颜色 默认值:#202020
|
||||
},
|
||||
"slogan": {
|
||||
"color": "#BBBBBB" // slogan 字体颜色 默认值:#BBBBBB
|
||||
},
|
||||
"authButton": {
|
||||
"normalColor": "#3479f5", // 授权按钮正常状态背景颜色 默认值:#3479f5
|
||||
"highlightColor": "#2861c5", // 授权按钮按下状态背景颜色 默认值:#2861c5(仅ios支持)
|
||||
"disabledColor": "#73aaf5", // 授权按钮不可点击时背景颜色 默认值:#73aaf5(仅ios支持)
|
||||
"textColor": "#ffffff", // 授权按钮文字颜色 默认值:#ffffff
|
||||
"title": "本机号码一键登录", // 授权按钮文案 默认值:“本机号码一键登录”
|
||||
"borderRadius": "24px" // 授权按钮圆角 默认值:"24px" (按钮高度的一半)
|
||||
},
|
||||
"otherLoginButton": {
|
||||
"visible": true, // 是否显示其他登录按钮,默认值:true
|
||||
"normalColor": "", // 其他登录按钮正常状态背景颜色 默认值:透明
|
||||
"highlightColor": "", // 其他登录按钮按下状态背景颜色 默认值:透明
|
||||
"textColor": "#656565", // 其他登录按钮文字颜色 默认值:#656565
|
||||
"title": "其他登录方式", // 其他登录方式按钮文字 默认值:“其他登录方式”
|
||||
"borderColor": "", //边框颜色 默认值:透明(仅iOS支持)
|
||||
"borderRadius": "0px" // 其他登录按钮圆角 默认值:"24px" (按钮高度的一半)
|
||||
},
|
||||
"privacyTerms": {
|
||||
"defaultCheckBoxState": true, // 条款勾选框初始状态 默认值: true
|
||||
"isCenterHint": false, //未勾选服务条款时点击登录按钮的提示是否居中显示 默认值: false (3.7.13+ 版本支持)
|
||||
"uncheckedImage": "", // 可选 条款勾选框未选中状态图片(仅支持本地图片 建议尺寸 24x24px)(3.2.0+ 版本支持)
|
||||
"checkedImage": "", // 可选 条款勾选框选中状态图片(仅支持本地图片 建议尺寸24x24px)(3.2.0+ 版本支持)
|
||||
"checkBoxSize": 12, // 可选 条款勾选框大小
|
||||
"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB
|
||||
"termsColor": "#5496E3", // 协议文字颜色 默认值: #5496E3
|
||||
"prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”
|
||||
"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”
|
||||
"privacyItems": [ // 自定义协议条款,最大支持2个,需要同时设置url和title. 否则不生效
|
||||
{
|
||||
"url": "https://", // 点击跳转的协议详情页面
|
||||
"title": "用户服务协议" // 协议名称
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
success(res) { // 登录成功
|
||||
console.log(res.authResult); // {openid:'登录授权唯一标识',access_token:'接口返回的 token'}
|
||||
},
|
||||
fail(res) { // 登录失败
|
||||
console.log(res.errCode)
|
||||
console.log(res.errMsg)
|
||||
uni.redirectTo({
|
||||
url: '/pages_app/login/login?univerify=0'
|
||||
});
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
});
|
||||
|
||||
// 页面显示
|
||||
onShow(() => {
|
||||
console.log('登录页面显示');
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view class="wrap">
|
||||
<view :class="isFull ? 'player-full' : 'player'">
|
||||
<plv-player
|
||||
ref="vodPlayer"
|
||||
class="vod-player"
|
||||
seekType=1
|
||||
autoPlay=true
|
||||
disableScreenCAP=false
|
||||
rememberLastPosition=false
|
||||
@onPlayStatus="onPlayStatus"
|
||||
@onPlayError="onPlayError"
|
||||
@positionChange="positionChange"
|
||||
@onEnableSubtitle="onEnableSubtitle"
|
||||
@onSRTTextConfig="onSRTTextConfig"
|
||||
@onSRTTitle="onSRTTitle">
|
||||
</plv-player>
|
||||
<skin ref="skinRef"
|
||||
class="skin-control"
|
||||
:defaultVolume="defaultVolume"
|
||||
@onPlayBtnClick="onPlayBtnClick"
|
||||
@onToSeek="onToSeek"
|
||||
@onFullBtnClick="onFullBtnClick"
|
||||
@onHdBtnClick="onHdBtnClick"
|
||||
@onRateBtnClick="onRateBtnClick"
|
||||
@onVolumeChanged="onVolumeChanged"
|
||||
@onScalingBtnClick="onScalingBtnClick"
|
||||
@onScreenShot="onScreenShot"
|
||||
@onChangeSRTBtnClick="onChangeSRTBtnClick"
|
||||
@onChangeSRTSingleMode="onChangeSRTSingleMode"
|
||||
@onOpenSRT="onOpenSRT">
|
||||
</skin>
|
||||
</view>
|
||||
<view v-if="!isFull" style="padding: 20rpx;">
|
||||
<input class="uni-input" style="min-height: 35px; height: 35px; border: 1px solid #cccccc;font-size: 14px;" :value="videoVid"
|
||||
@input="onVidInput" placeholder="请输入视频vid" />
|
||||
<button type="primary" @click="setVid()">播放</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
//import Head from '../../components/page-head.nvue';
|
||||
//import skin from '@/components/plv-player-skin/skin.nvue';
|
||||
//import DragTips from '@/components/plv-player-skin/drag-tips.nvue';
|
||||
const dom = weex.requireModule('dom');
|
||||
var configModule = uni.requireNativePlugin("PLV-VodUniPlugin-ConfigModule")
|
||||
const vod=ref(null);
|
||||
|
||||
const title='播放器Demo';
|
||||
// 播放器组件
|
||||
const vodPlayer=ref(null);
|
||||
const skinRef=ref(null);
|
||||
const isFull=ref(false);
|
||||
const defaultVolume=ref(0.5);
|
||||
const videoVid=ref('4ae3fe3ab5a2009a8d6605d81b2e3c9b_4');
|
||||
|
||||
onShow(() => {
|
||||
configModule.setConfig({
|
||||
'config': "dDzXiPJ8psA/7LvtlPgpNfdOjzKVVEYvca1QBOp2MqCVKC93YiligqqfzOzETkDmolLNBUF4vAykBuUnn+U4V9NoK9vaofwESluIMO9WSB0eWhrw+fBkn+h+OZAmwmYgHQ6fCtsggZKN6cW/FhjWAQ==", //加密串配置
|
||||
},
|
||||
(ret) => {
|
||||
if (ret.isSuccess == true) {
|
||||
uni.showToast({
|
||||
title: '设置加密串成功',
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
const onVidInput=(event)=> {
|
||||
videoVid.value = event.detail.value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const setVid=()=> {
|
||||
if(!videoVid.value) {
|
||||
uni.showToast({
|
||||
title: "请输入视频Vid",
|
||||
icon: "none"
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
vodPlayer.value.setVid({
|
||||
vid:videoVid.value,
|
||||
level:0
|
||||
}, (ret) => {
|
||||
console.log(12)
|
||||
console.log(ret)
|
||||
text.value = JSON.stringify(ret);
|
||||
if (ret.errMsg != null) {
|
||||
uni.showToast({
|
||||
title: ret.errMsg,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onPlayError=(e)=>{
|
||||
console.log(e);
|
||||
if (e.detail.errEvent != null) {
|
||||
uni.showToast({
|
||||
title:'playErrorEvent - '+e.detail.errEvent,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const positionChange=(e)=>{
|
||||
skinRef.value.timeUpdate(e.detail.currentPosition);
|
||||
};
|
||||
|
||||
const onEnableSubtitle=(e)=>{
|
||||
console.log("===1" + e.detail);
|
||||
skinRef.value.setEnableSubtitle(e.detail.isEnableSubtitle, e.detail.isEnableDoubleSubtitle);
|
||||
};
|
||||
|
||||
const onSRTTextConfig=(e)=>{
|
||||
console.log("===1 fontColor: " + e.detail.fontColor);
|
||||
skinRef.value.setSRTTextConfig(e.detail);
|
||||
};
|
||||
|
||||
const onSRTTitle=(e)=>{
|
||||
console.log("===1 onSRTTitle" + e.detail);
|
||||
|
||||
};
|
||||
|
||||
const onPlayStatus=(e)=>{
|
||||
//const { skin, vodPlayer } = this;
|
||||
const state = e.detail.playbackState;
|
||||
const preparedToPlay = e.detail.preparedToPlay;
|
||||
if (state != null) {
|
||||
skinRef.value.changePlayStatus(state === 'start');
|
||||
} else if (preparedToPlay != null) {
|
||||
updateDuration();
|
||||
updateLevels();
|
||||
updateScaling();
|
||||
}
|
||||
};
|
||||
|
||||
const updateDuration=()=> {
|
||||
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.getDuration(null, ret => {
|
||||
skinRef.value.updateDuration(ret.duration);
|
||||
});
|
||||
};
|
||||
|
||||
const updateLevels=()=> {
|
||||
if (vodPlayer.value) return;
|
||||
|
||||
vodPlayer.value.getLevelNum(null, ret => {
|
||||
skinRef.value.updateLevels(ret.levelNum);
|
||||
});
|
||||
|
||||
vodPlayer.value.getCurrentLevel(null, ret => {
|
||||
skinRef.value.updateCurrentLevel(ret.currentLevel);
|
||||
});
|
||||
};
|
||||
|
||||
const updateScaling=()=> {
|
||||
if (vodPlayer.value) return;
|
||||
|
||||
vodPlayer.value.getScalingMode({}, ret => {
|
||||
skinRef.value.updateScaling(ret.scalingMode);
|
||||
});
|
||||
};
|
||||
|
||||
const onPlayBtnClick=(isPlaying)=> {
|
||||
if (vodPlayer.value) return;
|
||||
isPlaying ? vodPlayer.value.start() : vodPlayer.value.pause();
|
||||
};
|
||||
|
||||
const onHdBtnClick=(level)=> {
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.changeLevel({level});
|
||||
};
|
||||
|
||||
const onRateBtnClick=(speed)=> {
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.setSpeed({speed});
|
||||
};
|
||||
|
||||
const onScalingBtnClick=(scalingMode)=> {
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.setScalingMode({scalingMode});
|
||||
};
|
||||
|
||||
const onChangeSRTBtnClick=(srt)=> {
|
||||
console.log("===1 " + srt);
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.changeSRT(srt);
|
||||
};
|
||||
|
||||
const onChangeSRTSingleMode=(isSingle)=> {
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.changeSRTSingleMode(isSingle);
|
||||
};
|
||||
|
||||
const onOpenSRT=(isOpen)=> {
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.setOpenSRT({
|
||||
openSrt: isOpen
|
||||
});
|
||||
};
|
||||
|
||||
const onFullBtnClick=(isFull)=> {
|
||||
// plus.screen.unlockOrientation();
|
||||
plus.navigator.setFullscreen(isFull);
|
||||
if (vodPlayer.value) return;
|
||||
isFull ? vodPlayer.value.changeToLandscape() : vodPlayer.value.changeToPortrait();
|
||||
isFull.value = isFull;
|
||||
};
|
||||
|
||||
const onToSeek=(time)=> {
|
||||
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.seekTo({seconds: time});
|
||||
};
|
||||
|
||||
const onVolumeChanged=(value)=> {
|
||||
|
||||
if (vodPlayer.value) return;
|
||||
vodPlayer.value.getVolume(null, ret => {
|
||||
const changedValue = ret.volume + value;
|
||||
|
||||
const realValue =limit(changedValue, 0, 1);
|
||||
|
||||
vodPlayer.value.setVolume({volume: realValue});
|
||||
|
||||
skinRef.value.updateVolumeValue(realValue);
|
||||
});
|
||||
};
|
||||
|
||||
const onScreenShot=()=> {
|
||||
if (vodPlayer.value) return;
|
||||
|
||||
vodPlayer.value.snapshot(null, result =>{
|
||||
if(result.errMsg != null){
|
||||
console.log(result.errMsg)
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 控制最小值,最大值
|
||||
* @param num
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns {*}
|
||||
*/
|
||||
const limit=(num, min, max)=> {
|
||||
if (num < min) return min;
|
||||
if (num > max) return max;
|
||||
return num;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wrap {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.player {
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
.player-full {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.vod-player {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.skin-control {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hide {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<view class="wrap">
|
||||
<view :class="isFull ? 'player-full' : 'player'">
|
||||
<plv-player
|
||||
ref="vod"
|
||||
class="vod-player"
|
||||
seekType=1
|
||||
autoPlay=true
|
||||
disableScreenCAP=false
|
||||
rememberLastPosition=false
|
||||
@onPlayStatus="onPlayStatus"
|
||||
@onPlayError="onPlayError"
|
||||
@positionChange="positionChange"
|
||||
@onEnableSubtitle="onEnableSubtitle"
|
||||
@onSRTTextConfig="onSRTTextConfig"
|
||||
@onSRTTitle="onSRTTitle">
|
||||
</plv-player>
|
||||
<Skin ref="skin"
|
||||
class="skin-control"
|
||||
:defaultVolume="defaultVolume"
|
||||
@onPlayBtnClick="onPlayBtnClick"
|
||||
@onToSeek="onToSeek"
|
||||
@onFullBtnClick="onFullBtnClick"
|
||||
@onHdBtnClick="onHdBtnClick"
|
||||
@onRateBtnClick="onRateBtnClick"
|
||||
@onVolumeChanged="onVolumeChanged"
|
||||
@onScalingBtnClick="onScalingBtnClick"
|
||||
@onScreenShot="onScreenShot"
|
||||
@onChangeSRTBtnClick="onChangeSRTBtnClick"
|
||||
@onChangeSRTSingleMode="onChangeSRTSingleMode"
|
||||
@onOpenSRT="onOpenSRT">
|
||||
</Skin>
|
||||
</view>
|
||||
<view v-if="!isFull" style="padding: 20rpx;">
|
||||
<input class="uni-input" style="min-height: 35px; height: 35px; border: 1px solid #cccccc;font-size: 14px;" :value="videoVid"
|
||||
@input="onVidInput" placeholder="请输入视频vid" />
|
||||
<button type="primary" @click="setVid()">播放</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
//import Head from '../../components/page-head.nvue';
|
||||
import Skin from '@/components/plv-player-skin2/skin.nvue';
|
||||
//import DragTips from '@/components/plv-player-skin/drag-tips.nvue';
|
||||
const dom = weex.requireModule('dom');
|
||||
var configModule = uni.requireNativePlugin("PLV-VodUniPlugin-ConfigModule")
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Skin,
|
||||
//Head
|
||||
},
|
||||
|
||||
onReady() {
|
||||
configModule.setConfig({
|
||||
'config': "dDzXiPJ8psA/7LvtlPgpNfdOjzKVVEYvca1QBOp2MqCVKC93YiligqqfzOzETkDmolLNBUF4vAykBuUnn+U4V9NoK9vaofwESluIMO9WSB0eWhrw+fBkn+h+OZAmwmYgHQ6fCtsggZKN6cW/FhjWAQ==", //加密串配置
|
||||
},
|
||||
(ret) => {
|
||||
if (ret.isSuccess == true) {
|
||||
uni.showToast({
|
||||
title: '设置加密串成功',
|
||||
icon: "none"
|
||||
})
|
||||
} else {
|
||||
let errMsg = ret.errMsg;
|
||||
uni.showToast({
|
||||
title: '设置加密串失败:' + errMsg,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
})
|
||||
this.vodPlayer = this.$refs.vod;
|
||||
this.skin = this.$refs.skin;
|
||||
// plus.screen.lockOrientation('portrait-primary');
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
title: '播放器Demo',
|
||||
// 播放器组件
|
||||
vodPlayer: null,
|
||||
// 控制栏组件
|
||||
skin: null,
|
||||
//是否全屏
|
||||
isFull: false,
|
||||
// 默认音量
|
||||
defaultVolume: 0.5,
|
||||
videoVid: '4ae3fe3ab5a2009a8d6605d81b2e3c9b_4'
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
//输入vid
|
||||
onVidInput: function(event) {
|
||||
this.videoVid = event.detail.value;
|
||||
},
|
||||
|
||||
setVid() {
|
||||
if(!this.videoVid) {
|
||||
uni.showToast({
|
||||
title: "请输入视频Vid",
|
||||
icon: "none"
|
||||
})
|
||||
return;
|
||||
}
|
||||
const { vodPlayer } = this;
|
||||
vodPlayer.setVid({
|
||||
vid:this.videoVid,
|
||||
level:0
|
||||
}, (ret) => {
|
||||
console.log(12)
|
||||
console.log(ret)
|
||||
this.text = JSON.stringify(ret);
|
||||
if (ret.errMsg != null) {
|
||||
uni.showToast({
|
||||
title: ret.errMsg,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onPlayError(e){
|
||||
console.log(e);
|
||||
if (e.detail.errEvent != null) {
|
||||
uni.showToast({
|
||||
title:'playErrorEvent - '+e.detail.errEvent,
|
||||
icon: "none"
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
positionChange(e){
|
||||
this.skin.timeUpdate(e.detail.currentPosition);
|
||||
},
|
||||
|
||||
onEnableSubtitle(e){
|
||||
console.log("===1" + e.detail);
|
||||
this.skin.setEnableSubtitle(e.detail.isEnableSubtitle, e.detail.isEnableDoubleSubtitle);
|
||||
},
|
||||
|
||||
onSRTTextConfig(e) {
|
||||
console.log("===1 fontColor: " + e.detail.fontColor);
|
||||
this.skit.setSRTTextConfig(e.detail);
|
||||
},
|
||||
|
||||
onSRTTitle(e) {
|
||||
console.log("===1 onSRTTitle" + e.detail);
|
||||
|
||||
},
|
||||
|
||||
onPlayStatus(e){
|
||||
const { skin, vodPlayer } = this;
|
||||
const state = e.detail.playbackState;
|
||||
const preparedToPlay = e.detail.preparedToPlay;
|
||||
if (state != null) {
|
||||
this.skin.changePlayStatus(state === 'start');
|
||||
} else if (preparedToPlay != null) {
|
||||
this.updateDuration();
|
||||
this.updateLevels();
|
||||
this.updateScaling();
|
||||
}
|
||||
},
|
||||
|
||||
updateDuration() {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.getDuration(null, ret => {
|
||||
this.skin.updateDuration(ret.duration);
|
||||
});
|
||||
},
|
||||
|
||||
updateLevels() {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
|
||||
vodPlayer.getLevelNum(null, ret => {
|
||||
this.skin.updateLevels(ret.levelNum);
|
||||
});
|
||||
|
||||
vodPlayer.getCurrentLevel(null, ret => {
|
||||
this.skin.updateCurrentLevel(ret.currentLevel);
|
||||
});
|
||||
},
|
||||
|
||||
updateScaling() {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
|
||||
vodPlayer.getScalingMode({}, ret => {
|
||||
this.skin.updateScaling(ret.scalingMode);
|
||||
});
|
||||
},
|
||||
|
||||
onPlayBtnClick(isPlaying) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
isPlaying ? vodPlayer.start() : vodPlayer.pause();
|
||||
},
|
||||
|
||||
onHdBtnClick(level) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.changeLevel({level});
|
||||
},
|
||||
|
||||
onRateBtnClick(speed) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.setSpeed({speed});
|
||||
},
|
||||
|
||||
onScalingBtnClick(scalingMode) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.setScalingMode({scalingMode});
|
||||
},
|
||||
|
||||
onChangeSRTBtnClick(srt) {
|
||||
console.log("===1 " + srt);
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.changeSRT(srt);
|
||||
},
|
||||
|
||||
onChangeSRTSingleMode(isSingle) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.changeSRTSingleMode(isSingle);
|
||||
},
|
||||
|
||||
onOpenSRT(isOpen) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.setOpenSRT({
|
||||
openSrt: isOpen
|
||||
});
|
||||
},
|
||||
|
||||
onFullBtnClick(isFull) {
|
||||
// plus.screen.unlockOrientation();
|
||||
plus.navigator.setFullscreen(isFull);
|
||||
|
||||
//通过h5+实现横竖屏
|
||||
// isFull ? plus.screen.lockOrientation('landscape-primary') : plus.screen.lockOrientation('portrait-primary');
|
||||
|
||||
//通过原生实现横竖屏切换
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
isFull ? vodPlayer.changeToLandscape() : vodPlayer.changeToPortrait();
|
||||
|
||||
this.isFull = isFull;
|
||||
},
|
||||
|
||||
onToSeek(time) {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.seekTo({seconds: time});
|
||||
},
|
||||
|
||||
onVolumeChanged(value) {
|
||||
const { vodPlayer, skin } = this;
|
||||
if (!vodPlayer) return;
|
||||
vodPlayer.getVolume(null, ret => {
|
||||
const changedValue = ret.volume + value;
|
||||
|
||||
const realValue = this.limit(changedValue, 0, 1);
|
||||
|
||||
vodPlayer.setVolume({volume: realValue});
|
||||
|
||||
skin.updateVolumeValue(realValue);
|
||||
});
|
||||
},
|
||||
|
||||
onScreenShot() {
|
||||
const { vodPlayer } = this;
|
||||
if (!vodPlayer) return;
|
||||
|
||||
vodPlayer.snapshot(null, result =>{
|
||||
if(result.errMsg != null){
|
||||
console.log(result.errMsg)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 控制最小值,最大值
|
||||
* @param num
|
||||
* @param min
|
||||
* @param max
|
||||
* @returns {*}
|
||||
*/
|
||||
limit(num, min, max) {
|
||||
if (num < min) return min;
|
||||
if (num > max) return max;
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.wrap {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.player {
|
||||
height: 400rpx;
|
||||
}
|
||||
|
||||
.player-full {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.vod-player {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.skin-control {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hide {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,17 +1,25 @@
|
||||
<template>
|
||||
<web-view :src="url"></web-view>
|
||||
<navBar :title="title" ></navBar>
|
||||
<web-view :src="url" :webview-styles="webviewStyles"></web-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
url: ''
|
||||
url: '',
|
||||
title: '新闻详情',
|
||||
webviewStyles: {
|
||||
width: '100%',
|
||||
height: 'calc(100vh - 160px)'
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad(item) {
|
||||
// 传入需要跳转的链接 使用web-view标签进行跳转
|
||||
this.url = decodeURIComponent(item.url)
|
||||
this.title = item.title;
|
||||
// console.log(this.url)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,843 @@
|
||||
<template>
|
||||
<view class="zhinan-list-page">
|
||||
<!-- 头部导航栏 -->
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="文献期刊"
|
||||
@clickLeft="goBack"
|
||||
|
||||
color="#8B2316"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 使用scroll-view实现列表 -->
|
||||
<scroll-view
|
||||
class="guidelines-scroll-view"
|
||||
scroll-y="true"
|
||||
|
||||
>
|
||||
<!-- 指南列表 -->
|
||||
<view class="guidelines-list">
|
||||
<view
|
||||
class="guideline-item"
|
||||
v-for="(item, index) in downLoadtaskList"
|
||||
:key="item.id || index"
|
||||
|
||||
>
|
||||
<!-- 指南信息 -->
|
||||
<view class="item-content">
|
||||
<view class="item-title">{{ item.title }}</view>
|
||||
<view class="item-bottom">
|
||||
<view class="item-date">{{ formatDate(item.releaseTime) }}</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="item-action">
|
||||
<view
|
||||
class="view-btn"
|
||||
@click.stop="viewGuideline(item)"
|
||||
>查看</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<view class="no-data" v-if="downLoadtaskList.length === 0 ">
|
||||
<uni-icons type="info" size="60" color="#999"></uni-icons>
|
||||
<text>暂无数据</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 组内排序弹窗 -->
|
||||
<view v-if="showInnerSort" class="popup-panel">
|
||||
<view
|
||||
class="popup-item"
|
||||
:class="{ active: sort == 1 }"
|
||||
@click.stop="chooseInnerSort(1)"
|
||||
>
|
||||
<text class="item-text">下载量</text>
|
||||
<uni-icons
|
||||
v-if="sort == 1"
|
||||
type="checkmarkempty"
|
||||
color="#8B2316"
|
||||
size="22"
|
||||
></uni-icons>
|
||||
</view>
|
||||
<view class="popup-divider"></view>
|
||||
<view
|
||||
class="popup-item"
|
||||
:class="{ active: sort == 2 }"
|
||||
@click.stop="chooseInnerSort(2)"
|
||||
>
|
||||
<text class="item-text">上传时间</text>
|
||||
<uni-icons
|
||||
v-if="sort == 2"
|
||||
type="checkmarkempty"
|
||||
color="#8B2316"
|
||||
size="22"
|
||||
></uni-icons>
|
||||
</view>
|
||||
<view class="popup-divider"></view>
|
||||
<view
|
||||
class="popup-item"
|
||||
:class="{ active: sort == 3 }"
|
||||
@click.stop="chooseInnerSort(3)"
|
||||
>
|
||||
<text class="item-text">标题</text>
|
||||
<uni-icons
|
||||
v-if="sort == 3"
|
||||
type="checkmarkempty"
|
||||
color="#8B2316"
|
||||
size="22"
|
||||
></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted,computed,nextTick} from "vue";
|
||||
import api from "@/api/api.js";
|
||||
import { onShow, onLoad } from "@dcloudio/uni-app";
|
||||
import docUrl from "@/utils/docUrl.js";
|
||||
import navTo from "@/utils/navTo.js";
|
||||
import hotImg from "@/static/hot_booklist.png";
|
||||
const guidelinesList = ref([]);
|
||||
const isLoading = ref(false);
|
||||
const hasMoreData = ref(true);
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const isRefreshing = ref(false);
|
||||
const keywords = ref("");
|
||||
import upImg from "@/static/triangle_green_theme.png";
|
||||
import downImg from "@/static/triangle_normal.png";
|
||||
const loadMoreStatus = ref("more"); // 'loading', 'more', 'noMore'
|
||||
const typeUuid = ref("");
|
||||
const title = ref("");
|
||||
const sort = ref(2);
|
||||
const showInnerSort = ref(false);
|
||||
const innerSortTitle = ref("上传时间");
|
||||
import downloadStore from "@/store/downloadStoreFile.js";
|
||||
const downloadTasks=ref([]);
|
||||
const downLoadtaskList=computed(()=>{
|
||||
return downloadTasks.value.filter((item)=>item.status == "completed" && item.type == "article");
|
||||
});
|
||||
const chooseInnerSort = (index) => {
|
||||
sort.value = index;
|
||||
if (index == 1) {
|
||||
innerSortTitle.value = "下载量";
|
||||
} else if (index == 2) {
|
||||
innerSortTitle.value = "上传时间";
|
||||
} else if (index == 3) {
|
||||
innerSortTitle.value = "标题";
|
||||
}
|
||||
showInnerSort.value = false;
|
||||
loadGuidelinesList(true);
|
||||
};
|
||||
onLoad((options) => {
|
||||
|
||||
});
|
||||
const goGot = () => {
|
||||
navTo({
|
||||
url: "/pages_app/hot/hot?from=hot&typeUuid=" + typeUuid.value,
|
||||
});
|
||||
};
|
||||
const toggleInnerSort = () => {
|
||||
showInnerSort.value = !showInnerSort.value;
|
||||
};
|
||||
onShow(() => {
|
||||
|
||||
syncTasksFromStore();
|
||||
// 监听store变化
|
||||
downloadStore.addListener((tasks) => {
|
||||
downloadTasks.value = tasks;
|
||||
|
||||
});
|
||||
// 恢复正在下载的任务
|
||||
resumeDownloadingTasks();
|
||||
// 页面显示时,如果列表为空则加载数据
|
||||
|
||||
});
|
||||
|
||||
// 跳转到搜索页
|
||||
const goToSearch = () => {
|
||||
const q = keywords.value ? encodeURIComponent(keywords.value) : "";
|
||||
const t = title.value ? encodeURIComponent(title.value) : "";
|
||||
const type = typeUuid.value
|
||||
? `&typeUuid=${encodeURIComponent(typeUuid.value)}`
|
||||
: "";
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/search/search?keywords=${q}&title=${t}${type}`,
|
||||
});
|
||||
// const goSearch=()=>{
|
||||
// uni.sendNativeEvent('goHomeSearch', {
|
||||
// msg: 'goHomeSearch'
|
||||
// },ret => {
|
||||
// console.log(ret);
|
||||
// })
|
||||
// }
|
||||
};
|
||||
|
||||
// scroll-view 下拉刷新
|
||||
const onRefresh = async () => {
|
||||
console.log("scroll-view 下拉刷新触发");
|
||||
isRefreshing.value = true;
|
||||
await refreshData();
|
||||
isRefreshing.value = false;
|
||||
};
|
||||
|
||||
// scroll-view 滚动到底部
|
||||
const onScrollToLower = () => {
|
||||
console.log("=== onScrollToLower 触发 ===");
|
||||
console.log("当前状态:", {
|
||||
loadMoreStatus: loadMoreStatus.value,
|
||||
isRefreshing: isRefreshing.value,
|
||||
currentPage: currentPage.value,
|
||||
listLength: guidelinesList.value.length,
|
||||
hasMoreData: hasMoreData.value,
|
||||
isLoading: isLoading.value,
|
||||
});
|
||||
|
||||
if (
|
||||
loadMoreStatus.value === "more" &&
|
||||
!isRefreshing.value &&
|
||||
!isLoading.value
|
||||
) {
|
||||
console.log("条件满足,开始加载更多数据");
|
||||
loadMoreData();
|
||||
} else {
|
||||
console.log("条件不满足,跳过加载:", {
|
||||
loadMoreStatus: loadMoreStatus.value,
|
||||
isRefreshing: isRefreshing.value,
|
||||
isLoading: isLoading.value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 刷新数据
|
||||
const refreshData = async () => {
|
||||
try {
|
||||
currentPage.value = 1;
|
||||
hasMoreData.value = true;
|
||||
loadMoreStatus.value = "more";
|
||||
|
||||
await loadGuidelinesList(true);
|
||||
|
||||
uni.showToast({
|
||||
title: "刷新成功",
|
||||
icon: "none",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("刷新失败:", error);
|
||||
uni.showToast({
|
||||
title: "刷新失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 加载指南列表
|
||||
const loadGuidelinesList = async (isRefresh = false) => {
|
||||
console.log("=== loadGuidelinesList 开始 ===");
|
||||
console.log("当前参数:", {
|
||||
isRefresh,
|
||||
page: currentPage.value,
|
||||
keywords: keywords.value,
|
||||
});
|
||||
|
||||
if (isLoading.value) return;
|
||||
|
||||
try {
|
||||
isLoading.value = true;
|
||||
loadMoreStatus.value = "loading";
|
||||
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
type: 1, // 诊疗指南类型
|
||||
sort: 2,
|
||||
typeUuid: typeUuid.value,
|
||||
keywords: keywords.value,
|
||||
};
|
||||
|
||||
const res = await api.searchLibraryU(params);
|
||||
console.log("指南列表响应:", res);
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
const newData = res.data.list || res.data;
|
||||
|
||||
if (isRefresh) {
|
||||
guidelinesList.value = newData;
|
||||
console.log("刷新模式:替换列表数据");
|
||||
} else {
|
||||
guidelinesList.value = [...guidelinesList.value, ...newData];
|
||||
console.log("加载更多:追加数据到列表");
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
if (newData.length < pageSize.value) {
|
||||
loadMoreStatus.value = "noMore";
|
||||
hasMoreData.value = false;
|
||||
console.log("没有更多数据了");
|
||||
} else {
|
||||
loadMoreStatus.value = "more";
|
||||
hasMoreData.value = true;
|
||||
// 只有在加载更多模式下才递增页码
|
||||
if (!isRefresh) {
|
||||
currentPage.value++;
|
||||
console.log(`还有更多数据,下一页: ${currentPage.value}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.error("加载指南列表失败:", res.message);
|
||||
loadMoreStatus.value = "noMore";
|
||||
uni.showToast({
|
||||
title: res.message || "加载失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载指南列表异常:", error);
|
||||
loadMoreStatus.value = "noMore";
|
||||
uni.showToast({
|
||||
title: "网络异常,请重试",
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
console.log("=== loadGuidelinesList 结束 ===");
|
||||
console.log("最终状态:", {
|
||||
loadMoreStatus: loadMoreStatus.value,
|
||||
page: currentPage.value,
|
||||
listLength: guidelinesList.value.length,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 加载更多数据
|
||||
const loadMoreData = () => {
|
||||
console.log("=== loadMoreData 被调用 ===");
|
||||
console.log("检查条件:", {
|
||||
hasMoreData: hasMoreData.value,
|
||||
isLoading: isLoading.value,
|
||||
currentPage: currentPage.value,
|
||||
});
|
||||
|
||||
if (hasMoreData.value && !isLoading.value) {
|
||||
console.log("条件满足,开始加载更多数据");
|
||||
loadGuidelinesList(false);
|
||||
} else {
|
||||
console.log("条件不满足,跳过加载更多");
|
||||
}
|
||||
};
|
||||
|
||||
// 下载指南
|
||||
const downloadGuideline = (item) => {
|
||||
console.log("下载指南:", item);
|
||||
uni.showToast({
|
||||
title: "开始下载...",
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
// 这里可以调用下载API
|
||||
// 示例:下载PDF文件
|
||||
if (item.file_path) {
|
||||
uni.downloadFile({
|
||||
url: item.file_path,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error("下载失败:", err);
|
||||
uni.showToast({
|
||||
title: "下载失败1",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
const downLoad = (item) => {
|
||||
if(!item.path){
|
||||
uni.showToast({
|
||||
title: "暂无下载链接",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
addDownloadTask({
|
||||
url: docUrl + item.path,
|
||||
title: item.title,
|
||||
id: item.uuid,
|
||||
});
|
||||
};
|
||||
// 查看指南(支持常用文档直链:pdf/doc/docx/xls/xlsx/ppt/pptx/txt)
|
||||
const viewGuideline = (cell) => {
|
||||
console.log(downloadTasks.value);
|
||||
downloadTasks.value.forEach(item => {
|
||||
if(item.id == cell.id) {
|
||||
console.log(2222222222);
|
||||
console.log(item.localPath);
|
||||
plus.runtime.openFile(item.localPath, function(e) {
|
||||
console.log('打开成功');
|
||||
}, function(e) {
|
||||
uni.showToast({
|
||||
title: '打开失败:' + e.message,
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
console.log('打开失败:' + e.message);
|
||||
});
|
||||
// uni.openDocument({
|
||||
// filePath: item.localPath,
|
||||
// fileType: 'pdf',
|
||||
// success: () => console.log('打开成功'),
|
||||
// fail: (err) => {
|
||||
// uni.showModal({
|
||||
// title: '提示',
|
||||
// content: JSON.stringify(err),
|
||||
// showCancel: false,
|
||||
// confirmText: '确定',
|
||||
// success: (res) => {
|
||||
// if(res.confirm){
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// let url = "https://view.xdocin.com/view?src=" + encodeURIComponent(pdfUrl);
|
||||
// uni.downloadFile({
|
||||
// url: pdfUrl,
|
||||
// success: (res) => {
|
||||
// if (res.statusCode === 200) {
|
||||
// uni.openDocument({
|
||||
// filePath: res.tempFilePath, // 临时文件路径
|
||||
// fileType: 'pdf',
|
||||
// success: () => console.log('打开成功'),
|
||||
// fail: (err) => console.error('打开失败', err)
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
|
||||
// 添加下载任务
|
||||
const addDownloadTask = (item) => {
|
||||
// 使用store添加任务
|
||||
const taskIndex = downloadStore.addTask({
|
||||
...item,
|
||||
type: 'zhinan',
|
||||
});
|
||||
// 同步任务列表
|
||||
syncTasksFromStore();
|
||||
// 开始下载
|
||||
startDownload(taskIndex);
|
||||
};
|
||||
|
||||
// 开始下载
|
||||
const startDownload = (index) => {
|
||||
const taskItem = downloadStore.getTask(index);
|
||||
if (!taskItem) return;
|
||||
if(taskItem.status == "loading"){
|
||||
|
||||
return false;
|
||||
};
|
||||
uni.showToast({
|
||||
title: "正在下载中",
|
||||
icon: "none",
|
||||
});
|
||||
downloadStore.updateTask(index, {
|
||||
status: "loading"
|
||||
});
|
||||
|
||||
const task = uni.downloadFile({
|
||||
url: taskItem.url,
|
||||
success: (res1) => {
|
||||
console.log("res1:"+JSON.stringify(res1));
|
||||
if (res1.statusCode === 200) {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
filePath: res1.tempFilePath,
|
||||
});
|
||||
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
|
||||
uni.saveFile({
|
||||
tempFilePath: res1.tempFilePath,
|
||||
success: function (res2) {
|
||||
console.log("res2:"+JSON.stringify(res2));
|
||||
uni.getSavedFileInfo({
|
||||
filePath: res2.savedFilePath,
|
||||
success: function (res) {
|
||||
console.log("res:"+JSON.stringify(res));
|
||||
console.log("size:"+res.size);
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
localPath: res2.savedFilePath,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
removeTask(index);
|
||||
uni.showToast({
|
||||
title: "下载失败2",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
removeTask(index);
|
||||
uni.showToast({
|
||||
title: "下载失败3: " + (err.errMsg || "未知错误"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// 监听下载进度
|
||||
task.onProgressUpdate((update) => {
|
||||
const currentTask = downloadStore.getTask(index);
|
||||
if (currentTask && currentTask.status === "downloading") {
|
||||
downloadStore.updateTask(index, {
|
||||
progress: update.progress
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 保存task对象到store(用于暂停/继续)
|
||||
downloadStore.updateTask(index, {
|
||||
task: task,
|
||||
});
|
||||
};
|
||||
|
||||
const syncTasksFromStore = () => {
|
||||
downloadTasks.value = downloadStore.getTasks();
|
||||
};
|
||||
const removeTask = (index) => {
|
||||
downloadStore.removeTask(index);
|
||||
syncTasksFromStore();
|
||||
};
|
||||
// 恢复正在下载的任务
|
||||
const resumeDownloadingTasks = () => {
|
||||
// 使用 nextTick 确保在页面渲染后再恢复下载任务
|
||||
nextTick(() => {
|
||||
downloadStore.resumeDownloadingTasks((index) => {
|
||||
// 重新开始下载(uni.downloadFile不支持断点续传,所以从0开始)
|
||||
console.log("恢复下载任务:", downloadStore.getTask(index)?.url);
|
||||
startDownload(index);
|
||||
});
|
||||
});
|
||||
};
|
||||
// 测试加载更多功能
|
||||
const testLoadMore = () => {
|
||||
console.log("=== 手动测试加载更多 ===");
|
||||
console.log("当前状态:", {
|
||||
loadMoreStatus: loadMoreStatus.value,
|
||||
hasMoreData: hasMoreData.value,
|
||||
isLoading: isLoading.value,
|
||||
currentPage: currentPage.value,
|
||||
listLength: guidelinesList.value.length,
|
||||
});
|
||||
|
||||
if (loadMoreStatus.value === "more" && !isLoading.value) {
|
||||
loadMoreData();
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: `状态: ${loadMoreStatus.value}, 加载中: ${isLoading.value}`,
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return "";
|
||||
|
||||
try {
|
||||
const date = new Date(dateString);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
return `${year}-${month}-${day}`;
|
||||
} catch (error) {
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 颜色变量
|
||||
$primary-color: #ff4757;
|
||||
$text-primary: #333;
|
||||
$text-secondary: #666;
|
||||
$text-light: #999;
|
||||
$border-color: #e0e0e0;
|
||||
$bg-color: #f6f6f6;
|
||||
$white: #ffffff;
|
||||
.imgbox {
|
||||
width: 32rpx;
|
||||
margin-top: -10rpx;
|
||||
}
|
||||
.popup-panel {
|
||||
position: fixed;
|
||||
top:285rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
z-index: 100;
|
||||
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.popup-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 28rpx 30rpx;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.popup-divider {
|
||||
height: 2rpx;
|
||||
background: #eaeaea;
|
||||
}
|
||||
|
||||
.popup-item.active .item-text {
|
||||
color: #8b2316;
|
||||
}
|
||||
.current-sort {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
|
||||
.sort-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sort-icon.up {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 8rpx solid transparent;
|
||||
border-right: 8rpx solid transparent;
|
||||
border-bottom: 12rpx solid #999;
|
||||
|
||||
&.active {
|
||||
border-bottom-color: #ff0000;
|
||||
}
|
||||
}
|
||||
}
|
||||
.zhinan-list-page {
|
||||
background-color: $bg-color;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.guidelines-scroll-view {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
height: calc(100vh - var(--status-bar-height) - 44px);
|
||||
background-color: $bg-color;
|
||||
}
|
||||
// 固定搜索容器
|
||||
.search-container-fixed {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px); // 导航栏高度
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 90;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 30rpx 30rpx;
|
||||
background-color: $white;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
// 筛选栏
|
||||
.filter-bar {
|
||||
background-color: $white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid #eee;
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
|
||||
.search-text {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 1px;
|
||||
height: 16px;
|
||||
background-color: #999;
|
||||
margin: 0 60rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// 指南列表
|
||||
.guidelines-list {
|
||||
padding: 20rpx 30rpx;
|
||||
|
||||
.guideline-item {
|
||||
background-color: $white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
margin-right: 30rpx;
|
||||
|
||||
.item-title {
|
||||
font-size: 32rpx;
|
||||
color: $text-primary;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: 500;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 10rpx;
|
||||
|
||||
.item-date {
|
||||
font-size: 26rpx;
|
||||
color: $text-secondary;
|
||||
}
|
||||
|
||||
.item-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.download-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(255, 71, 87, 0.1);
|
||||
// transition: all 0.3s ease;
|
||||
|
||||
// &:active {
|
||||
// transform: scale(0.95);
|
||||
// background-color: rgba(255, 71, 87, 0.2);
|
||||
// }
|
||||
}
|
||||
|
||||
.view-btn {
|
||||
color: #8b2316;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background-color: darken($primary-color, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多状态
|
||||
.load-more-status {
|
||||
padding: 20rpx 0;
|
||||
text-align: center;
|
||||
|
||||
.loading,
|
||||
.more,
|
||||
.no-more {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10rpx;
|
||||
padding: 20rpx 0;
|
||||
font-size: 26rpx;
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
|
||||
// 无数据提示
|
||||
.no-data {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 0;
|
||||
|
||||
text {
|
||||
margin-top: 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
<template>
|
||||
<uni-nav-bar
|
||||
<!-- <uni-nav-bar
|
||||
left-icon="left"
|
||||
title="购买积分"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
></uni-nav-bar> -->
|
||||
<navBar :title="'购买积分'" ></navBar>
|
||||
<view class="buy-point-page">
|
||||
|
||||
|
||||
@@ -46,20 +47,80 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<unidialog
|
||||
:visible="freeVisible"
|
||||
:content="freeContent"
|
||||
@close="freeClose"
|
||||
@confirm="freeConfirm"
|
||||
></unidialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import api from '@/api/api';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import unidialog from '@/components/dialog/dialog.vue';
|
||||
import navBar from '@/components/navBar/navBar.vue';
|
||||
const freeVisible = ref(false);
|
||||
const freeContent = ref('您确定是否购买?');
|
||||
const product_id = ref('');
|
||||
const type = ref('');
|
||||
const freeClose = () => {
|
||||
freeVisible.value = false;
|
||||
};
|
||||
const freeConfirm = () => {
|
||||
freeVisible.value = false;
|
||||
api.createBointsOrder({
|
||||
point: selectedPackageData.value.points
|
||||
}).then(res => {
|
||||
if(res.code==200){
|
||||
console.log('price:'+res.data.amount);
|
||||
console.log('order_id:'+res.data.order_id);
|
||||
console.log('trade_no:'+res.data.trade_no);
|
||||
console.log('jifen:'+res.data.point);
|
||||
uni.sendNativeEvent('payPonitPage', {
|
||||
msg: {
|
||||
"price":res.data.amount,
|
||||
"order_id":res.data.order_id,
|
||||
"trade_no":res.data.trade_no,
|
||||
'jifen':res.data.point,
|
||||
'product_id':product_id.value,
|
||||
'type':type.value,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
onLoad((options) => {
|
||||
if(options.product_id){
|
||||
product_id.value = options.product_id;
|
||||
}
|
||||
if(options.type){
|
||||
type.value = options.type;
|
||||
}
|
||||
getPointUnitPrice();
|
||||
});
|
||||
const pointUnitPrice = ref(1);
|
||||
// 积分套餐数据 - 根据图片显示5个选项
|
||||
const packages = ref([
|
||||
{ id: 1, points: 500, price: '45.00' },
|
||||
{ id: 2, points: 1000, price: '88.00' },
|
||||
{ id: 3, points: 2500, price: '198.00' },
|
||||
{ id: 4, points: 5000, price: '398.00' },
|
||||
{ id: 5, points: 10000, price: '758.00' }
|
||||
{ id: 1, points: 500, price: 500*pointUnitPrice.value/100 },
|
||||
{ id: 2, points: 1000, price: 1000*pointUnitPrice.value/100 },
|
||||
{ id: 3, points: 2500, price: 2500*pointUnitPrice.value/100 },
|
||||
{ id: 4, points: 5000, price: 5000*pointUnitPrice.value/100 },
|
||||
{ id: 5, points: 10000, price: 10000*pointUnitPrice.value/100 }
|
||||
]);
|
||||
|
||||
const getPointUnitPrice = () => {
|
||||
api.getPointUnitPrice().then(res => {
|
||||
if(res.code==200){
|
||||
pointUnitPrice.value=Number(res.data);
|
||||
console.log(pointUnitPrice.value);
|
||||
packages.value.forEach(pkg => {
|
||||
pkg.price = pkg.points * pointUnitPrice.value / 100;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// 选择状态
|
||||
const selectedPackage = ref(0); // 默认未选择
|
||||
|
||||
@@ -96,18 +157,7 @@
|
||||
}
|
||||
|
||||
const packageData = selectedPackageData.value;
|
||||
uni.showModal({
|
||||
title: '确认购买',
|
||||
content: `确认购买${packageData.points}积分,支付金额¥${packageData.price}?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showToast({
|
||||
title: '购买成功',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
freeVisible.value=true;
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -138,7 +188,7 @@
|
||||
}
|
||||
|
||||
.buy-point-page {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: 100vh;
|
||||
background-color: $bg-color;
|
||||
overflow: hidden; // 隐藏滚动条
|
||||
|
||||
@@ -224,6 +274,7 @@
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
padding: 40rpx 0rpx;
|
||||
|
||||
.page-title {
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
<template>
|
||||
<view class="address-page">
|
||||
<navBar :title="'收货地址'" />
|
||||
<!-- <uni-nav-bar left-icon="left" title="收货地址" fixed color="#8B2316" height="180rpx" :border="false" backgroundColor="#ffffff" @clickLeft="goBack" /> -->
|
||||
|
||||
<scroll-view scroll-y class="content">
|
||||
<view class="form-item">
|
||||
<view class="label">收件人</view>
|
||||
<input class="input" v-model="receiver" placeholder="请输入收货人名字" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">手机号</view>
|
||||
<input class="input" v-model="mobile" type="number" placeholder="收货人的电话,方便联系" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<!-- <view class="form-item">
|
||||
<view class="label">邮箱</view>
|
||||
<input class="input" v-model="email" type="text" placeholder="用于接收电子卡等信息(可选)" />
|
||||
</view> -->
|
||||
|
||||
|
||||
<view class="form-item select-item" @click="openAreaPicker">
|
||||
<view class="label">地址</view>
|
||||
<view class="input placeholder" v-if="!regionText">请选择地址</view>
|
||||
<view class="input" v-else>{{ regionText }}</view>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label">详细地址</view>
|
||||
<input class="input" v-model="detail" placeholder="请输入街道、门牌等详细地址信息" />
|
||||
</view>
|
||||
<view class="divider-line"></view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="footer-bar" @click="submit">
|
||||
<view class="confirm-btn" >确定兑换</view>
|
||||
</view>
|
||||
|
||||
<!-- 省市区选择器 -->
|
||||
<view v-if="showAreaPicker" class="picker-mask" @click="closeAreaPicker"></view>
|
||||
<view v-if="showAreaPicker" class="picker-panel">
|
||||
<view class="picker-header">
|
||||
<text class="picker-btn" @click="closeAreaPicker">取消</text>
|
||||
<text class="picker-title">选择地区</text>
|
||||
<text class="picker-btn ok" @click="confirmArea">确定</text>
|
||||
</view>
|
||||
<picker-view v-if="provinces.length && cities.length && areas.length" class="picker-view" :indicator-style="indicatorStyle" :value="pickerIndex" @change="onAreaChange">
|
||||
<picker-view-column>
|
||||
<view v-for="(p,pi) in provinces" :key="pi" class="picker-item">{{ p.name }}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view v-for="(c,ci) in cities" :key="ci" class="picker-item">{{ c.name }}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view v-for="(a,ai) in areas" :key="ai" class="picker-item">{{ a.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
<view v-else class="picker-empty">地区数据加载中...</view>
|
||||
</view>
|
||||
</view>
|
||||
<unidialog
|
||||
:title="'确认兑换信息'"
|
||||
:visible="freeVisible"
|
||||
:content="freeContent"
|
||||
:titleColor="'#000'"
|
||||
@close="freeClose"
|
||||
@confirm="freeConfirm"
|
||||
>
|
||||
<template #content>
|
||||
<view>
|
||||
<view class="row">
|
||||
<view class="left">收件人:</view>
|
||||
<view class="right">{{ receiver }}</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="left">手机号:</view>
|
||||
<view class="right">{{ mobile }}</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="left">地址:</view>
|
||||
<view class="right">{{ regionText+detail }}</view>
|
||||
</view>
|
||||
<view class="row">
|
||||
<view class="left">兑换积分:</view>
|
||||
<view class="right"><text class="price">0积分</text>(包邮)</view>
|
||||
</view>
|
||||
<view class="row">请确认此次兑换,物品不退不换</view>
|
||||
</view>
|
||||
</template>
|
||||
</unidialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import areaList from '@/utils/areaList.js'
|
||||
import api from '@/api/api.js'
|
||||
import unidialog from '@/components/dialog/dialog.vue';
|
||||
const freeVisible = ref(false)
|
||||
const freeContent = ref('')
|
||||
const goods_order_id = ref('')
|
||||
const goodsName = ref('');
|
||||
import navTo from '@/utils/navTo';
|
||||
const freeClose = () => {
|
||||
freeVisible.value = false
|
||||
}
|
||||
const freeConfirm = () => {
|
||||
freeVisible.value = false;
|
||||
api.useWelfareNum({
|
||||
other_uuid: goods_order_id.value,
|
||||
type: 5
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
|
||||
uni.showToast({
|
||||
title: '兑换成功',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
navTo({
|
||||
url: '/pages_goods/myRedemption/myRedemption?from=upan'
|
||||
});
|
||||
}, 1000);
|
||||
// uni.sendNativeEvent('goTabbarPage', {
|
||||
// msg: 'mine'
|
||||
// },ret => {
|
||||
// console.log(ret);
|
||||
// })
|
||||
}
|
||||
})
|
||||
}
|
||||
const receiver = ref('')
|
||||
const mobile = ref('')
|
||||
const regionText = ref('')
|
||||
const detail = ref('')
|
||||
const email = ref('')
|
||||
const editingId = ref(null)
|
||||
const goodsUuid = ref('')
|
||||
const goodsNum = ref(0)
|
||||
const goBack = () => uni.navigateBack()
|
||||
|
||||
// 省市区数据(适配树形数组:[{code,label,value,children:[...] }...])
|
||||
const provinces = ref([])
|
||||
const cities = ref([])
|
||||
const areas = ref([])
|
||||
const pickerIndex = ref([0,0,0])
|
||||
const showAreaPicker = ref(false)
|
||||
const indicatorStyle = `height: 80rpx;`
|
||||
|
||||
const normalizeNode = (node) => ({
|
||||
code: node?.code || '',
|
||||
name: node?.label || node?.value || node?.name || '',
|
||||
children: Array.isArray(node?.children) ? node.children : []
|
||||
})
|
||||
|
||||
const getAreaTree = () => {
|
||||
const raw = areaList && (areaList.default || areaList)
|
||||
return Array.isArray(raw) ? raw.map(normalizeNode) : []
|
||||
}
|
||||
|
||||
const buildData = () => {
|
||||
const tree = getAreaTree()
|
||||
provinces.value = tree.length ? tree : [{ code: '', name: '', children: [] }]
|
||||
const pIdx = Math.min(pickerIndex.value[0], Math.max(provinces.value.length - 1, 0))
|
||||
const pNode = provinces.value[pIdx]
|
||||
cities.value = (pNode?.children || []).map(normalizeNode)
|
||||
if (!cities.value.length) cities.value = [{ code: '', name: '', children: [] }]
|
||||
const cIdx = Math.min(pickerIndex.value[1], Math.max(cities.value.length - 1, 0))
|
||||
const cNode = cities.value[cIdx]
|
||||
areas.value = (cNode?.children || []).map(normalizeNode)
|
||||
if (!areas.value.length) areas.value = [{ code: '', name: '' }]
|
||||
}
|
||||
|
||||
const openAreaPicker = () => {
|
||||
showAreaPicker.value = true
|
||||
pickerIndex.value = [0,0,0]
|
||||
buildData()
|
||||
}
|
||||
const closeAreaPicker = () => { showAreaPicker.value = false }
|
||||
|
||||
const onAreaChange = (e) => {
|
||||
const val = (e && e.detail && e.detail.value) ? e.detail.value : [0,0,0]
|
||||
const [pi, ci, ai] = val
|
||||
if (pi !== pickerIndex.value[0]) {
|
||||
pickerIndex.value = [pi, 0, 0]
|
||||
buildData()
|
||||
return
|
||||
}
|
||||
if (ci !== pickerIndex.value[1]) {
|
||||
pickerIndex.value = [pi, ci, 0]
|
||||
buildData()
|
||||
return
|
||||
}
|
||||
pickerIndex.value = [pi, ci, ai]
|
||||
}
|
||||
|
||||
const confirmArea = () => {
|
||||
const p = provinces.value[pickerIndex.value[0]]
|
||||
const c = cities.value[pickerIndex.value[1]]
|
||||
const a = areas.value[pickerIndex.value[2]]
|
||||
regionText.value = [p?.name, c?.name, a?.name].filter(Boolean).join(' ')
|
||||
closeAreaPicker()
|
||||
}
|
||||
|
||||
onLoad((opts) => {
|
||||
console.log(22);
|
||||
console.log(opts);
|
||||
goodsUuid.value = opts.goodsUuid
|
||||
goodsNum.value = opts.goodsNum;
|
||||
goodsName.value = opts.goodsName;
|
||||
getAddress()
|
||||
})
|
||||
|
||||
const saveAddress = () => {
|
||||
uni.setStorageSync('goods_address', {
|
||||
receiver: receiver.value,
|
||||
mobile: mobile.value,
|
||||
regionText: regionText.value,
|
||||
detail: detail.value,
|
||||
email: email.value
|
||||
})
|
||||
}
|
||||
const getAddress = () => {
|
||||
const address = uni.getStorageSync('goods_address')
|
||||
if(address){
|
||||
receiver.value = address.receiver
|
||||
mobile.value = address.mobile
|
||||
regionText.value = address.regionText
|
||||
detail.value = address.detail
|
||||
email.value = address.email
|
||||
}
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
|
||||
if (!receiver.value) return uni.showToast({ title: '请输入收件人', icon: 'none' })
|
||||
if (!/^1\d{10}$/.test(mobile.value)) return uni.showToast({ title: '请输入正确手机号', icon: 'none' })
|
||||
if (!regionText.value) return uni.showToast({ title: '请选择地址', icon: 'none' })
|
||||
if (!detail.value) return uni.showToast({ title: '请输入详细地址', icon: 'none' })
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "boint_jifengood",
|
||||
page_type: "积分商城",
|
||||
resource_name:goodsName.value,
|
||||
event_val:0,
|
||||
event_unit:'积分',
|
||||
number:goodsNum.value,
|
||||
belong:'U盘',
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
saveAddress();
|
||||
api.createGoodsOrder({
|
||||
goodsUuid: goodsUuid.value,
|
||||
goodsNum: goodsNum.value,
|
||||
user_name: receiver.value,
|
||||
mobile: mobile.value,
|
||||
email:'',
|
||||
address: regionText.value+detail.value
|
||||
}).then(res => {
|
||||
if(res.code == 1 || res.code == 200){
|
||||
freeVisible.value = true
|
||||
goods_order_id.value = res.data.goods_order_id
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.address-page { min-height: 100vh; background: #fff; }
|
||||
.content { position: absolute; top: calc(var(--status-bar-height) + 44px); bottom: 120rpx; left: 0; right: 0; background: #fff; }
|
||||
.form-item { display: flex; align-items: center; padding: 24rpx; }
|
||||
.label { width: 160rpx; color: #333; font-size: 30rpx; }
|
||||
.input { flex: 1; color: #333; font-size: 30rpx; }
|
||||
.placeholder { color: #808080;}
|
||||
.divider-line { height: 2rpx; background: #eee; margin: 0 24rpx; }
|
||||
.select-item { position: relative; }
|
||||
.arrow { position: absolute; right: 24rpx; color: #999; font-size: 48rpx; }
|
||||
.footer-bar { position: fixed; left: 0; right: 0; bottom: 0; height: 120rpx; background: #27c5b8; display: flex; align-items: center; justify-content: center; }
|
||||
.confirm-btn { color: #fff; font-size: 34rpx; font-weight: 700; }
|
||||
|
||||
/* 地区选择器 */
|
||||
.picker-mask { position: fixed; left: 0; right: 0; top: 0; bottom: 0; background: rgba(0,0,0,0.4); }
|
||||
.picker-panel { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; }
|
||||
.picker-header { display: flex; align-items: center; justify-content: space-between; padding: 20rpx 24rpx; border-bottom: 1rpx solid #eee; }
|
||||
.picker-title { font-size: 30rpx; color: #333; }
|
||||
.picker-btn { color: #666; font-size: 28rpx; }
|
||||
.picker-btn.ok { color: #38c1b1; }
|
||||
.picker-view { height: 480rpx; }
|
||||
.picker-item { height: 80rpx; line-height: 80rpx; text-align: center; color: #333; }
|
||||
.picker-empty { padding: 40rpx; text-align: center; color: #999; }
|
||||
.row{
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
font-size: 28rpx;
|
||||
padding: 12rpx 0;
|
||||
|
||||
max-width: 800rpx;
|
||||
|
||||
.left{
|
||||
text-align: left;
|
||||
max-width: 142rpx;
|
||||
white-space: nowrap;
|
||||
width:auto!important;
|
||||
}
|
||||
.price{
|
||||
color: #FF4D4F;
|
||||
}
|
||||
}
|
||||
.left{
|
||||
width: 160rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
<template>
|
||||
<navBar :title="'U盘在线兑换'" />
|
||||
|
||||
<view class="buy-upan-page">
|
||||
<!-- 主要内容区域 -->
|
||||
<view class="main-content">
|
||||
<!-- 商品信息卡片 -->
|
||||
<view class="product-card">
|
||||
<!-- 商品描述 -->
|
||||
<view class="product-title">{{ goodsInfo.name }}</view>
|
||||
|
||||
<!-- 兑换信息 -->
|
||||
<view class="exchange-info">
|
||||
<text class="info-left">免费兑换剩余{{ remainingCount }}个</text>
|
||||
<text class="info-right">已兑换{{ exchangedCount }}件</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 兑换数量选择器 -->
|
||||
<view class="quantity-section">
|
||||
<text class="quantity-label">兑换数量</text>
|
||||
<view class="quantity-selector">
|
||||
<view
|
||||
class="quantity-btn minus-btn"
|
||||
:class="{ disabled: quantity <= 1 }"
|
||||
@click="decreaseQuantity"
|
||||
>
|
||||
<text class="btn-text">—</text>
|
||||
</view>
|
||||
<view class="quantity-display">
|
||||
<text class="quantity-value">{{ quantity }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="quantity-btn plus-btn"
|
||||
:class="{ disabled: quantity >= remainingCount }"
|
||||
@click="increaseQuantity"
|
||||
>
|
||||
<text class="btn-text">+</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部兑换按钮 -->
|
||||
<view class="bottom-actions">
|
||||
<view class="exchange-btn" @click="handleExchange">
|
||||
<text class="btn-text">我要兑换</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import navBar from '@/components/navBar/navBar.vue';
|
||||
import api from '@/api/api';
|
||||
import goods_api from '@/api/goods_api';
|
||||
import navTo from '@/utils/navTo';
|
||||
const goodsUuid = ref('');
|
||||
|
||||
|
||||
// 商品信息
|
||||
const remainingCount = ref(0); // 剩余数量
|
||||
const exchangedCount = ref(1129); // 已兑换数量
|
||||
const quantity = ref(1); // 当前选择的数量
|
||||
const goodsInfo = ref({});
|
||||
|
||||
// 增加数量
|
||||
const increaseQuantity = () => {
|
||||
if (quantity.value < remainingCount.value) {
|
||||
quantity.value += 1;
|
||||
}
|
||||
};
|
||||
const getUpanCount = async () => {
|
||||
const res = await goods_api.getUpanWelfareCount()
|
||||
if (res.code == 200) {
|
||||
remainingCount.value=res.data;
|
||||
};
|
||||
}
|
||||
// 减少数量
|
||||
const decreaseQuantity = () => {
|
||||
if (quantity.value > 1) {
|
||||
quantity.value -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
// 处理兑换
|
||||
const handleExchange = () => {
|
||||
if (quantity.value <= 0) {
|
||||
uni.showToast({
|
||||
title: '请选择兑换数量',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// if (quantity.value > remainingCount.value) {
|
||||
// uni.showToast({
|
||||
// title: '兑换数量不能超过剩余数量',
|
||||
// icon: 'none'
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
// TODO: 调用兑换接口
|
||||
navTo({
|
||||
url:'/pages_app/buyUpan/address?goodsUuid='+goodsUuid.value+'&goodsNum='+quantity.value+'&goodsName='+goodsInfo.value.name
|
||||
})
|
||||
};
|
||||
|
||||
// 获取U盘福利剩余数量
|
||||
const getUpanWelfareCount = () => {
|
||||
api.getUGoods().then(res => {
|
||||
console.log(res);
|
||||
if (res.code == 1 || res.code == 200) {
|
||||
// 根据实际接口返回的数据结构更新
|
||||
console.log(33);
|
||||
console.log(res.data);
|
||||
goodsInfo.value = res.data;
|
||||
if (res.data) {
|
||||
//remainingCount.value = res.data.remainingCount;
|
||||
exchangedCount.value = res.data.times;
|
||||
goodsUuid.value = res.data.uuid;
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('获取U盘福利数量失败:', err);
|
||||
});
|
||||
};
|
||||
|
||||
onShow((options) => {
|
||||
//remainingCount.value = options.restNum;
|
||||
// 可选:获取实时剩余数量
|
||||
//getUGoods();
|
||||
getUpanWelfareCount();
|
||||
getUpanCount();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 变量定义
|
||||
$bg-color: #ffffff;
|
||||
$text-primary: #333333;
|
||||
$text-secondary: #666666;
|
||||
$text-light: #999999;
|
||||
$border-color: #e5e5e5;
|
||||
$white: #ffffff;
|
||||
$teal-color: #00cbc0;
|
||||
$light-teal: #e6f7f6;
|
||||
$page-bg: #f5f6f7;
|
||||
|
||||
// 混合器
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@mixin flex-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.buy-upan-page {
|
||||
|
||||
overflow: hidden;
|
||||
background-color: $page-bg;
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
// 为底部按钮留出空间
|
||||
}
|
||||
|
||||
|
||||
// 商品信息卡片
|
||||
.product-card {
|
||||
background-color: $white;
|
||||
|
||||
padding: 40rpx 30rpx;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.product-title {
|
||||
font-size: 32rpx;
|
||||
color: $text-primary;
|
||||
font-weight: 500;
|
||||
margin-bottom: 30rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.exchange-info {
|
||||
@include flex-between;
|
||||
font-size: 28rpx;
|
||||
|
||||
.info-left {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.info-right {
|
||||
color: $text-secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 数量选择器区域
|
||||
.quantity-section {
|
||||
background-color: $white;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 30rpx;
|
||||
|
||||
.quantity-label {
|
||||
font-size: 32rpx;
|
||||
color: $text-primary;
|
||||
margin-bottom: 30rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.quantity-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 20rpx;
|
||||
|
||||
.quantity-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 2rpx solid $teal-color;
|
||||
border-radius: 8rpx;
|
||||
@include flex-center;
|
||||
background-color: $white;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
.btn-text {
|
||||
font-size: 36rpx;
|
||||
color: $teal-color;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
border-color: $border-color;
|
||||
cursor: not-allowed;
|
||||
|
||||
.btn-text {
|
||||
color: $text-light;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.disabled):active {
|
||||
background-color: $light-teal;
|
||||
}
|
||||
}
|
||||
|
||||
.quantity-display {
|
||||
min-width: 120rpx;
|
||||
height: 80rpx;
|
||||
background-color: $teal-color;
|
||||
border-radius: 8rpx;
|
||||
@include flex-center;
|
||||
margin: 0 10rpx;
|
||||
|
||||
.quantity-value {
|
||||
font-size: 40rpx;
|
||||
color: $white;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部操作按钮
|
||||
.bottom-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
.exchange-btn {
|
||||
background-color: $teal-color;
|
||||
height: 88rpx;
|
||||
@include flex-center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
color: $white;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 头部导航 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="病情记录"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
@@ -17,6 +19,7 @@
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
@@ -30,10 +33,11 @@
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="recordList.length === 0 && !loading">
|
||||
<empty v-if="recordList.length === 0 && !loading" :emptyDesc="'您暂未添加病情记录'"></empty>
|
||||
<!-- <view class="empty-state" v-if="recordList.length === 0 && !loading">
|
||||
<text class="empty-text">暂无病情记录</text>
|
||||
<button class="add-first-btn" @click="addRecord">添加第一条记录</button>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 时间线容器 -->
|
||||
<view class="timeline-container" v-else>
|
||||
@@ -105,6 +109,7 @@ import { onShow, onLoad } from '@dcloudio/uni-app'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import api from '@/api/api.js'
|
||||
import docUrl from '@/utils/docUrl.js'
|
||||
import empty from '@/components/empty/empty.vue'
|
||||
|
||||
const patientUuid = ref('')
|
||||
const getRecordList = (isRefresh = false) => {
|
||||
@@ -197,7 +202,7 @@ const goBack = () => {
|
||||
const addRecord = () => {
|
||||
// 跳转到添加记录页面
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/addRecord/addRecord?patientUuid=' + patientUuid.value
|
||||
url: '/pages_app/caseRecord/caseRecord?patientUuid=' + patientUuid.value
|
||||
})
|
||||
}
|
||||
|
||||
@@ -301,7 +306,10 @@ onMounted(() => {
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main-content {
|
||||
height: calc(100vh - 140rpx);
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom:0;
|
||||
padding: 40rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -390,7 +398,7 @@ onMounted(() => {
|
||||
height: 200rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
}
|
||||
|
||||
.content-image {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 头部导航 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="病情记录"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
@@ -16,10 +16,11 @@
|
||||
<text class="modify-btn" @click="saveRecord" v-if="recordUuid"
|
||||
>修改</text
|
||||
>
|
||||
<text class="save-btn" @click="saveRecord" v-else>保存</text>
|
||||
<text class="save-btn" @click="saveRecord" v-else>提交</text>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<view class="main-content">
|
||||
@@ -40,6 +41,7 @@
|
||||
class="description-input"
|
||||
v-model="des"
|
||||
placeholder="请输入患者病情"
|
||||
:adjust-position="false"
|
||||
></textarea>
|
||||
</view>
|
||||
</view>
|
||||
@@ -100,7 +102,7 @@ import { onShow, onLoad } from "@dcloudio/uni-app";
|
||||
import api from "@/api/api.js";
|
||||
import docUrl from "@/utils/docUrl.js";
|
||||
import dayjs from "dayjs";
|
||||
import { pathToBase64, base64ToPath } from "image-tools";
|
||||
import { pathToBase64} from "image-tools";
|
||||
|
||||
// 响应式数据
|
||||
const des = ref("");
|
||||
@@ -146,18 +148,14 @@ const chooseImage = () => {
|
||||
// 这里应该上传图片到服务器
|
||||
// imageList.value = [...imageList.value, ...res.tempFilePaths]
|
||||
tempImageList.value = [...tempImageList.value, ...res.tempFilePaths];
|
||||
const fileManager = uni.getFileSystemManager();
|
||||
for (let i = 0; i < res.tempFilePaths.length; i++) {
|
||||
fileManager.readFile({
|
||||
filePath: res.tempFilePaths[i],
|
||||
encoding: "base64",
|
||||
success: (res) => {
|
||||
imageList.value.push(res.data);
|
||||
},
|
||||
fail: (error) => {
|
||||
console.log("chooseImage", error);
|
||||
},
|
||||
});
|
||||
pathToBase64(res.tempFilePaths[i])
|
||||
.then((base64) => {
|
||||
imageList.value.push(base64.split(',')[1]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -246,7 +244,7 @@ const updateRecord = async () => {
|
||||
title: "修改成功",
|
||||
icon: "none",
|
||||
});
|
||||
uni.setStorageSync("caseRecord",null);
|
||||
uni.setStorageSync("caseRecord", null);
|
||||
goBack();
|
||||
}
|
||||
};
|
||||
@@ -291,19 +289,18 @@ onLoad((options) => {
|
||||
for (let i = 0; i < record.photo.length; i++) {
|
||||
console.log("url", docUrl + record.photo[i]);
|
||||
uni.request({
|
||||
url: docUrl + record.photo[i],
|
||||
method: 'GET',
|
||||
responseType: 'arraybuffer',
|
||||
success: (res) => {
|
||||
const base64 = `${uni.arrayBufferToBase64(res.data)}`
|
||||
console.log(base64);
|
||||
imageList.value.push(base64);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
})
|
||||
|
||||
url: docUrl + record.photo[i],
|
||||
method: "GET",
|
||||
responseType: "arraybuffer",
|
||||
success: (res) => {
|
||||
const base64 = `${uni.arrayBufferToBase64(res.data)}`;
|
||||
console.log(base64);
|
||||
imageList.value.push(base64);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -342,7 +339,16 @@ const saveRecord = () => {
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main-content {
|
||||
padding: 0rpx 30rpx;
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
bottom:150rpx;
|
||||
z-index:1;
|
||||
overflow-y: scroll;
|
||||
padding:0 30rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
|
||||
@@ -6,15 +6,13 @@
|
||||
<!-- 主要内容区域 -->
|
||||
<view class="main-content">
|
||||
<!-- 疾病诊断部分 -->
|
||||
<view class="section">
|
||||
<view class="section-header">
|
||||
<view class="red-bar"></view>
|
||||
<text class="section-title">疾病诊断</text>
|
||||
</view>
|
||||
<view class="header">
|
||||
<view class="section">
|
||||
<view class="section-content">
|
||||
<text class="diagnosis-text">疾病诊断: {{ pageData.diseaseName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 化验报告部分 -->
|
||||
<view class="section">
|
||||
@@ -153,7 +151,7 @@ onMounted(() => {
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.container {
|
||||
background-color: #ffffff;
|
||||
min-height: 100vh;
|
||||
@@ -205,13 +203,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
/* 头部导航样式 */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
|
||||
.back-btn {
|
||||
width: 60rpx;
|
||||
@@ -237,7 +229,13 @@ onMounted(() => {
|
||||
|
||||
/* 主要内容区域 */
|
||||
.main-content {
|
||||
padding: 0 30rpx;
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right:0;
|
||||
bottom: 0rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
}
|
||||
|
||||
.section {
|
||||
@@ -247,6 +245,7 @@ onMounted(() => {
|
||||
.section-header {
|
||||
margin-top: 20rpx;
|
||||
position: relative;
|
||||
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
@@ -277,7 +276,21 @@ onMounted(() => {
|
||||
color: #333333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.header{
|
||||
background: #8B2316;
|
||||
color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
.section{
|
||||
padding:20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.section-content{
|
||||
padding-left:0rpx;
|
||||
}
|
||||
.diagnosis-text{
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.no-report-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
@@ -306,7 +319,7 @@ onMounted(() => {
|
||||
height: 200rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
}
|
||||
|
||||
.report-image {
|
||||
|
||||
+146
-54
@@ -4,6 +4,7 @@
|
||||
<navBar title="公益咨询" />
|
||||
<view class="tabs">
|
||||
<view :class="['tab', activeTab==='new' ? 'active' : '']" @tap="switchTab('new')">新的咨询</view>
|
||||
<view class="bar"></view>
|
||||
<view :class="['tab', activeTab==='mine' ? 'active' : '']" @tap="switchTab('mine')">我已回答</view>
|
||||
</view>
|
||||
<view class="tabs-spacer"></view>
|
||||
@@ -18,16 +19,20 @@
|
||||
@scrolltolower="onReachBottom"
|
||||
lower-threshold="80"
|
||||
>
|
||||
<view v-for="(item, idx) in displayList" :key="idx" class="consult-card" @click="goDetail(item.id)">
|
||||
<view v-for="(item, idx) in displayList" :key="idx" class="consult-card" @click="goDetail(item.id,item.patientUuid)">
|
||||
<view class="card-head">
|
||||
<text class="user-name">{{ item.maskName }}</text>
|
||||
<view class="namebox">
|
||||
<text class="user-name">{{ item.maskName }}</text>
|
||||
<text class="user-avatar" v-if="bottomActive!=='quick'">({{item.sex==1?'女':'男' }}<text decode> </text>{{ calcAge(item.birthDate) }}岁)</text>
|
||||
</view>
|
||||
<text class="date">{{ item.date }}</text>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<text class="content">{{ item.content }}</text>
|
||||
<text class="content twoline">{{ item.disease_describe }}</text>
|
||||
</view>
|
||||
<view class="card-foot" v-if="bottomActive==='multi'">
|
||||
<text class="reply-count">{{ item.answer_num }}位医生已回答</text>
|
||||
<text class="reply-count" v-if="item.answer_num>0">{{ item.answer_num }}位医生已回答</text>
|
||||
<text class="reply-count-none" v-else>暂未有医生回答</text>
|
||||
<view v-if="item.tag" class="tag">{{ item.tag }}</view>
|
||||
</view>
|
||||
<view class="card-foot" v-else>
|
||||
@@ -52,7 +57,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { onShow,onBackPress,onLoad } from '@dcloudio/uni-app'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import empty from '@/components/empty/empty.vue'
|
||||
import api from '@/api/api.js'
|
||||
@@ -65,14 +70,30 @@ const pageSize=ref(10)
|
||||
const hasMore = ref(true)
|
||||
const isLoading = ref(false)
|
||||
const isRefreshing = ref(false)
|
||||
const goDetail=async(uuid)=>{
|
||||
onBackPress(()=>{
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
})
|
||||
const goDetail=async(uuid,patientUuid)=>{
|
||||
if(bottomActive.value==='quick'){
|
||||
let userId=uni.getStorageSync('userInfo').uuid.toLowerCase();
|
||||
let conversationId=userId+'|1|'+uuid.toLowerCase();
|
||||
await uni.$UIKitStore.uiStore.selectConversation(conversationId)
|
||||
navTo({
|
||||
url:'/pages_chat/chat/index?from=consult'
|
||||
if(activeTab.value==='new'){
|
||||
navTo({
|
||||
url:'/pages_app/freeDetail/freeDetail?uuid='+uuid
|
||||
})
|
||||
}else{
|
||||
let userId=uni.getStorageSync('userInfo').uuid.toLowerCase();
|
||||
uni.sendNativeEvent('goConsultPage', {
|
||||
msg: 'chat'
|
||||
},ret => {
|
||||
console.log(ret);
|
||||
})
|
||||
//let conversationId=userId+'|1|'+patientUuid.toLowerCase();
|
||||
//await uni.$UIKitStore.uiStore.selectConversation(conversationId)
|
||||
// navTo({
|
||||
// url:'/pages_chat/chat/index?from=consult&&patientUuid='+patientUuid+'&&uuid='+uuid
|
||||
// })
|
||||
}
|
||||
|
||||
}else{
|
||||
let status=0;
|
||||
if(activeTab.value==='new'){
|
||||
@@ -90,6 +111,22 @@ function maskName(name){
|
||||
const first = name.slice(0,1)
|
||||
return `${first}**`
|
||||
}
|
||||
// 根据出生日期计算年龄(birth 可以是 'YYYY-MM-DD' 或可被 Date 解析的字符串 / 时间戳)
|
||||
function calcAge(birth) {
|
||||
if (!birth) return ''
|
||||
const birthDate = new Date(birth)
|
||||
if (isNaN(birthDate.getTime())) {
|
||||
return ''
|
||||
}
|
||||
const today = new Date()
|
||||
let age = today.getFullYear() - birthDate.getFullYear()
|
||||
const m = today.getMonth() - birthDate.getMonth()
|
||||
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
||||
age--
|
||||
}
|
||||
// 年龄小于 0 视为无效
|
||||
return age >= 0 ? age : ''
|
||||
}
|
||||
const newConsultList=async(isRefresh=false)=>{
|
||||
if(isLoading.value) return
|
||||
isLoading.value = true
|
||||
@@ -106,12 +143,15 @@ const newConsultList=async(isRefresh=false)=>{
|
||||
if(res && res.code===200 && res.data && res.data.consult_list){
|
||||
const list = Array.isArray(res.data.consult_list.list) ? res.data.consult_list.list : []
|
||||
const mapped = list.map(item=>({
|
||||
maskName: maskName(item.realName || ''),
|
||||
date: (item.createDate || '').slice(0,10),
|
||||
maskName: item.realName,
|
||||
date: (item.createDate || '').slice(0,16),
|
||||
content: item.content || '',
|
||||
replyCount: 0,
|
||||
sex: item.sex || 0,
|
||||
birthDate: item.birthDate || item.birthday,
|
||||
tag: item.diseaseName || '',
|
||||
id:item.patientUuid || ''
|
||||
id:item.uuid || '',
|
||||
patientUuid:item.patientUuid || ''
|
||||
}))
|
||||
if(isRefresh){
|
||||
listNew.value = mapped
|
||||
@@ -142,12 +182,15 @@ const consultListHis=async(isRefresh=false)=>{
|
||||
if(res.code==200){
|
||||
const list = Array.isArray(res.data.list) ? res.data.list : []
|
||||
const mapped = list.map(item=>({
|
||||
maskName: maskName(item.realName || ''),
|
||||
date: (item.createDate || '').slice(0,10),
|
||||
maskName: item.realName,
|
||||
date: (item.createDate || '').slice(0,16),
|
||||
content: item.content || '',
|
||||
replyCount: 0,
|
||||
sex: item.sex || 0,
|
||||
birthDate: item.birthDate || item.birthday,
|
||||
tag: item.diseaseName || '',
|
||||
id:item.patientUuid || ''
|
||||
id:item.uuid || '',
|
||||
patientUuid:item.patientUuid || ''
|
||||
}))
|
||||
if(isRefresh){
|
||||
listMine.value = mapped
|
||||
@@ -182,7 +225,9 @@ const listNewInterrogation=async(isRefresh=false)=>{
|
||||
maskName: maskName(item.name || ''),
|
||||
date: (item.create_date || '').slice(0,10),
|
||||
content: item.your_question || '',
|
||||
disease_describe:item.your_question || '',
|
||||
disease_describe:item.disease_describe || '',
|
||||
sex: item.sex || 0,
|
||||
birthDate: item.birthday || '',
|
||||
answer_num: item.answer_num || 0,
|
||||
tag: item.disease_name || '',
|
||||
id:item.step1_uuid || ''
|
||||
@@ -220,6 +265,8 @@ const listMyAnsweredInterrogation=async(isRefresh=false)=>{
|
||||
date: (item.create_date || '').slice(0,10),
|
||||
content: item.your_question || '',
|
||||
disease_describe:item.disease_describe || '',
|
||||
sex: item.sex || 0,
|
||||
birthDate: item.birthday || '',
|
||||
answer_num: item.answer_num || 0,
|
||||
tag: item.disease_name || '',
|
||||
id:item.step1_uuid || ''
|
||||
@@ -237,20 +284,22 @@ const listMyAnsweredInterrogation=async(isRefresh=false)=>{
|
||||
isRefreshing.value = false
|
||||
}
|
||||
};
|
||||
onShow(()=>{
|
||||
onLoad(()=>{
|
||||
page.value = 1
|
||||
hasMore.value = true;
|
||||
listNew.value = [];
|
||||
listMine.value=[];
|
||||
if(bottomActive.value==='quick'){
|
||||
if(activeTab.value==='new'){
|
||||
newConsultList(true)
|
||||
newConsultList(false)
|
||||
}else{
|
||||
consultListHis(true)
|
||||
consultListHis(false)
|
||||
}
|
||||
}else{
|
||||
if(activeTab.value==='new'){
|
||||
listNewInterrogation(true)
|
||||
listNewInterrogation(false)
|
||||
}else{
|
||||
listMyAnsweredInterrogation(true)
|
||||
listMyAnsweredInterrogation(false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -267,18 +316,20 @@ function switchTab(key) {
|
||||
isLoading.value = false;
|
||||
listNew.value = [];
|
||||
listMine.value=[];
|
||||
page.value = 1
|
||||
hasMore.value = true;
|
||||
if(bottomActive.value==='quick'){
|
||||
if(activeTab.value==='new'){
|
||||
newConsultList(true)
|
||||
newConsultList(false)
|
||||
}else{
|
||||
consultListHis(true)
|
||||
consultListHis(false)
|
||||
}
|
||||
|
||||
}else{
|
||||
if(activeTab.value==='new'){
|
||||
listNewInterrogation(true)
|
||||
listNewInterrogation(false)
|
||||
}else{
|
||||
listMyAnsweredInterrogation(true)
|
||||
listMyAnsweredInterrogation(false)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -294,25 +345,32 @@ function goBack() {
|
||||
}
|
||||
|
||||
// 底部tab交互
|
||||
const bottomActive = ref('quick')
|
||||
const bottomActive = ref('multi')
|
||||
const switchBottomTab=(key)=>{
|
||||
isLoading.value = false;
|
||||
bottomActive.value = key;
|
||||
page.value = 1
|
||||
hasMore.value = true;
|
||||
listNew.value = [];
|
||||
listMine.value=[];
|
||||
if(key=='quick'){
|
||||
try {
|
||||
plus.runtime.quit();
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
if(activeTab.value==='new'){
|
||||
newConsultList(true)
|
||||
newConsultList(false)
|
||||
}else{
|
||||
consultListHis(true)
|
||||
consultListHis(false)
|
||||
}
|
||||
|
||||
}else{
|
||||
if(activeTab.value==='new'){
|
||||
console.log('listNewInterrogation')
|
||||
listNewInterrogation(true);
|
||||
listNewInterrogation(false);
|
||||
}else{
|
||||
listMyAnsweredInterrogation(true)
|
||||
listMyAnsweredInterrogation(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,6 +380,8 @@ function onRefresh(){
|
||||
isRefreshing.value = true
|
||||
page.value = 1
|
||||
hasMore.value = true
|
||||
listNew.value = [];
|
||||
listMine.value=[];
|
||||
if(bottomActive.value==='quick'){
|
||||
if(activeTab.value==='new'){
|
||||
newConsultList(true)
|
||||
@@ -372,35 +432,49 @@ function onReachBottom(){
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 44px;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 1px 0 rgba(0,0,0,0.06);
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
.bar{
|
||||
width:1px;
|
||||
height: 100%;
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-size: 36rpx;
|
||||
color: #7a7a7a;
|
||||
padding: 10px 0;
|
||||
&.active { color: #8B2316; position: relative; }
|
||||
&.active::after { content: ''; position: absolute; left: 25%; right: 25%; bottom: 2px; height: 3px; background-color: #8B2316; border-radius: 2px; }
|
||||
|
||||
}
|
||||
}
|
||||
.tabs-spacer { height: 44px; }
|
||||
.namebox{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.user-avatar{
|
||||
margin-left: 10rpx;
|
||||
font-size:32rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.list-scroll {
|
||||
flex: 1;
|
||||
position: fixed;
|
||||
top: 228rpx;
|
||||
bottom: 136rpx;
|
||||
padding: 8px 0px 0 0px;
|
||||
margin: 20rpx 30rpx 0;
|
||||
top: calc(var(--status-bar-height) + 44px + 48px);
|
||||
bottom:56px;
|
||||
margin: 20rpx rpx 0;
|
||||
box-sizing: border-box;
|
||||
width:auto;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.consult-card {
|
||||
@@ -412,8 +486,8 @@ function onReachBottom(){
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
.user-name { font-size: 16px; color: #a31712; }
|
||||
.date { font-size: 14px; color: #9aa0a6; }
|
||||
.user-name { font-size: 36rpx; color: #a31712; }
|
||||
.date { font-size: 36rpx; color: #9aa0a6; }
|
||||
}
|
||||
.card-body {
|
||||
background: #efefef;
|
||||
@@ -443,31 +517,49 @@ function onReachBottom(){
|
||||
}
|
||||
display: flex; align-items: center; justify-content: space-between; margin-top: 8px;
|
||||
.reply-count { font-size:28rpx; color: #8B2316; }
|
||||
.reply-count-none{
|
||||
font-size:28rpx;
|
||||
color: #999;
|
||||
position: relative;
|
||||
padding-left: 25rpx;
|
||||
}
|
||||
.reply-count-none::after{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
background: red;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.tag {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8rpx 16rpx; background: #fff5f5; color: #a31712; border-radius: 28rpx; font-size: 24rpx; border:2rpx solid #a31712;}
|
||||
padding: 0rpx 16rpx; background: #fff; color: #a31712; border-radius: 28rpx; font-size: 24rpx; border:2rpx solid #a31712;}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
position: fixed;
|
||||
left: 0; right: 0; bottom: 0;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 -2px 8px rgba(0,0,0,0.06);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 8px 12px;
|
||||
gap: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.bottom-tab {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
color: #a31712;
|
||||
background-color: #fff5f5;
|
||||
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
background-color: #fff;
|
||||
}
|
||||
.bottom-tab.active {
|
||||
background-color: #a31712;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,935 @@
|
||||
<template>
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="视频缓存"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
<template #right>
|
||||
<view class="nav-actions">
|
||||
<view class="nav-edit" @click="toggleEdit">
|
||||
<text>{{ isEditMode ? "取消" : "编辑" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
<view class="download-video-page">
|
||||
<!-- 标签页 -->
|
||||
<view class="tabs-container">
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'completed' }"
|
||||
@click="switchTab('completed')"
|
||||
>
|
||||
已完成
|
||||
</view>
|
||||
<view class="tab-divider"></view>
|
||||
<view
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === 'downloading' }"
|
||||
@click="switchTab('downloading')"
|
||||
>
|
||||
缓存中
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容列表 -->
|
||||
<scroll-view class="content-scroll" scroll-y :scroll-top="scrollTop">
|
||||
<view v-if="currentList.length === 0" class="empty-state">
|
||||
<text>暂无数据</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="(item, index) in currentList"
|
||||
:key="item.id || index"
|
||||
class="video-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<!-- 编辑模式下的多选框 -->
|
||||
<view
|
||||
v-if="isEditMode"
|
||||
class="checkbox-wrapper"
|
||||
@click.stop="toggleSelectItem(item)"
|
||||
>
|
||||
<view
|
||||
class="checkbox"
|
||||
:class="{ checked: isItemSelected(item) }"
|
||||
>
|
||||
<uni-icons
|
||||
v-if="isItemSelected(item)"
|
||||
type="checkmarkempty"
|
||||
size="16"
|
||||
color="#ffffff"
|
||||
></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 缩略图 -->
|
||||
<image
|
||||
class="video-thumbnail"
|
||||
:src="docUrl + item.imgpath"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
|
||||
<!-- 内容信息 -->
|
||||
<view class="video-info">
|
||||
<view class="video-title">{{ item.name || "视频标题" }}</view>
|
||||
<view class="video-author">{{ item.author || "作者" }}</view>
|
||||
|
||||
<!-- 时长和大小 -->
|
||||
<view class="video-meta" v-if="item.status === 'completed'">
|
||||
<uni-icons
|
||||
type="clock"
|
||||
size="12"
|
||||
color="#999999"
|
||||
class="meta-icon"
|
||||
></uni-icons>
|
||||
<text class="meta-text"><text v-if="item.duration">{{ formatDuration(item.duration) }}</text></text>
|
||||
<text class="meta-size">{{ formatSize(item.size) }}</text>
|
||||
</view>
|
||||
<view class="video-meta video-status" v-if="item.status == 'downloading' || item.status == 'paused'">
|
||||
<view class="status-icon">
|
||||
<image :src="item.status == 'paused' ? playImg : pauseImg" mode="aspectFill"></image>
|
||||
<text>{{ item.status == 'paused' ? '继续' : '暂停' }}</text>
|
||||
</view>
|
||||
<view class="box">
|
||||
<!-- <view class="video-progress-bar">
|
||||
<view class="video-progress-bar-inner" :style="{ width: item.progress + '%' }"></view>
|
||||
</view> -->
|
||||
<!-- <text>{{ item.progress + '%' }}</text> -->
|
||||
<view class="size-box">{{ formatSize(item.downloadSize) }}/{{ formatSize(item.totalSize) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 编辑模式下的删除按钮 -->
|
||||
<!-- <view
|
||||
v-if="isEditMode"
|
||||
class="delete-btn"
|
||||
@click.stop="deleteItem(item, index)"
|
||||
>
|
||||
<text>删除</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部存储信息 -->
|
||||
<view class="bottom-box">
|
||||
<view class="storage-info">
|
||||
<text
|
||||
>手机存储:总空间{{ storageInfo.total }}/剩余{{
|
||||
storageInfo.available
|
||||
}}可用</text
|
||||
>
|
||||
</view>
|
||||
<view class="footer-btn" v-if="isEditMode">
|
||||
<view class="footer-btn-item select" @click="clearAll">
|
||||
<text v-if="!isAllSelect">全选</text>
|
||||
<text v-else>取消全选</text>
|
||||
</view>
|
||||
<view class="bar"></view>
|
||||
<view class="footer-btn-item del" @click="delTask">
|
||||
删除<text v-if="selectedItems.length > 0">({{ selectedItems.length }})</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, nextTick } from "vue";
|
||||
import downloadStore from "@/store/downloadStoreVideo.js";
|
||||
import { onLoad, onShow,onUnload,onBackPress} from "@dcloudio/uni-app";
|
||||
import playImg from "@/static/down_true.png";
|
||||
import pauseImg from "@/static/down_false.png";
|
||||
import navTo from "@/utils/navTo";
|
||||
import docUrl from "@/utils/docUrl";
|
||||
const downloadTasks = ref([]);
|
||||
const unsubscribe = ref(null);
|
||||
const isAllSelect = ref(false);
|
||||
const selectedItems = ref([]);
|
||||
// 响应式数据
|
||||
const activeTab = ref("completed"); // completed: 已完成, downloading: 缓存中
|
||||
const isEditMode = ref(false);
|
||||
const scrollTop = ref(0);
|
||||
const storageInfo = ref({
|
||||
total: "461.31G",
|
||||
available: "312.92G",
|
||||
});
|
||||
const delTask=()=>{
|
||||
if(selectedItems.value.length === 0){
|
||||
uni.showToast({
|
||||
title: "请选择要删除的缓存",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要删除选中的缓存吗?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 从后往前删除,避免索引变化问题
|
||||
const idsToDelete = [...selectedItems.value];
|
||||
idsToDelete.forEach(id => {
|
||||
const taskIndex = downloadTasks.value.findIndex(t => t.id === id);
|
||||
if (taskIndex !== -1) {
|
||||
removeTask(taskIndex);
|
||||
}
|
||||
});
|
||||
// 清空选择
|
||||
selectedItems.value = [];
|
||||
isAllSelect.value = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const clearAll=()=>{
|
||||
if(!isAllSelect.value){
|
||||
// 全选当前列表的所有项
|
||||
selectedItems.value = currentList.value.map(item => item.id);
|
||||
isAllSelect.value = true;
|
||||
}else{
|
||||
// 取消全选
|
||||
selectedItems.value = [];
|
||||
isAllSelect.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断项是否被选中
|
||||
const isItemSelected = (item) => {
|
||||
return selectedItems.value.includes(item.id);
|
||||
}
|
||||
onBackPress(() => {
|
||||
if(from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 切换项的选中状态
|
||||
const toggleSelectItem = (item) => {
|
||||
const index = selectedItems.value.indexOf(item.id);
|
||||
if (index > -1) {
|
||||
selectedItems.value.splice(index, 1);
|
||||
} else {
|
||||
selectedItems.value.push(item.id);
|
||||
}
|
||||
// 更新全选状态
|
||||
isAllSelect.value = selectedItems.value.length === currentList.value.length && currentList.value.length > 0;
|
||||
}
|
||||
|
||||
// 计算当前显示的列表
|
||||
const currentList = computed(() => {
|
||||
let list = [];
|
||||
if (activeTab.value === "completed") {
|
||||
list = downloadTasks.value.filter((task) => task.status === "completed");
|
||||
} else {
|
||||
list = downloadTasks.value.filter(
|
||||
(task) => task.status === "downloading" || task.status === "paused"
|
||||
);
|
||||
}
|
||||
// 当列表变化时,更新全选状态
|
||||
nextTick(() => {
|
||||
if (isAllSelect.value && selectedItems.value.length !== list.length) {
|
||||
isAllSelect.value = false;
|
||||
}
|
||||
});
|
||||
return list;
|
||||
});
|
||||
// 方法
|
||||
const goBack = () => {
|
||||
if(from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack()
|
||||
};
|
||||
};
|
||||
|
||||
const switchTab = (tab) => {
|
||||
activeTab.value = tab;
|
||||
isEditMode.value = false;
|
||||
// 切换标签时清空选择
|
||||
selectedItems.value = [];
|
||||
isAllSelect.value = false;
|
||||
// 切换到缓存中时,滚动到顶部
|
||||
if (tab === 'downloading') {
|
||||
// 先设置为一个非0值,然后在下一个tick设置为0,确保滚动触发
|
||||
scrollTop.value = 0.01;
|
||||
nextTick(() => {
|
||||
scrollTop.value = 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toggleEdit = () => {
|
||||
isEditMode.value = !isEditMode.value;
|
||||
// 退出编辑模式时清空选择
|
||||
if (!isEditMode.value) {
|
||||
selectedItems.value = [];
|
||||
isAllSelect.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleItemClick = (item) => {
|
||||
if (isEditMode.value) {
|
||||
// 编辑模式下,点击项切换选中状态
|
||||
toggleSelectItem(item);
|
||||
return;
|
||||
}
|
||||
// 跳转到视频详情或播放页面
|
||||
if (item.status === "completed") {
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/videoDetail/videoDetail?id=${item.id}&from=download`,
|
||||
});
|
||||
}else if(item.status === "downloading"){
|
||||
let index=downloadTasks.value.findIndex(t => t.id === item.id);
|
||||
if(index !== -1){
|
||||
pauseTask(index);
|
||||
}
|
||||
}else if(item.status === "paused"){
|
||||
let index=downloadTasks.value.findIndex(t => t.id === item.id);
|
||||
if(index !== -1){
|
||||
resumeTask(index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteItem = (item, index) => {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要删除这个缓存吗?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 从store中删除
|
||||
const taskIndex = downloadTasks.value.findIndex((t) => t.id === item.id);
|
||||
if (taskIndex !== -1) {
|
||||
removeTask(taskIndex);
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const formatDuration = (duration) => {
|
||||
if (!duration) return "00:00:00";
|
||||
// 如果duration是秒数
|
||||
if (typeof duration === "number") {
|
||||
const hours = Math.floor(duration / 3600);
|
||||
const minutes = Math.floor((duration % 3600) / 60);
|
||||
const seconds = duration % 60;
|
||||
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(
|
||||
2,
|
||||
"0"
|
||||
)}:${String(seconds).padStart(2, "0")}`;
|
||||
}
|
||||
// 如果已经是格式化字符串
|
||||
return duration;
|
||||
};
|
||||
|
||||
const formatSize = (size) => {
|
||||
if (!size) return "0M";
|
||||
// 如果size是字节数
|
||||
|
||||
const mb = (Number(size) / 1024 / 1024).toFixed(2);
|
||||
return `${mb}M`;
|
||||
|
||||
// 如果已经是格式化字符串
|
||||
return size;
|
||||
};
|
||||
const from = ref('');
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
if(options.type){
|
||||
switchTab('downloading')
|
||||
}
|
||||
// 从store同步任务列表
|
||||
syncTasksFromStore();
|
||||
// 监听store变化
|
||||
unsubscribe.value = downloadStore.addListener((tasks) => {
|
||||
downloadTasks.value = tasks;
|
||||
});
|
||||
console.log(11111);
|
||||
console.log(downloadTasks.value);
|
||||
// 恢复正在下载的任务
|
||||
resumeDownloadingTasks();
|
||||
}),
|
||||
onShow(() => {
|
||||
// 页面显示时同步最新任务列表
|
||||
syncTasksFromStore();
|
||||
// 检查并恢复下载任务
|
||||
resumeDownloadingTasks();
|
||||
}),
|
||||
onUnload(() => {
|
||||
// 页面 卸载时取消监听
|
||||
if (unsubscribe.value) {
|
||||
unsubscribe.value();
|
||||
}
|
||||
});
|
||||
|
||||
const getStorageInfo = () => {
|
||||
// 获取手机存储信息
|
||||
// #ifdef APP-PLUS
|
||||
if (uni.getSystemInfoSync().platform !== 'android') {
|
||||
uni.sendNativeEvent('getSysSpace',{
|
||||
msg: 'getSysSpace'
|
||||
},(res) => {
|
||||
storageInfo.value = {
|
||||
total: res.total,
|
||||
available: res.available,
|
||||
};
|
||||
});
|
||||
}else{
|
||||
// 1. 导入所需的Android类
|
||||
const Environment = plus.android.importClass("android.os.Environment");
|
||||
const StatFs = plus.android.importClass("android.os.StatFs");
|
||||
|
||||
try {
|
||||
// 2. 获取内部存储的数据目录(File对象)
|
||||
const dataDirectory = Environment.getDataDirectory(); // 这是一个Java File对象
|
||||
|
||||
// 3. 关键修正:使用 plus.android.invoke 调用 File 对象的 getPath 方法
|
||||
const dataDirectoryPath = plus.android.invoke(dataDirectory, "getPath");
|
||||
// 现在 dataDirectoryPath 是一个字符串,表示路径
|
||||
|
||||
// 4. 创建 StatFs 对象,传入路径字符串
|
||||
const statFs = new StatFs(dataDirectoryPath);
|
||||
|
||||
// 5. 使用 invoke 调用 StatFs 的方法获取存储块信息
|
||||
const blockSize = plus.android.invoke(statFs, "getBlockSize");
|
||||
const availableBlocks = plus.android.invoke(statFs, "getAvailableBlocks");
|
||||
const totalBlocks = plus.android.invoke(statFs, "getBlockCount");
|
||||
|
||||
|
||||
// 6. 计算可用空间和总空间(单位:字节)
|
||||
const availableSizeInBytes = blockSize * availableBlocks;
|
||||
const totalSizeInBytes = blockSize * totalBlocks;
|
||||
|
||||
|
||||
// 7. 转换为常用单位
|
||||
const availableSizeInGB = (availableSizeInBytes / (1024 * 1024 * 1024)).toFixed(2);
|
||||
const availableSizeInMB = (availableSizeInBytes / (1024 * 1024)).toFixed(2);
|
||||
const totalSizeInGB = (totalSizeInBytes / (1024 * 1024 * 1024)).toFixed(2);
|
||||
|
||||
|
||||
// console.log(`可用存储空间:${availableSizeInBytes} 字节`);
|
||||
// console.log(`可用存储空间:${availableSizeInMB} MB`);
|
||||
// console.log(`可用存储空间:${availableSizeInGB} GB`);
|
||||
|
||||
// 可以根据需要返回不同单位的值
|
||||
storageInfo.value = {
|
||||
total: totalSizeInGB+"G",
|
||||
available: availableSizeInGB+"G",
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取存储信息时发生错误:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #endif
|
||||
};
|
||||
const syncTasksFromStore=()=> {
|
||||
downloadTasks.value = downloadStore.getTasks();
|
||||
};
|
||||
// 添加下载任务
|
||||
const addDownloadTask = (item) => {
|
||||
// 使用store添加任务
|
||||
const taskIndex = downloadStore.addTask(item);
|
||||
|
||||
// 同步任务列表
|
||||
syncTasksFromStore();
|
||||
|
||||
// 开始下载
|
||||
startDownload(taskIndex);
|
||||
};
|
||||
|
||||
// 开始下载
|
||||
const startDownload = (index) => {
|
||||
const taskItem = downloadStore.getTask(index);
|
||||
if (!taskItem) return;
|
||||
|
||||
const task = uni.downloadFile({
|
||||
url: taskItem.url,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
filePath: res.tempFilePath,
|
||||
});
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
console.log(res);
|
||||
uni.saveFile({
|
||||
tempFilePath: res.tempFilePath,
|
||||
success: function (res) {
|
||||
uni.getSavedFileInfo({
|
||||
filePath: res.savedFilePath,
|
||||
success: function (res) {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
realyPath: res.savedFilePath,
|
||||
size: res.size,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
console.error("下载失败:", err);
|
||||
uni.showToast({
|
||||
title: "下载失败: " + (err.errMsg || "未知错误"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// 监听下载进度
|
||||
task.onProgressUpdate((update) => {
|
||||
const currentTask = downloadStore.getTask(index);
|
||||
if (currentTask && currentTask.status === "downloading") {
|
||||
console.log(update.progress);
|
||||
downloadStore.updateTask(index, {
|
||||
progress: update.progress,
|
||||
downloadSize: update.totalBytesWritten,
|
||||
totalSize: update.totalBytesExpectedToWrite,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 保存task对象到store(用于暂停/继续)
|
||||
downloadStore.updateTask(index, {
|
||||
task: task,
|
||||
});
|
||||
};
|
||||
|
||||
// 暂停任务
|
||||
const pauseTask = (index) => {
|
||||
const taskItem = downloadStore.getTask(index);
|
||||
if (taskItem && taskItem.task) {
|
||||
taskItem.task.abort();
|
||||
downloadStore.updateTask(index, {
|
||||
status: "paused",
|
||||
task: null,
|
||||
});
|
||||
uni.showToast({
|
||||
title: "已暂停",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 继续任务
|
||||
const resumeTask = (index) => {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "downloading",
|
||||
progress: 0, // 重新开始(uni.downloadFile不支持断点续传)
|
||||
});
|
||||
startDownload(index);
|
||||
};
|
||||
|
||||
// 删除任务
|
||||
const removeTask = (index) => {
|
||||
downloadStore.removeTask(index);
|
||||
syncTasksFromStore();
|
||||
};
|
||||
|
||||
// 打开文件
|
||||
const openFile = (filePath) => {
|
||||
// #ifdef APP-PLUS
|
||||
plus.runtime.openFile(filePath);
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
uni.showToast({
|
||||
title: "请在APP中打开",
|
||||
icon: "none",
|
||||
});
|
||||
// #endif
|
||||
};
|
||||
|
||||
// 获取文件名
|
||||
const getFileName = (url) => {
|
||||
if (!url) return "未知文件";
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
const pathname = urlObj.pathname;
|
||||
const fileName = pathname.split("/").pop();
|
||||
return fileName || "下载文件";
|
||||
} catch (e) {
|
||||
// 如果不是完整URL,尝试从路径中提取
|
||||
const parts = url.split("/");
|
||||
return parts[parts.length - 1] || "下载文件";
|
||||
}
|
||||
};
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
downloading: "下载中",
|
||||
paused: "已暂停",
|
||||
completed: "已完成",
|
||||
failed: "下载失败",
|
||||
};
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 恢复正在下载的任务
|
||||
const resumeDownloadingTasks = () => {
|
||||
// 使用 nextTick 确保在页面渲染后再恢复下载任务
|
||||
nextTick(() => {
|
||||
downloadStore.resumeDownloadingTasks((index) => {
|
||||
// 重新开始下载(uni.downloadFile不支持断点续传,所以从0开始)
|
||||
console.log("恢复下载任务:", downloadStore.getTask(index)?.url);
|
||||
startDownload(index);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getStorageInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page{
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.size-box{
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
justify-content: flex-end;
|
||||
|
||||
white-space: nowrap;
|
||||
font-size: 24rpx;
|
||||
color:#8b2316
|
||||
}
|
||||
.box{
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
justify-content: flex-end;
|
||||
margin-left: 30rpx;
|
||||
text{
|
||||
width: 40rpx;
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
font-size: 24rpx;
|
||||
color:#8b2316
|
||||
}
|
||||
}
|
||||
.download-video-page {
|
||||
width: 100%;
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
height: calc(100vh - var(--status-bar-height) - 44px);
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.footer-btn{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
height: 100rpx;
|
||||
background-color: #ffffff;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.select{
|
||||
flex:1;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #333;
|
||||
}
|
||||
.del{
|
||||
height: 100rpx;
|
||||
flex:1;
|
||||
color:red;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.bar{
|
||||
width: 1px;
|
||||
height: 40rpx;
|
||||
|
||||
background-color: #999;
|
||||
}
|
||||
}
|
||||
.video-progress-bar {
|
||||
flex:1;
|
||||
height: 10rpx;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.video-progress-bar-inner {
|
||||
height: 10rpx;
|
||||
background-color: #8b2316;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.nav-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 44px;
|
||||
padding: 0 15px;
|
||||
background-color: #ffffff;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-back {
|
||||
width: 40px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
font-size: 28px;
|
||||
color: #8b2316;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #8b2316;
|
||||
}
|
||||
|
||||
.nav-edit {
|
||||
width: 40px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.tabs-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 50px;
|
||||
background-color: #ffffff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
position: sticky;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #999999;
|
||||
position: relative;
|
||||
|
||||
&.active {
|
||||
color: #8b2316;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-divider {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 200rpx;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100px 0;
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.video-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.video-thumbnail {
|
||||
width: 120px;
|
||||
height: 80px;
|
||||
border-radius: 4px;
|
||||
background-color: #f5f5f5;
|
||||
margin-right: 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.video-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.video-title {
|
||||
font-size: 15px;
|
||||
color: #333333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.video-author {
|
||||
font-size: 13px;
|
||||
color: #666666;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.video-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
}
|
||||
.video-status{
|
||||
display: flex;
|
||||
|
||||
|
||||
justify-content: space-between;
|
||||
.status-icon{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
image{
|
||||
width:30rpx;
|
||||
height: 29rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
text{
|
||||
white-space: nowrap;
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.meta-icon {
|
||||
margin-right: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.meta-text {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.meta-size {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #d0d0d0;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #ffffff;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.checked {
|
||||
background-color: #8b2316;
|
||||
border-color: #8b2316;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 8px 16px;
|
||||
background-color: #ff4444;
|
||||
color: #ffffff;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.bottom-box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.storage-info {
|
||||
padding: 12px 15px;
|
||||
background-color: #f8f8f8;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
|
||||
|
||||
<!-- 顶部导航栏 -->
|
||||
<navBar title="意见反馈"></navBar>
|
||||
<navBar :title="'投诉反馈'"></navBar>
|
||||
|
||||
<!-- 反馈输入区域 -->
|
||||
<view class="feedback-input-container">
|
||||
<view class="input-area">
|
||||
<text class="input-placeholder" v-show="!feedbackText">欢迎对我们的软件提供建议,帮助我们更好更快的改进"肝胆相照"APP (200字以内)</text>
|
||||
<!-- <text class="input-placeholder" v-show="!feedbackText">欢迎对我们的软件提供建议,帮助我们更好更快的改进"肝胆相照"APP (200字以内)</text> -->
|
||||
<textarea
|
||||
class="feedback-textarea"
|
||||
v-model="feedbackText"
|
||||
:maxlength="200"
|
||||
placeholder=""
|
||||
placeholder="尊敬的医生您好,若在交流过程中发现患者发布不适当内容,请您及时填写相关信息,我们将第一时间处理,谢谢您的支持。"
|
||||
:adjust-position="false"
|
||||
@input="onInput"
|
||||
></textarea>
|
||||
<!-- <view class="voice-button" @click="toggleVoiceInput">
|
||||
@@ -24,7 +25,7 @@
|
||||
|
||||
<!-- 底部提交按钮 -->
|
||||
<view class="submit-container">
|
||||
<button class="submit-btn" @click="submitFeedback" :disabled="!feedbackText.trim()">
|
||||
<button class="submit-btn" @click="submitFeedback" >
|
||||
提交
|
||||
</button>
|
||||
</view>
|
||||
@@ -126,8 +127,15 @@
|
||||
|
||||
/* 反馈输入区域 */
|
||||
.feedback-input-container {
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 160rpx;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
padding: 30rpx;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
@@ -199,10 +207,10 @@
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background-color: #ffffff;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
background-color: #fff;
|
||||
border: 2rpx solid #8B2316;
|
||||
border-radius: 8rpx;
|
||||
color: #ff0000;
|
||||
color: #8B2316;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
<template>
|
||||
<view class="visit-note-page">
|
||||
<uni-nav-bar
|
||||
<navBar :title="'随访详情'" />
|
||||
<!-- <uni-nav-bar
|
||||
left-icon="left"
|
||||
title="随访详情"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
|
||||
</uni-nav-bar>
|
||||
</uni-nav-bar> -->
|
||||
|
||||
<!-- 患者行 -->
|
||||
<view class="row" @click="noop">
|
||||
<view class="contentbox">
|
||||
<view class="row" @click="noop">
|
||||
<text class="row-label">患者</text>
|
||||
<text class="row-value">{{ patientName }}</text>
|
||||
</view>
|
||||
@@ -27,7 +29,8 @@
|
||||
|
||||
<!-- 输入框区域 -->
|
||||
<view class="note-box">
|
||||
<textarea class="note-textarea" v-model.trim="note" placeholder="请填写随访内容" auto-height :maxlength="200" />
|
||||
<textarea class="note-textarea" v-model.trim="note" placeholder="请填写随访内容" auto-height :maxlength="200" :adjust-position="false"/>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 底部删除按钮 -->
|
||||
<view class="fixed-footer">
|
||||
@@ -41,6 +44,7 @@
|
||||
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||||
import api from '@/api/api.js'
|
||||
const patientName = ref('')
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
const note = ref('请近日来医院复诊、复查')
|
||||
const datetime = ref('')
|
||||
const followUpUuid = ref('')
|
||||
@@ -91,19 +95,29 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contentbox{
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: scroll;
|
||||
bottom:128rpx;
|
||||
z-index:1;
|
||||
|
||||
}
|
||||
.visit-note-page{
|
||||
min-height: 100vh; background:#f5f5f5; padding-bottom: 120rpx;
|
||||
background:#f5f5f5; padding-bottom: 120rpx;
|
||||
}
|
||||
.nav-right{ display:flex; align-items:center; }
|
||||
.submit-text{ color:#8B2316; font-size: 30rpx; }
|
||||
|
||||
.row{
|
||||
margin-top: 20rpx; background:#fff; padding: 26rpx 30rpx; display:flex; align-items:center; justify-content:space-between; border-bottom: 1rpx solid #eee;
|
||||
background:#fff; padding: 26rpx 30rpx; display:flex; align-items:center; justify-content:space-between; border-bottom: 1rpx solid #eee;
|
||||
.row-label{ font-size: 32rpx; color:#8B2316; font-weight: 500; }
|
||||
.row-value{ font-size: 32rpx; color:#333; }
|
||||
}
|
||||
|
||||
.section-title{ background:#fff; padding: 22rpx 30rpx; color:#8B2316; font-size: 30rpx; border-top: 1rpx solid #eee; border-bottom: 1rpx solid #eee; }
|
||||
.section-title{ background:#fff; padding: 22rpx 30rpx; color:#8B2316; font-size: 30rpx;border-bottom: 1rpx solid #eee; }
|
||||
|
||||
.note-box{ background:#fff; padding: 20rpx 24rpx; }
|
||||
.note-textarea{
|
||||
|
||||
@@ -0,0 +1,513 @@
|
||||
<template>
|
||||
<view class="consult-detail-page">
|
||||
<!-- 导航栏 -->
|
||||
<navBar title="咨询详情" />
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<scroll-view scroll-y class="content-scroll">
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-section">
|
||||
<view class="user-info">
|
||||
<image v-if="userInfo.avatar" :src="userInfo.avatar" class="user-avatar" mode="aspectFill" />
|
||||
<view class="user-details">
|
||||
<view class="user-name">
|
||||
<text class="name">{{ userInfo.name }}</text>
|
||||
<text class="gender-age" v-if="userInfo.gender !== '未知'">({{ userInfo.gender }} {{ userInfo.age }}岁)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 疾病标签和日期 -->
|
||||
<view class="tag-date-row">
|
||||
<view class="disease-tag">
|
||||
<text class="tag-text">{{ questionInfo.diseaseTag }}</text>
|
||||
</view>
|
||||
<view class="date">{{ questionInfo.date }}</view>
|
||||
</view>
|
||||
|
||||
<!-- 问题内容 -->
|
||||
<view class="question-content">
|
||||
<text class="content-text">{{ questionInfo.diseaseDescribe }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 疾病描述 -->
|
||||
<!-- <view v-if="questionInfo.diseaseDescribe" class="disease-describe">
|
||||
<view class="describe-title">疾病描述:</view>
|
||||
<text class="describe-text">{{ questionInfo.diseaseDescribe }}</text>
|
||||
</view> -->
|
||||
|
||||
<!-- 图片网格 -->
|
||||
<view class="image-grid" v-if="questionInfo.images && questionInfo.images.length > 0">
|
||||
<image
|
||||
v-for="(img, index) in questionInfo.images"
|
||||
:key="index"
|
||||
:src="docUrl+img.path"
|
||||
class="grid-image"
|
||||
mode="aspectFill"
|
||||
@click="previewImage(docUrl+img.path, index)"
|
||||
/>
|
||||
</view>
|
||||
<view class="bar"></view>
|
||||
|
||||
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部固定区域 -->
|
||||
<view class="bottom-fixed">
|
||||
<!-- 特别声明 -->
|
||||
<!-- 编辑按钮 -->
|
||||
<view class="edit-btn" @click="answerConsult">
|
||||
我要回答
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import detailImg from "@/static/iv_jiwangshi.png"
|
||||
import navTo from '@/utils/navTo.js'
|
||||
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||||
import docUrl from '@/utils/docUrl'
|
||||
import api from "@/api/api.js"
|
||||
const uuid = ref('');
|
||||
const step1_uuid = ref('');
|
||||
let patientUuid = ref('');
|
||||
const status = ref(0);
|
||||
const hasAnswer = ref(false);
|
||||
onLoad((options) => {
|
||||
uuid.value = options.uuid
|
||||
status.value = options.status || 0
|
||||
|
||||
})
|
||||
|
||||
const consultDetail=()=>{
|
||||
api.consultDetail({
|
||||
uuid:uuid.value
|
||||
}).then(res=>{
|
||||
console.log('咨询详情数据:', res)
|
||||
if(res.code === 200 && res.data && res.data.detail) {
|
||||
const detail = res.data.detail
|
||||
patientUuid.value = detail.patientUuid;
|
||||
// 更新用户信息
|
||||
userInfo.value = {
|
||||
name: detail.patientName ,
|
||||
gender: '未知', // 新数据结构中没有性别信息
|
||||
age: '未知' // 新数据结构中没有年龄信息
|
||||
}
|
||||
|
||||
// 更新问题信息
|
||||
questionInfo.value = {
|
||||
date: detail.createDate ? formatDate(detail.createDate) : '未知',
|
||||
diseaseTag: detail.diseaseName || '未知疾病',
|
||||
content: detail.content || '暂无问题描述',
|
||||
images: res.data.imgList?res.data.imgList:[],
|
||||
your_question: detail.content || '',
|
||||
diseaseDescribe: detail.content || '' // 将咨询内容作为疾病描述显示
|
||||
}
|
||||
|
||||
// 更新患者头像
|
||||
if(detail.patientPhoto) {
|
||||
userInfo.value.avatar = docUrl + detail.patientPhoto
|
||||
}
|
||||
|
||||
// 更新状态信息
|
||||
status.value = detail.state || 0
|
||||
|
||||
console.log('更新后的用户信息:', userInfo.value)
|
||||
console.log('更新后的问题信息:', questionInfo.value)
|
||||
} else {
|
||||
console.error('获取咨询详情失败:', res)
|
||||
uni.showToast({
|
||||
title: res.msg || '获取咨询详情失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}).catch(err => {
|
||||
console.error('请求咨询详情失败:', err)
|
||||
uni.showToast({
|
||||
title: '网络请求失败',
|
||||
icon: 'none'
|
||||
})
|
||||
})
|
||||
}
|
||||
const countConsult=()=>{
|
||||
api.countConsult({
|
||||
consultUuid:uuid.value,
|
||||
expertUuid:uni.getStorageSync('userInfo').uuid
|
||||
}).then(res=>{
|
||||
console.log('咨询数量:', res)
|
||||
if(res.code ==200 && res.data){
|
||||
if(res.data> 0){
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `您已回答过该患者${res.data}次公益咨询,是否确定回答`,
|
||||
success: (res)=>{
|
||||
if(res.confirm){
|
||||
resConsult()
|
||||
}
|
||||
}
|
||||
})
|
||||
}else{
|
||||
resConsult();
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
const answerConsult=async()=>{
|
||||
if(hasAnswer.value){
|
||||
uni.sendNativeEvent('goConsultPage', {
|
||||
msg: 'chat'
|
||||
},ret => {
|
||||
console.log(ret);
|
||||
})
|
||||
// let userId=uni.getStorageSync('userInfo').uuid.toLowerCase();
|
||||
// let conversationId=userId+'|1|'+patientUuid.value.toLowerCase();
|
||||
// await uni.$UIKitStore.uiStore.selectConversation(conversationId)
|
||||
// navTo({
|
||||
// url:'/pages_chat/chat/index?from=consult&patientUuid='+patientUuid.value
|
||||
// })
|
||||
}else{
|
||||
countConsult()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const resConsult=()=>{
|
||||
api.resConsult({
|
||||
consultUuid:uuid.value,
|
||||
expertUuid:uni.getStorageSync('userInfo').uuid
|
||||
}).then(async(res)=>{
|
||||
if(res.code ==200){
|
||||
hasAnswer.value = true;
|
||||
patientUuid.value = res.data.patient_uuid;
|
||||
let userId=uni.getStorageSync('userInfo').uuid.toLowerCase();
|
||||
let conversationId=userId+'|1|'+patientUuid.value.toLowerCase();
|
||||
await uni.$UIKitStore.uiStore.selectConversation(conversationId)
|
||||
navTo({
|
||||
url:'/pages_chat/chat/index?from=consult&patientUuid='+patientUuid.value+'&uuid='+uuid.value
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
onShow(()=>{
|
||||
consultDetail()
|
||||
})
|
||||
|
||||
// 计算年龄
|
||||
function calculateAge(birthday) {
|
||||
const birthDate = new Date(birthday)
|
||||
const today = new Date()
|
||||
let age = today.getFullYear() - birthDate.getFullYear()
|
||||
const monthDiff = today.getMonth() - birthDate.getMonth()
|
||||
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
||||
age--
|
||||
}
|
||||
return age.toString()
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
function formatDate(dateString) {
|
||||
const date = new Date(dateString)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
// 用户信息
|
||||
const userInfo = ref({
|
||||
name: '提**',
|
||||
gender: '未知',
|
||||
age: '未知',
|
||||
avatar: ''
|
||||
})
|
||||
|
||||
// 问题信息
|
||||
const questionInfo = ref({
|
||||
date: '2022-11-09',
|
||||
diseaseTag: '甲型肝炎',
|
||||
content: '为什么程序员总是分不清万圣节和圣诞节?因为Oct31==Dec25。\n任何我写的代码,超过6个月不去看它,当我再看时,都像是别人写的。',
|
||||
diseaseDescribe: '', // 疾病描述
|
||||
images: [
|
||||
'/static/images/placeholder1.jpg',
|
||||
'/static/images/placeholder2.jpg',
|
||||
'/static/images/placeholder3.jpg',
|
||||
'/static/images/placeholder4.jpg',
|
||||
'/static/images/placeholder5.jpg',
|
||||
'/static/images/placeholder6.jpg',
|
||||
'/static/images/placeholder7.jpg',
|
||||
'/static/images/placeholder8.jpg'
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
// 预览图片
|
||||
function previewImage(current, index) {
|
||||
uni.previewImage({
|
||||
urls: questionInfo.value.images?questionInfo.value.images.map(item=> docUrl + item.path):[],
|
||||
current: index
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 编辑问题
|
||||
function editQuestion() {
|
||||
navTo({
|
||||
url:'/pages_app/myAnswer/myAnswer?uuid='+uuid.value
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.consult-detail-page {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 88rpx;
|
||||
padding: 0 32rpx;
|
||||
background-color: #ffffff;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
|
||||
.nav-left {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.back-icon {
|
||||
font-size: 48rpx;
|
||||
color: #8B2316;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 500;
|
||||
color: #8B2316;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
width: 80rpx;
|
||||
}
|
||||
}
|
||||
.bar{
|
||||
width:100%;
|
||||
height:20rpx;
|
||||
background-color: #efefef;
|
||||
}
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
position: fixed;
|
||||
top: 135rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx 0;
|
||||
bottom: 100rpx;
|
||||
}
|
||||
|
||||
.user-section {
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
padding: 0 30rpx;
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.user-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
margin-right: 24rpx;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
|
||||
.user-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8rpx;
|
||||
|
||||
.name {
|
||||
font-size: 32rpx;
|
||||
color: #8B2316;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.gender-age {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.user-status {
|
||||
.status-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
padding: 4rpx 12rpx;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-btn {
|
||||
display: flex;
|
||||
margin-left: 10rpx;
|
||||
|
||||
|
||||
.detail-text {
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.tag-date-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24rpx;
|
||||
margin: 0 30rpx 30rpx;
|
||||
.disease-tag {
|
||||
margin-bottom: 0;
|
||||
|
||||
.tag-text {
|
||||
display: inline-block;
|
||||
background-color: #ffffff;
|
||||
color: #8B2316;
|
||||
border: 2rpx solid #8B2316;
|
||||
border-radius: 40rpx;
|
||||
padding: 7rpx 22rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.question-content {
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin: 0 30rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.disease-describe {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin: 0 30rpx 24rpx;
|
||||
border-left: 6rpx solid #8B2316;
|
||||
|
||||
.describe-title {
|
||||
font-size: 30rpx;
|
||||
color: #8B2316;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.describe-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.image-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8rpx;
|
||||
margin: 0 30rpx 40rpx;
|
||||
|
||||
|
||||
.grid-image {
|
||||
width: 100%;
|
||||
height: 160rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.bottom-fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
padding: 24rpx 32rpx;
|
||||
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
background-color: #fff5f5;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
.disclaimer-title {
|
||||
font-size: 28rpx;
|
||||
color: #8B2316;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.disclaimer-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
text-align: center;
|
||||
border: 1rpx solid #8B2316;
|
||||
background-color: #fff;
|
||||
color: #8B2316;
|
||||
font-size: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,14 @@
|
||||
<template>
|
||||
<view class="group-edit-page">
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
:title="groupUuid ? '编辑分组' : '新建分组'"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
@@ -15,7 +17,9 @@
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
|
||||
<!-- 分组名称 -->
|
||||
</view>
|
||||
<view class="contentbox">
|
||||
<!-- 分组名称 -->
|
||||
<view class="section-header">分组名称</view>
|
||||
<view class="name-row">
|
||||
<input class="name-input" v-model.trim="groupName" placeholder="请输入分组名称" maxlength="20" />
|
||||
@@ -28,16 +32,14 @@
|
||||
<view class="section-header">分组成员</view>
|
||||
|
||||
<view class="add-member" @click="addMember">
|
||||
<view class="add-circle">
|
||||
<up-icon name="plus" size="34" color="#bfbfbf" />
|
||||
</view>
|
||||
<up-image :src="addImg" width="120rpx" height="120rpx" />
|
||||
<text class="add-text">添加组患者</text>
|
||||
</view>
|
||||
<!-- 已选中的成员 -->
|
||||
<view class="selected-members" v-if="members.length > 0">
|
||||
<view class="selected-item" v-for="(m, idx) in members" :key="m.uuid || idx">
|
||||
<image class="selected-avatar" :src="docUrl + (m.photo || '')" mode="aspectFill" />
|
||||
<text class="selected-name">{{ m.realName || '未知' }}</text>
|
||||
<image class="selected-avatar" :src="getMemberAvatar(m)" mode="aspectFill" @error="handleMemberAvatarError(m)" />
|
||||
<text class="selected-name">{{ m.nickname || m.realName }}</text>
|
||||
<view class="remove-selected" @click="removeMember(idx)">
|
||||
<text class="remove-text">——</text>
|
||||
<!-- <up-icon name="minus" size="43rpx" color="#fff" bold /> -->
|
||||
@@ -46,6 +48,7 @@
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 底部删除按钮 -->
|
||||
@@ -63,12 +66,35 @@
|
||||
import navTo from '@/utils/navTo.js'
|
||||
import docUrl from '@/utils/docUrl.js'
|
||||
import delImg from "@/static/iv_delete.png"
|
||||
import addImg from "@/static/addpatient.png"
|
||||
import api from '@/api/api.js'
|
||||
import defaultImg from "@/static/default.png"
|
||||
import unidialog from '@/components/dialog/dialog.vue'
|
||||
const groupUuid = ref('')
|
||||
const groupName = ref('')
|
||||
const members = ref([])
|
||||
const visible = ref(false)
|
||||
const avatarErrorMap = ref({})
|
||||
const getAvatarKey = (member = {}) => String(member.uuid || member.id || member.realName || '')
|
||||
const normalizeAvatarUrl = (photo) => {
|
||||
const raw = String(photo || '').trim()
|
||||
if (!raw) return defaultImg
|
||||
if (/^https?:\/\//i.test(raw)) return raw
|
||||
return `${docUrl}${raw}`
|
||||
}
|
||||
const getMemberAvatar = (member = {}) => {
|
||||
const key = getAvatarKey(member)
|
||||
if (key && avatarErrorMap.value[key]) return defaultImg
|
||||
return normalizeAvatarUrl(member.photo)
|
||||
}
|
||||
const handleMemberAvatarError = (member) => {
|
||||
const key = getAvatarKey(member)
|
||||
if (!key) return
|
||||
avatarErrorMap.value = {
|
||||
...avatarErrorMap.value,
|
||||
[key]: true
|
||||
}
|
||||
}
|
||||
const confirmDelete = () => {
|
||||
deleteGroup();
|
||||
}
|
||||
@@ -182,6 +208,7 @@
|
||||
})
|
||||
}
|
||||
const patientListByGroup = async () => {
|
||||
avatarErrorMap.value = {}
|
||||
const res = await api.patientListByGroup({
|
||||
group_uuid: groupUuid.value,
|
||||
list_sort:0
|
||||
@@ -194,19 +221,22 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contentbox{
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
}
|
||||
.group-edit-page{
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 160rpx;
|
||||
}
|
||||
.save-text{
|
||||
background:#8B2316;
|
||||
color:#8B2316;
|
||||
font-size: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 15rpx 25rpx;
|
||||
color:#fff;
|
||||
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<view class="group-manage-page">
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="分组管理"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
@@ -14,8 +14,10 @@
|
||||
<view class="save-text" @click="saveGroups">保存</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 已选中的分组 -->
|
||||
<view class="content-box">
|
||||
<!-- 已选中的分组 -->
|
||||
<view class="selected-section">
|
||||
<view class="tag-list">
|
||||
<view
|
||||
@@ -30,7 +32,7 @@
|
||||
|
||||
<!-- 所有分组 -->
|
||||
<view class="all-groups-section">
|
||||
<view class="section-title">所有分组(选择分组)</view>
|
||||
<view class="section-title"><text calss="red">所有分组</text>(选择分组)</view>
|
||||
<view class="tag-list">
|
||||
<view
|
||||
class="tag-item"
|
||||
@@ -43,6 +45,7 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部添加按钮 -->
|
||||
<view class="bottom-bar">
|
||||
@@ -80,7 +83,9 @@ const loadAllGroups = async () => {
|
||||
try {
|
||||
const res = await api.groupList();
|
||||
if (res.code === 200) {
|
||||
allGroups.value = res.data || [];
|
||||
const hiddenGroupNames = new Set(['待分组患者', '肝系一生非患教组', '肝系一生患教组']);
|
||||
const arr = (res.data || []).filter((item) => !hiddenGroupNames.has(String(item?.name || '').trim()));
|
||||
allGroups.value = arr;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("加载分组列表失败:", e);
|
||||
@@ -165,10 +170,20 @@ const saveGroups = () => {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
.content-box{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
bottom: 140rpx;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
}
|
||||
.selected-section {
|
||||
|
||||
min-height: 300rpx;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
border-bottom: 20rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.all-groups-section {
|
||||
@@ -176,9 +191,12 @@ const saveGroups = () => {
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
margin-bottom: 20rpx;
|
||||
.red{
|
||||
color: #8b2316;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-list {
|
||||
@@ -233,7 +251,7 @@ const saveGroups = () => {
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
padding: 20rpx 30rpx env(safe-area-inset-bottom);
|
||||
padding: 20rpx 30rpx 20rpx;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
/>
|
||||
|
||||
+239
-84
@@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<view class="zhinan-list-page">
|
||||
<!-- 头部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<!-- <uni-nav-bar
|
||||
left-icon="left"
|
||||
:title="title"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
|
||||
</uni-nav-bar>
|
||||
</uni-nav-bar> -->
|
||||
<navBar :title="title" />
|
||||
|
||||
<!-- 使用scroll-view实现列表 -->
|
||||
<scroll-view
|
||||
@@ -39,20 +40,17 @@
|
||||
<view class="item-date">{{ formatDate(item.releaseTime) }}</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="item-action">
|
||||
<view
|
||||
class="download-btn"
|
||||
@click.stop="viewGuideline(item)"
|
||||
>
|
||||
<up-icon name="download" color="#8D2316" size="28"></up-icon>
|
||||
</view>
|
||||
<!-- <view
|
||||
v-else
|
||||
class="view-btn"
|
||||
@click.stop="viewGuideline(item)"
|
||||
>
|
||||
查看
|
||||
</view> -->
|
||||
</view>
|
||||
<view class="download-btn" @click.stop="downLoad(item)" v-if="!downLoadtaskList.includes(item.uuid)">
|
||||
<!-- <up-icon name="download" color="#8D2316" size="28" ></up-icon> -->
|
||||
<up-image :src="downIng" width="35rpx" height="35rpx"></up-image>
|
||||
<!-- <uni-icons type="arrow-down" size="26" color="#8D2316"></uni-icons> -->
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="view-btn"
|
||||
@click.stop="viewGuideline(item)"
|
||||
>查看</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -73,22 +71,25 @@
|
||||
</view>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<view class="no-data" v-if="guidelinesList.length === 0 && !isLoading">
|
||||
<empty v-if="guidelinesList.length === 0 && !isLoading"></empty>
|
||||
<!-- <view class="no-data" v-if="guidelinesList.length === 0 && !isLoading">
|
||||
<uni-icons type="info" size="60" color="#999"></uni-icons>
|
||||
<text>暂无诊疗指南数据</text>
|
||||
</view>
|
||||
</view> -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted} from 'vue'
|
||||
import { ref, onMounted,computed,nextTick} from 'vue'
|
||||
import api from '@/api/api.js'
|
||||
import { onShow,onLoad } from "@dcloudio/uni-app";
|
||||
import docUrl from "@/utils/docUrl.js"
|
||||
import navTo from "@/utils/navTo.js"
|
||||
import hotImg from "@/static/hot_booklist.png"
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
import empty from "@/components/empty/empty.vue"
|
||||
// 响应式数据
|
||||
const guidelinesList = ref([])
|
||||
const isLoading = ref(false)
|
||||
@@ -99,6 +100,7 @@ const isRefreshing = ref(false)
|
||||
const keywords=ref('');
|
||||
import upImg from "@/static/triangle_green_theme.png"
|
||||
import downImg from "@/static/triangle_normal.png"
|
||||
import downIng from "@/static/icon_library_down.png";
|
||||
const loadMoreStatus = ref('more') // 'loading', 'more', 'noMore'
|
||||
const typeUuid=ref('');
|
||||
const title=ref('');
|
||||
@@ -107,6 +109,12 @@ const from=ref('');
|
||||
const name=ref('');
|
||||
const showInnerSort=ref(false);
|
||||
const innerSortTitle=ref('上传时间');
|
||||
import downloadStore from "@/store/downloadStoreFile.js";
|
||||
import isAndroid from '@/utils/platform';
|
||||
const downloadTasks=ref([]);
|
||||
const downLoadtaskList=computed(()=>{
|
||||
return downloadTasks.value.filter((item)=>item.status == "completed" && item.type == "zhinan").map((item)=>item.id);
|
||||
});
|
||||
const chooseInnerSort=(index)=>{
|
||||
sort.value=index;
|
||||
if(index==1){
|
||||
@@ -144,12 +152,20 @@ const toggleInnerSort=()=>{
|
||||
showInnerSort.value=!showInnerSort.value;
|
||||
}
|
||||
onShow(() => {
|
||||
syncTasksFromStore();
|
||||
// 监听store变化
|
||||
downloadStore.addListener((tasks) => {
|
||||
downloadTasks.value = tasks;
|
||||
|
||||
});
|
||||
// 恢复正在下载的任务
|
||||
resumeDownloadingTasks();
|
||||
// 页面显示时,如果列表为空则加载数据
|
||||
if (guidelinesList.value.length === 0) {
|
||||
if(from.value){
|
||||
top10ByType();
|
||||
}else{
|
||||
loadGuidelinesList(true)
|
||||
loadGuidelinesList(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -246,15 +262,16 @@ const loadGuidelinesList = async (isRefresh = false) => {
|
||||
try {
|
||||
isLoading.value = true
|
||||
loadMoreStatus.value = 'loading'
|
||||
|
||||
let expertUuid=uni.getStorageSync('userInfo').uuid;
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
expertUUid:expertUuid,
|
||||
type: 1, // 诊疗指南类型
|
||||
sort:2,
|
||||
name:name.value,
|
||||
typeUuid:typeUuid.value,
|
||||
keywords:keywords.value
|
||||
keyWords:keywords.value
|
||||
}
|
||||
|
||||
const res = await api.searchLibraryU(params)
|
||||
@@ -272,7 +289,7 @@ const loadGuidelinesList = async (isRefresh = false) => {
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
if (newData.length < pageSize.value) {
|
||||
if (newData.length < res.data.pageSize) {
|
||||
loadMoreStatus.value = 'noMore'
|
||||
hasMoreData.value = false
|
||||
console.log('没有更多数据了');
|
||||
@@ -359,66 +376,94 @@ const downloadGuideline = (item) => {
|
||||
})
|
||||
}
|
||||
}
|
||||
const downLoad = (item) => {
|
||||
if(!item.path){
|
||||
uni.showToast({
|
||||
title: "暂无下载链接",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "magazine_donwload",
|
||||
page_type: "诊疗指南",
|
||||
resource_name:item.title,
|
||||
belong:title.value,
|
||||
number:1,
|
||||
resource_option:item.tags
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
addDownloadTask({
|
||||
url: docUrl + item.path,
|
||||
title: item.title,
|
||||
id: item.uuid,
|
||||
type: 'zhinan',
|
||||
releaseTime: item.releaseTime,
|
||||
});
|
||||
};
|
||||
// 查看指南(支持常用文档直链:pdf/doc/docx/xls/xlsx/ppt/pptx/txt)
|
||||
const viewGuideline = (item) => {
|
||||
const url = docUrl+item.path
|
||||
if (url) {
|
||||
const isPDF = /\.(pdf)(\?|$)/i.test(url)
|
||||
const isOffice = /\.(docx?|xlsx?|pptx?)(\?|$)/i.test(url)
|
||||
const isText = /\.(txt)(\?|$)/i.test(url)
|
||||
const viewGuideline = (cell) => {
|
||||
console.log(cell);
|
||||
if (!cell.path) {
|
||||
uni.showToast({
|
||||
title: "暂无下载链接",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
console.log('下载列表');
|
||||
console.log(downloadTasks.value);
|
||||
downloadTasks.value.forEach(item => {
|
||||
if(item.id == cell.uuid) {
|
||||
|
||||
// H5 端
|
||||
// #ifdef H5
|
||||
if (isPDF) {
|
||||
try { window.open(url, '_blank') } catch (e) {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isOffice) {
|
||||
const officeUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`
|
||||
try { window.open(officeUrl, '_blank') } catch (e) {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(officeUrl)}` })
|
||||
}
|
||||
return
|
||||
}
|
||||
if (isText) {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
return
|
||||
}
|
||||
// 其他格式统一用 webview 打开
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
return
|
||||
// #endif
|
||||
|
||||
// 非 H5 端:下载后尝试用 openDocument,失败回退 webview
|
||||
// #ifndef H5
|
||||
uni.showToast({ title: '正在打开...', icon: 'none' })
|
||||
uni.downloadFile({
|
||||
url,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200 && res.tempFilePath) {
|
||||
uni.openDocument({
|
||||
filePath: res.tempFilePath,
|
||||
showMenu: true,
|
||||
success: () => {},
|
||||
fail: () => {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.navigateTo({ url: `/pages_app/webview/webview?url=${encodeURIComponent(url)}` })
|
||||
}
|
||||
})
|
||||
return
|
||||
// #endif
|
||||
}
|
||||
// 无直链,回退到详情页
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "detail_page",
|
||||
page_type: "诊疗指南",
|
||||
resource_name:cell.title,
|
||||
resource_option:cell.tags
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
// if(isAndroid){
|
||||
plus.runtime.openFile(item.localPath, function(e) {
|
||||
console.log('打开成功');
|
||||
}, function(e) {
|
||||
uni.showToast({
|
||||
title: '打开失败:' + e.message,
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
console.log('打开失败:' + e.message);
|
||||
});
|
||||
// }else{
|
||||
// uni.sendNativeEvent('openDocument', {
|
||||
// msg: item.localPath.replaceAll('_doc/uniapp_save/',''),
|
||||
// }, ret => {
|
||||
// console.log(ret);
|
||||
// });
|
||||
// }
|
||||
// uni.openDocument({
|
||||
// filePath: item.localPath,
|
||||
// fileType: 'pdf',
|
||||
// success: () => console.log('打开成功'),
|
||||
// fail: (err) => {
|
||||
// uni.showToast({
|
||||
// title: err,
|
||||
// icon: "none",
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -463,6 +508,116 @@ const formatDate = (dateString) => {
|
||||
return dateString
|
||||
}
|
||||
}
|
||||
// 添加下载任务
|
||||
const addDownloadTask = (item) => {
|
||||
// 使用store添加任务
|
||||
const taskIndex = downloadStore.addTask(item);
|
||||
// 同步任务列表
|
||||
syncTasksFromStore();
|
||||
// 开始下载
|
||||
startDownload(taskIndex);
|
||||
};
|
||||
|
||||
// 开始下载
|
||||
const startDownload = (index) => {
|
||||
const taskItem = downloadStore.getTask(index);
|
||||
if (!taskItem) return;
|
||||
if(taskItem.status == "loading"){
|
||||
return false;
|
||||
};
|
||||
uni.showToast({
|
||||
title: "正在下载中",
|
||||
icon: "none",
|
||||
});
|
||||
downloadStore.updateTask(index, {
|
||||
status: "loading"
|
||||
});
|
||||
|
||||
const task = uni.downloadFile({
|
||||
url: taskItem.url,
|
||||
success: (res1) => {
|
||||
//console.log("res1:"+JSON.stringify(res1));
|
||||
if (res1.statusCode === 200) {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
filePath: res1.tempFilePath,
|
||||
});
|
||||
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "none",
|
||||
});
|
||||
|
||||
|
||||
uni.saveFile({
|
||||
tempFilePath: res1.tempFilePath,
|
||||
success: function (res2) {
|
||||
console.log("res2:"+JSON.stringify(res2));
|
||||
uni.getSavedFileInfo({
|
||||
filePath: res2.savedFilePath,
|
||||
success: function (res) {
|
||||
console.log("res:"+JSON.stringify(res));
|
||||
console.log("size:"+res.size);
|
||||
downloadStore.updateTask(index, {
|
||||
status: "completed",
|
||||
localPath: res2.savedFilePath,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
downloadStore.updateTask(index, {
|
||||
status: "failed",
|
||||
});
|
||||
uni.showToast({
|
||||
title: "下载失败: " + (err.errMsg || "未知错误"),
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
// 监听下载进度
|
||||
task.onProgressUpdate((update) => {
|
||||
const currentTask = downloadStore.getTask(index);
|
||||
if (currentTask && currentTask.status === "downloading") {
|
||||
downloadStore.updateTask(index, {
|
||||
progress: update.progress
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 保存task对象到store(用于暂停/继续)
|
||||
downloadStore.updateTask(index, {
|
||||
task: task,
|
||||
});
|
||||
};
|
||||
|
||||
const syncTasksFromStore = () => {
|
||||
downloadTasks.value = downloadStore.getTasks();
|
||||
};
|
||||
// 恢复正在下载的任务
|
||||
const resumeDownloadingTasks = () => {
|
||||
// 使用 nextTick 确保在页面渲染后再恢复下载任务
|
||||
nextTick(() => {
|
||||
downloadStore.resumeDownloadingTasks((index) => {
|
||||
// 重新开始下载(uni.downloadFile不支持断点续传,所以从0开始)
|
||||
console.log("恢复下载任务:", downloadStore.getTask(index)?.url);
|
||||
startDownload(index);
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -534,18 +689,18 @@ $white: #ffffff;
|
||||
|
||||
.guidelines-scroll-view {
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: 180rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
background-color: $bg-color;
|
||||
}
|
||||
// 固定搜索容器
|
||||
.search-container-fixed {
|
||||
position: fixed;
|
||||
top: 140rpx; // 导航栏高度
|
||||
top: 180rpx; // 导航栏高度
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 90;
|
||||
|
||||
@@ -1,35 +1,63 @@
|
||||
<template>
|
||||
<view class="bank-card-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="常用银行卡"
|
||||
@clickLeft="goBack()"
|
||||
right-text="添加"
|
||||
@clickLeft="goBack"
|
||||
right-icon="plusempty"
|
||||
right-icon-color="#8B2316"
|
||||
@clickRight="addBankCard"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
</uni-nav-bar>
|
||||
|
||||
</view>
|
||||
<!-- 银行卡列表 -->
|
||||
<view class="card-list">
|
||||
<view class="card-item" v-for="(card, index) in bankCards" :key="card.uuid">
|
||||
<view class="card-logo">
|
||||
<view class="logo-bg">
|
||||
<text class="logo-text">{{ getBankLogo(card.open_bank) }}</text>
|
||||
<uni-swipe-action>
|
||||
<uni-swipe-action-item
|
||||
v-for="(card, index) in bankCards"
|
||||
:key="card.uuid"
|
||||
|
||||
@change="onSwipeChange($event, card)"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<view class="swipe-right">
|
||||
|
||||
<view class="card-delete-btn" @click.stop="handleDeleteBankCard(card)">删除</view>
|
||||
</view>
|
||||
</template>
|
||||
<view class="card-item" :class="{ 'is-swiping': openedSwipeUuid === card.uuid }">
|
||||
<view class="card-logo">
|
||||
<image
|
||||
v-if="getBankLogoImg(card.open_bank)"
|
||||
class="bank-logo-img"
|
||||
:src="getBankLogoImg(card.open_bank)"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view v-else class="logo-bg">
|
||||
<text class="logo-text">{{ getBankLogo(card.open_bank) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="card-number">尾号{{ card.card_number }}储蓄卡</view>
|
||||
<view class="bank-name">{{ card.open_bank }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-info">
|
||||
<view class="card-number">尾号{{ card.card_number }}储蓄卡</view>
|
||||
<view class="bank-name">{{ card.open_bank }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-swipe-action-item>
|
||||
</uni-swipe-action>
|
||||
</view>
|
||||
<empty v-if="bankCards.length === 0"></empty>
|
||||
<view class="empty-container" v-if="bankCards.length === 0">
|
||||
<image :src="emptyBankImg" class="empty-image"></image>
|
||||
<text class="empty-text">使用常用卡,支付更快捷</text>
|
||||
</view>
|
||||
<!-- <empty v-if="bankCards.length === 0" :imgWidth="'218rpx'" :imgHeight="'164rpx'" :emptyImage="emptyBankImg" emptyDesc="使用常用卡,支付更快捷"></empty> -->
|
||||
|
||||
<!-- 底部导航指示器 -->
|
||||
<view class="bottom-indicator"></view>
|
||||
@@ -41,27 +69,127 @@ import { ref, onMounted } from 'vue';
|
||||
import navTo from '@/utils/navTo';
|
||||
import api from '@/api/api';
|
||||
import empty from "@/components/empty/empty.vue"
|
||||
import emptyBankImg from "@/static/empty_bank.png"
|
||||
const bankCards = ref([]);
|
||||
|
||||
const openedSwipeUuid = ref('');
|
||||
import { onLoad,onBackPress,onShow } from '@dcloudio/uni-app';
|
||||
const from = ref('');
|
||||
const returnTo = ref('');
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
if (options.returnTo) {
|
||||
returnTo.value = decodeURIComponent(options.returnTo);
|
||||
}
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "常用银行卡",
|
||||
},
|
||||
});
|
||||
});
|
||||
onShow(() => {
|
||||
getBankCardList();
|
||||
});
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 银行卡数据
|
||||
const getBankCardList = () => {
|
||||
api.bankCardList({}).then(res => {
|
||||
if (res.code === 200 && res.data.bankList) {
|
||||
bankCards.value = res.data.bankList;
|
||||
|
||||
if (res.code === 200 && res.data) {
|
||||
bankCards.value = res.data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
};
|
||||
|
||||
const addBankCard = () => {
|
||||
const target = returnTo.value
|
||||
? `/pages_app/idcardAuth/idcardAuth?returnTo=${encodeURIComponent(returnTo.value)}`
|
||||
: '/pages_app/idcardAuth/idcardAuth';
|
||||
navTo({
|
||||
url: '/pages_app/idcardAuth/idcardAuth'
|
||||
url: target
|
||||
});
|
||||
};
|
||||
|
||||
const bankLogoMap = {
|
||||
'工商银行': '/static/icon_bankcard_gongshang.png',
|
||||
'中国银行': '/static/icon_bankcard_zhongguo.png',
|
||||
'建设银行': '/static/icon_bankcard_jianseyinhang.png',
|
||||
'农业银行': '/static/icon_bankcard_nongyeyinhang.png',
|
||||
'交通银行': '/static/icon_bankcard_jiatong.png',
|
||||
'招商银行': '/static/icon_bankcard_zhaoshangyinhang.png',
|
||||
'民生银行': '/static/icon_bankcard_minshneg.png',
|
||||
'兴业银行': '/static/icon_bankcard_xingye.png',
|
||||
'浦发银行': '/static/icon_bankcard_shanghaipudongfazhanyinhang.png',
|
||||
'光大银行': '/static/icon_bankcard_guangda.png',
|
||||
'华夏银行': '/static/icon_bankcard_huaxiayinhnag.png',
|
||||
'中信银行': '/static/icon_bankcard_zhongxinshiye.png',
|
||||
'平安银行': '/static/icon_bankcard_pingan.png',
|
||||
'广发银行': '/static/icon_bankcard_guangfa.png',
|
||||
'邮储银行': '/static/icon_bankcard_youzheng.png',
|
||||
'上海银行': '/static/icon_bankcard_shanghai.png',
|
||||
'北京银行': '/static/icon_bankcard_beijingyinhang.png'
|
||||
};
|
||||
|
||||
const getBankLogoImg = (bankName) => {
|
||||
let name1=bankName.split(',')[0];
|
||||
let name2=bankName.split(',')[1];
|
||||
return bankLogoMap[name1] || bankLogoMap[name2];
|
||||
};
|
||||
|
||||
const handleDeleteBankCard = (card) => {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: `确定删除尾号${card.card_number}的银行卡吗?`,
|
||||
success: async (modalRes) => {
|
||||
if (!modalRes.confirm) return;
|
||||
try {
|
||||
const res = await api.deleteBankCard({
|
||||
uuid: card.uuid
|
||||
});
|
||||
if (res.code === 200) {
|
||||
uni.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'none'
|
||||
});
|
||||
getBankCardList();
|
||||
return;
|
||||
}
|
||||
uni.showToast({
|
||||
title: res.msg || '删除失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onSwipeChange = (e, card) => {
|
||||
const state = typeof e === 'string'
|
||||
? e
|
||||
: e?.position || e?.show || e?.detail?.position || e?.detail?.show || 'none';
|
||||
openedSwipeUuid.value = state === 'right' ? card.uuid : '';
|
||||
};
|
||||
|
||||
// 获取银行logo文字
|
||||
const getBankLogo = (bankName) => {
|
||||
const bankLogos = {
|
||||
@@ -84,33 +212,95 @@ const getBankLogo = (bankName) => {
|
||||
return bankLogos[bankName] || bankName.charAt(0);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getBankCardList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.empty-container {
|
||||
height:800rpx;
|
||||
min-width:600rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.empty-image {
|
||||
width: 218rpx;
|
||||
height: 164rpx;
|
||||
}
|
||||
.empty-text {
|
||||
margin-top: 20rpx;
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
.bank-card-page {
|
||||
min-height: 100vh;
|
||||
background: #F5F5F5;
|
||||
position: relative;
|
||||
|
||||
:deep(.uni-nav-bar-right-text) {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
:deep(.uni-swipe){
|
||||
margin-bottom: 20rpx!important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 银行卡列表样式 */
|
||||
.card-list {
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0rpx;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.swipe-right {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
padding-right: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card-delete-btn {
|
||||
min-width: 112rpx;
|
||||
height: 100%;
|
||||
padding: 0 24rpx;
|
||||
border-radius: 0 16rpx 16rpx 0;
|
||||
background: #E60012;
|
||||
color: #ffffff;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
&.is-swiping {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.card-logo {
|
||||
margin-right: 30rpx;
|
||||
|
||||
.bank-logo-img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.logo-bg {
|
||||
width: 80rpx;
|
||||
@@ -145,6 +335,7 @@ onMounted(() => {
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<template>
|
||||
<view class="idcard-auth-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
:title="currentStep === 1 ? '身份验证' : '添加银行卡'"
|
||||
@clickLeft="goBack()"
|
||||
fixed
|
||||
@clickLeft="goBack"
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
<!-- 内容区域 -->
|
||||
<view class="content-area">
|
||||
<!-- 进度指示器 -->
|
||||
@@ -65,6 +68,7 @@
|
||||
class="form-input"
|
||||
placeholder="请输入您的姓名"
|
||||
v-model="formData.name"
|
||||
:adjust-position="false"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
</view>
|
||||
@@ -73,6 +77,7 @@
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入您的身份证号"
|
||||
:adjust-position="false"
|
||||
v-model="formData.idNumber"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
@@ -85,28 +90,34 @@
|
||||
<text class="form-label">银行卡号</text>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="form-input"
|
||||
class="form-input card-number-input"
|
||||
:class="{ 'is-filled': !!formData.cardNumber }"
|
||||
placeholder="仅限借记卡"
|
||||
v-model="formData.cardNumber"
|
||||
:value="cardNumberDisplay"
|
||||
:adjust-position="false"
|
||||
@input="onCardNumberInput"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
<view class="info-icon">
|
||||
|
||||
</view>
|
||||
<view class="info-icon" @click="showInfo('card')">
|
||||
<text class="icon-text">!</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="form-item">
|
||||
<text class="form-label">手机号</text>
|
||||
<view class="input-container">
|
||||
<input
|
||||
class="form-input"
|
||||
class="form-input card-number-input"
|
||||
placeholder="银行预留手机号"
|
||||
v-model="formData.mobile"
|
||||
:adjust-position="false"
|
||||
placeholder-style="color: #cccccc"
|
||||
/>
|
||||
<view class="info-icon">
|
||||
|
||||
</view>
|
||||
<view class="info-icon" @click="showInfo('phone')">
|
||||
<text class="icon-text">!</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -145,6 +156,18 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<unidialog
|
||||
:visible="cardVisible"
|
||||
:showCancel="false"
|
||||
:title="cardTitle"
|
||||
:content="cardContent"
|
||||
:showConfirm="true"
|
||||
:confirmText="'知道了'"
|
||||
@close="cardVisible=false"
|
||||
@confirm="cardVisible=false"
|
||||
>
|
||||
|
||||
</unidialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@@ -153,7 +176,11 @@ import stepImg from "@/static/add_card_no.png"
|
||||
import stepActiveImg from "@/static/add_card_yes.png"
|
||||
import navTo from '@/utils/navTo';
|
||||
import api from '@/api/api';
|
||||
|
||||
import unidialog from '@/components/dialog/dialog.vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
const cardContent = ref('暂支持以下银行:农业银行、建设银行、光大银行、平安银行、兴业银行、中信银行、邮政储蓄银行、民生银行、中国银行、工商银行、交通银行、浦发银行、广发银行、华夏银行、招商银行、北京银行、上海银行。');
|
||||
const cardTitle = ref('银行卡说明');
|
||||
const cardVisible = ref(false);
|
||||
const formData = ref({
|
||||
name: '',
|
||||
idNumber: '',
|
||||
@@ -163,13 +190,29 @@ const formData = ref({
|
||||
|
||||
const isLoading = ref(false);
|
||||
const currentStep = ref(1); // 当前步骤,1表示身份信息,2表示添加银行卡
|
||||
|
||||
const showInfo = (type) => {
|
||||
if (type === 'card') {
|
||||
cardTitle.value = '银行卡说明';
|
||||
cardContent.value = '暂支持以下银行:农业银行、建设银行、光大银行、平安银行、兴业银行、中信银行、邮政储蓄银行、民生银行、中国银行、工商银行、交通银行、浦发银行、广发银行、华夏银行、招商银行、北京银行、上海银行。';
|
||||
} else if (type === 'phone') {
|
||||
cardTitle.value = '手机号说明';
|
||||
cardContent.value = '银行预留的手机号码是办理银行卡时所填写的手机号码。没有预留,手机号码已经忘记或者已经停用,请联系银行客服更新处理';
|
||||
}
|
||||
cardVisible.value = true;
|
||||
};
|
||||
// 短信弹框相关
|
||||
const showSmsDialog = ref(false);
|
||||
const smsCode = ref('');
|
||||
const sendingCode = ref(false);
|
||||
const countdown = ref(0);
|
||||
let countdownTimer = null;
|
||||
const returnTo = ref('');
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.returnTo) {
|
||||
returnTo.value = decodeURIComponent(options.returnTo);
|
||||
}
|
||||
});
|
||||
|
||||
const maskedMobile = computed(() => {
|
||||
const m = formData.value.mobile || '';
|
||||
@@ -178,6 +221,18 @@ const maskedMobile = computed(() => {
|
||||
}
|
||||
return m || '***********';
|
||||
});
|
||||
|
||||
const formatCardNumber = (value) => {
|
||||
const digits = String(value || '').replace(/\D/g, '').slice(0, 19);
|
||||
return digits.replace(/(\d{4})(?=\d)/g, '$1 ');
|
||||
};
|
||||
|
||||
const cardNumberDisplay = computed(() => formatCardNumber(formData.value.cardNumber));
|
||||
|
||||
const onCardNumberInput = (e) => {
|
||||
const value = e?.detail?.value || '';
|
||||
formData.value.cardNumber = String(value).replace(/\D/g, '').slice(0, 19);
|
||||
};
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
@@ -246,7 +301,7 @@ const onNextStep = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('身份验证失败:', error);
|
||||
uni.showToast({ title: '网络错误,请重试', icon: 'none' });
|
||||
uni.showToast({ title: error.data.message || error.message, icon: 'none' });
|
||||
isLoading.value = false;
|
||||
}
|
||||
} else if (currentStep.value === 2) {
|
||||
@@ -296,7 +351,9 @@ const onGetSmsCode = async () => {
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '短信验证码发送失败', icon: 'none' });
|
||||
uni.showToast({
|
||||
title: res.msg || res.data.message, icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -315,9 +372,16 @@ const onConfirmSms = async () => {
|
||||
});
|
||||
if (res.code === 200) {
|
||||
uni.showToast({ title: '银行卡添加成功', icon: 'none' });
|
||||
navTo({
|
||||
url: '/pages_app/idcardAuth/bankCardList'
|
||||
});
|
||||
uni.navigateBack();
|
||||
// if (returnTo.value) {
|
||||
// uni.redirectTo({
|
||||
// url: returnTo.value
|
||||
// });
|
||||
// } else {
|
||||
// navTo({
|
||||
// url: '/pages_app/idcardAuth/bankCardList'
|
||||
// });
|
||||
// }
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '银行卡添加失败', icon: 'none' });
|
||||
}
|
||||
@@ -332,12 +396,17 @@ const onCancelSms = () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.idcard-auth-page {
|
||||
min-height: 100vh;
|
||||
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
padding-top: 160rpx;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
padding: 0rpx 0rpx 0;
|
||||
}
|
||||
|
||||
@@ -455,78 +524,98 @@ const onCancelSms = () => {
|
||||
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
padding: 0 30rpx 20rpx;
|
||||
height: 92rpx;
|
||||
padding: 0 30rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
width: 120rpx;
|
||||
font-weight: 500;
|
||||
text-align: right;
|
||||
text-align-last: auto;
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
min-height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:focus {
|
||||
border-color: #8B2316;
|
||||
}
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #8B2316;
|
||||
|
||||
.icon-text {
|
||||
font-size: 20rpx;
|
||||
color: #8B2316;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
width: 80%;
|
||||
height: 80rpx;
|
||||
flex: 1;
|
||||
padding-right: 56rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
.form-input {
|
||||
flex: 9;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
line-height: 80rpx;
|
||||
padding: 0;
|
||||
font-size: 28rpx;
|
||||
background: #ffffff;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
outline: none;
|
||||
|
||||
&:focus {
|
||||
/* 去除边框后无需变更边框颜色 */
|
||||
box-sizing: border-box;
|
||||
|
||||
&.card-number-input.is-filled {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
flex:1;
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
background: #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.icon-text {
|
||||
font-size: 20rpx;
|
||||
color: #cccccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -644,6 +733,10 @@ const onCancelSms = () => {
|
||||
background: #eeeeee;
|
||||
color: #8B2316;
|
||||
font-size: 26rpx;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sms-actions {
|
||||
|
||||
+1177
-1057
File diff suppressed because it is too large
Load Diff
+65
-32
@@ -11,14 +11,14 @@
|
||||
<up-image :src="logo" width="164rpx" height="167rpx" ></up-image>
|
||||
|
||||
</view>
|
||||
<text class="app-name">专家端</text>
|
||||
<text class="app-name">专家版</text>
|
||||
</view>
|
||||
|
||||
<!-- 手机号显示 -->
|
||||
<!-- #ifdef APP -->
|
||||
<view class="phone-display">
|
||||
<!-- <view class="phone-display">
|
||||
<text class="phone-number">176****8628</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<view class="login-button" @click="onOneClickLogin">
|
||||
@@ -129,34 +129,16 @@
|
||||
};
|
||||
// 一键登录
|
||||
const onOneClickLogin = () => {
|
||||
if (!isAgreed.value) {
|
||||
uni.showToast({
|
||||
title: '请先同意相关协议',
|
||||
icon: 'none'
|
||||
const res = checkUniverifyLogin()
|
||||
if(res){
|
||||
uni.redirectTo({
|
||||
url: '/pages/univerify/univerify'
|
||||
});
|
||||
}else{
|
||||
uni.redirectTo({
|
||||
url: '/pages_app/smsLogin/smsLogin'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('一键登录');
|
||||
uni.showLoading({
|
||||
title: '登录中2...'
|
||||
});
|
||||
|
||||
// 模拟登录过程
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
// 跳转到首页
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}, 1500);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// 短信验证码登录
|
||||
@@ -179,7 +161,7 @@
|
||||
|
||||
// #ifdef APP
|
||||
uni.showToast({
|
||||
title: '微信登录 11',
|
||||
title: '微信登录',
|
||||
icon: 'none'
|
||||
});
|
||||
// #endif
|
||||
@@ -235,9 +217,10 @@
|
||||
uni.setStorageSync('DEV_AUTH_YX_TOKEN_App', res.data.YX_token);
|
||||
uni.setStorageSync('userInfo', res.data);
|
||||
}
|
||||
|
||||
const app = getApp()
|
||||
//app.initNim({appkey: "885dea390870814acf3ba8558c717572", account:result.data.YX_accid, token: result.data.YX_token })
|
||||
// 跳转到首页
|
||||
navTo({
|
||||
uni.redirectTo({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}).catch(err=>{
|
||||
@@ -339,11 +322,61 @@
|
||||
url:'/pages/index/index'
|
||||
})
|
||||
}
|
||||
|
||||
const univerify = ref(1)
|
||||
// 页面加载
|
||||
onLoad(() => {
|
||||
console.log('登录页面加载完成');
|
||||
onLoad((options) => {
|
||||
if(options.univerify){
|
||||
univerify.value = options.univerify // 已支持 App-Plus
|
||||
}
|
||||
})
|
||||
const res = checkUniverifyLogin()
|
||||
if(res){
|
||||
uni.redirectTo({
|
||||
url: '/pages/univerify/univerify'
|
||||
});
|
||||
}else{
|
||||
uni.redirectTo({
|
||||
url: '/pages_app/smsLogin/smsLogin'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const checkUniverifyLogin=()=>{
|
||||
let res = false
|
||||
// #ifdef APP
|
||||
uni.getProvider({
|
||||
service: 'oauth',
|
||||
success: function (res) {
|
||||
console.log(res.provider)// ['qq', 'univerify']
|
||||
if(res.provider.indexOf('univerify') !== -1){
|
||||
uni.preLogin({
|
||||
provider: 'univerify',
|
||||
success(){ //预登录成功
|
||||
// 显示一键登录选项
|
||||
if(univerify.value == 1){
|
||||
return true
|
||||
}
|
||||
},
|
||||
fail(res){ // 预登录失败
|
||||
// 不显示一键登录选项(或置灰)
|
||||
// 根据错误信息判断失败原因,如有需要可将错误提交给统计服务器
|
||||
console.log(res.errCode)
|
||||
console.log(res.errMsg)
|
||||
return false
|
||||
}
|
||||
})
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
return res
|
||||
}
|
||||
|
||||
// 页面显示
|
||||
onShow(() => {
|
||||
// #ifdef APP
|
||||
|
||||
@@ -0,0 +1,582 @@
|
||||
<template>
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="过往会议"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eee"
|
||||
>
|
||||
<template #right>
|
||||
<view class="nav-right">
|
||||
<uni-icons type="search" size="24" color="#8B2316" @click="searchMeetHistroy"></uni-icons>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
<view class="page">
|
||||
<!-- 筛选标签栏 -->
|
||||
<view class="filter-bar">
|
||||
<view class="filter-item" :class="{active:monthName}" @click="showTimePopup">
|
||||
<text>{{ monthName?monthName:'会议年份' }}</text>
|
||||
<up-image :src="monthName?selectOn:select" width="26rpx" height="26rpx"></up-image>
|
||||
</view>
|
||||
<view class="filter-divider"></view>
|
||||
<view class="filter-item" :class="{active:typeName}" @click="showLocationPopup">
|
||||
<text>{{ typeName?typeName:'会议月份' }}</text>
|
||||
<up-image :src="typeName?selectOn:select" width="26rpx" height="26rpx"></up-image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 可滚动内容区域 -->
|
||||
<scroll-view
|
||||
class="scroll-content"
|
||||
scroll-y="true"
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="isRefreshing"
|
||||
:refresher-threshold="100"
|
||||
@refresherrefresh="onRefresh"
|
||||
@scrolltolower="onLoadMore"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<!-- 会议列表 -->
|
||||
<view class="meeting-list" v-if="meetingList.length > 0">
|
||||
<view
|
||||
class="meeting-item" @click="goDetail(meeting)"
|
||||
v-for="(meeting, index) in meetingList"
|
||||
:key="meeting.id || index"
|
||||
>
|
||||
<view class="meeting-content">
|
||||
<text class="meeting-title">{{
|
||||
meeting.title || meeting.name
|
||||
}}</text>
|
||||
<view class="meeting-info">
|
||||
<view class="meeting-time">
|
||||
<view class="timebox">
|
||||
<up-image
|
||||
:src="timeImg"
|
||||
width="24rpx"
|
||||
height="24rpx"
|
||||
></up-image>
|
||||
</view>
|
||||
<view class="text"> {{ formatDate(meeting.begin_date) }}</view>
|
||||
</view>
|
||||
<view class="meeting-location">
|
||||
<uni-icons type="location" size="14" color="#999"></uni-icons>
|
||||
{{ meeting.location }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else-if="!isRefreshing">
|
||||
<empty></empty>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多提示 -->
|
||||
<view class="load-more" v-if="showLoadMore">
|
||||
<view class="load-more-content" v-if="isLoadingMore">
|
||||
<uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons>
|
||||
<text class="load-more-text">加载中...</text>
|
||||
</view>
|
||||
<view
|
||||
class="load-more-content"
|
||||
v-else-if="hasMoreData && meetingList.length > 0"
|
||||
>
|
||||
<text class="load-more-text">上拉加载更多</text>
|
||||
</view>
|
||||
<view
|
||||
class="load-more-content"
|
||||
v-else-if="meetingList.length > 0 && !isLoadingMore"
|
||||
>
|
||||
<text class="load-more-text">没有更多数据了</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 时间选择弹窗 -->
|
||||
<view class="time-popup" v-if="isTimePopupShow" @click="hideTimePopup">
|
||||
<view class="popup-mask"></view>
|
||||
<view class="time-popup-content" @click.stop>
|
||||
<view class="time-list">
|
||||
<view
|
||||
class="time-item"
|
||||
v-for="(month, index) in monthList"
|
||||
:key="index"
|
||||
:class="{ active: selectedMonth === month.value }"
|
||||
@click="selectMonth(month)"
|
||||
>
|
||||
<text>{{ month.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 地区选择弹窗 -->
|
||||
<view
|
||||
class="time-popup"
|
||||
v-if="isLocationPopupShow"
|
||||
@click="hideLocationPopup"
|
||||
>
|
||||
<view class="popup-mask"></view>
|
||||
<view class="time-popup-content" @click.stop>
|
||||
<view class="time-list">
|
||||
<view
|
||||
class="time-item"
|
||||
v-for="(location, index) in locationList"
|
||||
:key="index"
|
||||
:class="{ active: selectedType === location.code }"
|
||||
@click="selectLocation(location)"
|
||||
>
|
||||
<text>{{ location.name }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { onShow,onLoad,onHide} from "@dcloudio/uni-app";
|
||||
import api from "@/api/api.js";
|
||||
import navBar from "@/components/navBar/navBar.vue";
|
||||
import select from "@/static/triangle_normal.png";
|
||||
import selectOn from "@/static/triangle_green_theme.png"
|
||||
import dayjs from "dayjs";
|
||||
import timeImg from "@/static/play_long.png"
|
||||
import navTo from "@/utils/navTo";
|
||||
import empty from '@/components/empty/empty.vue';
|
||||
// 弹窗状态
|
||||
const isTimePopupShow = ref(false);
|
||||
const isLocationPopupShow = ref(false);
|
||||
const selectedMonth = ref("");
|
||||
const monthName = ref("");
|
||||
const selectedType = ref("");
|
||||
const typeName = ref("");
|
||||
// 下拉刷新和上拉加载状态
|
||||
const isRefreshing = ref(false);
|
||||
const isLoadingMore = ref(false);
|
||||
const hasMoreData = ref(true);
|
||||
const showLoadMore = ref(true);
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
|
||||
// 会议列表数据
|
||||
const meetingList = ref([]);
|
||||
const goBack=()=>{
|
||||
uni.navigateBack({
|
||||
fail:()=>{
|
||||
uni.redirectTo({
|
||||
url:'/pages/index/index'
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
onShow(() => {
|
||||
|
||||
});
|
||||
onHide(() => {
|
||||
|
||||
});
|
||||
// 年份数据
|
||||
const monthList = ref([]);
|
||||
const generateYearList = () => {
|
||||
const years = [];
|
||||
const currentDate = new Date();
|
||||
const currentYear = currentDate.getFullYear();
|
||||
// 从今年到过去10年
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const year = currentYear - i;
|
||||
years.push({
|
||||
value: year.toString(),
|
||||
label: `${year}年`,
|
||||
year: year,
|
||||
});
|
||||
}
|
||||
monthList.value = years;
|
||||
console.log("生成年份列表:", monthList.value);
|
||||
};
|
||||
|
||||
// 月份数据
|
||||
const locationList = ref([]);
|
||||
|
||||
// 生成月份列表
|
||||
const generateMonthList = () => {
|
||||
const months = [];
|
||||
const currentDate = new Date();
|
||||
const currentYear = currentDate.getFullYear();
|
||||
const currentMonth = currentDate.getMonth() + 1; // 当前月份(1-12)
|
||||
|
||||
// 如果选择的是今年,只显示到当前月份
|
||||
if (selectedMonth.value && selectedMonth.value === currentYear.toString()) {
|
||||
for (let i = 1; i <= currentMonth; i++) {
|
||||
months.push({
|
||||
code: i,
|
||||
name: `${i}月`,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// 其他年份显示完整的12个月
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
months.push({
|
||||
code: i,
|
||||
name: `${i}月`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
locationList.value = months;
|
||||
console.log("生成月份列表:", locationList.value);
|
||||
};
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
generateYearList();
|
||||
generateMonthList();
|
||||
});
|
||||
const searchMeetHistroy=()=>{
|
||||
navTo({
|
||||
url:'/pages_app/meetHistroySearch/meetHistroySearch'
|
||||
})
|
||||
}
|
||||
onLoad(() => {
|
||||
currentPage.value = 1;
|
||||
hasMoreData.value = true;
|
||||
loadMeetingData();
|
||||
});
|
||||
|
||||
// 加载会议数据
|
||||
const loadMeetingData = async (isRefresh = false) => {
|
||||
if (isLoadingMore.value && !isRefresh) return;
|
||||
|
||||
if (isRefresh) {
|
||||
isRefreshing.value = true;
|
||||
} else {
|
||||
isLoadingMore.value = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
year: selectedMonth.value,
|
||||
title: "",
|
||||
month: selectedType.value,
|
||||
};
|
||||
|
||||
console.log("获取会议列表参数:", params);
|
||||
const response = await api.meetingHistoryList(params);
|
||||
|
||||
if (response && response.code === 200) {
|
||||
const { list, totalPage, pageNumber } = response.data || {};
|
||||
|
||||
if (isRefresh) {
|
||||
meetingList.value = list || [];
|
||||
currentPage.value = 1;
|
||||
} else {
|
||||
meetingList.value = [...meetingList.value, ...(list || [])];
|
||||
}
|
||||
|
||||
hasMoreData.value = totalPage > pageNumber;
|
||||
showLoadMore.value = meetingList.value.length > 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载会议数据失败:", error);
|
||||
} finally {
|
||||
isRefreshing.value = false;
|
||||
isLoadingMore.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下拉刷新
|
||||
const onRefresh = () => {
|
||||
currentPage.value = 1;
|
||||
hasMoreData.value = true;
|
||||
loadMeetingData(true);
|
||||
};
|
||||
|
||||
// 上拉加载更多
|
||||
const onLoadMore = () => {
|
||||
if (!hasMoreData.value || isLoadingMore.value) return;
|
||||
currentPage.value++;
|
||||
loadMeetingData();
|
||||
};
|
||||
|
||||
// 显示时间选择弹窗
|
||||
const showTimePopup = () => {
|
||||
isTimePopupShow.value = !isTimePopupShow.value;
|
||||
};
|
||||
|
||||
// 隐藏时间选择弹窗
|
||||
const hideTimePopup = () => {
|
||||
isTimePopupShow.value = false;
|
||||
};
|
||||
|
||||
// 选择年份
|
||||
const selectMonth = (month) => {
|
||||
selectedMonth.value = month.value;
|
||||
monthName.value = month.label;
|
||||
console.log("选择年份:", month.label);
|
||||
|
||||
// 选择年份后重新生成月份列表
|
||||
generateMonthList();
|
||||
|
||||
// 重置月份选择
|
||||
selectedType.value = "";
|
||||
|
||||
// 选择年份后重新加载数据
|
||||
loadMeetingData(true);
|
||||
hideTimePopup();
|
||||
};
|
||||
|
||||
// 显示地区选择弹窗
|
||||
const showLocationPopup = () => {
|
||||
if (selectedMonth.value === "") {
|
||||
uni.showToast({
|
||||
title: "请先选择年份",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
isLocationPopupShow.value = !isLocationPopupShow.value;
|
||||
};
|
||||
|
||||
// 隐藏地区选择弹窗
|
||||
const hideLocationPopup = () => {
|
||||
isLocationPopupShow.value = false;
|
||||
};
|
||||
|
||||
// 选择月份
|
||||
const selectLocation = (location) => {
|
||||
selectedType.value = location.code;
|
||||
typeName.value = location.name;
|
||||
console.log("选择月份:", location.name);
|
||||
// 选择月份后重新加载数据
|
||||
loadMeetingData(true);
|
||||
hideLocationPopup();
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return "";
|
||||
return dayjs(dateStr).format("YYYY.MM.DD");
|
||||
};
|
||||
const goDetail=(item)=>{
|
||||
const encoded = encodeURIComponent(item.path);
|
||||
let imgPath=encodeURIComponent('https://doc.igandan.com/app/html/img/2016/20160714132557.png');
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/webview/webview?url=${encoded}&sharetitle=${item.title}&bg=1&type=live_old&imgPath=${imgPath}&share=1&title=会议详情`
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$white: #fff;
|
||||
$gray: #999;
|
||||
$gray-dark: #666;
|
||||
$gray-light: #eee;
|
||||
$border-color: #e0e0e0;
|
||||
$theme-color: #8b2316;
|
||||
// .nav-right{
|
||||
// margin-top: 50rpx;
|
||||
// }
|
||||
.page {
|
||||
background-color: #f5f5f5;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
// 筛选标签栏
|
||||
.filter-bar {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
background-color: $white;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 30rpx;
|
||||
border-bottom: 2rpx solid $gray-light;
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 20rpx;
|
||||
font-size: 28rpx;
|
||||
color:$gray-dark;
|
||||
|
||||
text {
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #8B2316;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-divider {
|
||||
width: 2rpx;
|
||||
height: 32rpx;
|
||||
background-color: $border-color;
|
||||
margin: 0 60rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动内容区域
|
||||
.scroll-content {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px + 88rpx);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
background-color: $white;
|
||||
|
||||
}
|
||||
|
||||
// 会议列表
|
||||
.meeting-list {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.meeting-item {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.meeting-content {
|
||||
.meeting-title {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 16rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.meeting-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8rpx;
|
||||
|
||||
.meeting-time,
|
||||
.meeting-location {
|
||||
.timebox{
|
||||
margin-top: -4rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
.load-more {
|
||||
padding: 30rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.load-more-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
|
||||
.load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 时间选择弹窗
|
||||
.time-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
|
||||
.popup-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.time-popup-content {
|
||||
margin-top: calc(var(--status-bar-height) + 44px + 90rpx);;
|
||||
position: relative;
|
||||
background-color: $white;
|
||||
width: 100%;
|
||||
height: calc(100vh - calc(var(--status-bar-height) - 44px - 88rpx));
|
||||
|
||||
.time-list {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.time-item {
|
||||
padding: 25rpx 60rpx;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #f8f8f8;
|
||||
color: $theme-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,493 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 头部搜索栏 -->
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<view class="search-header ">
|
||||
|
||||
<view class="back-icon" @click="goBack">
|
||||
<uni-icons type="left" size="30" color="#8B2316"></uni-icons>
|
||||
</view>
|
||||
<view class="search-input-wrapper">
|
||||
<view class="search-icon">
|
||||
<uni-icons type="search" size="20" color="#999"></uni-icons>
|
||||
</view>
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="搜索会议关键字"
|
||||
v-model="searchKeyword"
|
||||
@input="onSearchInput"
|
||||
@confirm="onSearchConfirm"
|
||||
confirm-type="search"
|
||||
/>
|
||||
<view class="clear-icon" v-if="searchKeyword" @click="clearSearch">
|
||||
<uni-icons type="clear" size="20" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cancel-btn" @click="goSearch">
|
||||
<text class="cancel-text">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 可滚动内容区域 -->
|
||||
<scroll-view
|
||||
class="scroll-content"
|
||||
scroll-y="true"
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="isRefreshing"
|
||||
:refresher-threshold="100"
|
||||
@refresherrefresh="onRefresh"
|
||||
@scrolltolower="onLoadMore"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<!-- 会议列表 -->
|
||||
<view class="meeting-list" v-if="meetingList.length > 0">
|
||||
<view
|
||||
class="meeting-item" @click="goDetail(meeting)"
|
||||
v-for="(meeting, index) in meetingList"
|
||||
:key="meeting.id || index"
|
||||
>
|
||||
<view class="meeting-content">
|
||||
<text class="meeting-title">{{
|
||||
meeting.title || meeting.name
|
||||
}}</text>
|
||||
<view class="meeting-info">
|
||||
<view class="meeting-time">
|
||||
<view class="timebox">
|
||||
<up-image
|
||||
:src="timeImg"
|
||||
width="24rpx"
|
||||
height="24rpx"
|
||||
></up-image>
|
||||
</view>
|
||||
<view class="text" >{{ formatDate(meeting.begin_date,'YYYY.MM.DD')}}</view>
|
||||
<view class="text" v-if="formatDate(meeting.end_date,'YYYY.MM.DD')!=formatDate(meeting.begin_date,'YYYY.MM.DD')">{{ '-'+formatDate(meeting.end_date,'YYYY.MM.DD')}}</view>
|
||||
</view>
|
||||
<view class="meeting-location">
|
||||
<uni-icons type="location" size="14" color="#999"></uni-icons>
|
||||
{{ meeting.location }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else-if="!isRefreshing">
|
||||
<empty></empty>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多提示 -->
|
||||
<view class="load-more" v-if="showLoadMore">
|
||||
<view class="load-more-content" v-if="isLoadingMore">
|
||||
<uni-icons type="spinner-cycle" size="20" color="#999"></uni-icons>
|
||||
<text class="load-more-text">加载中...</text>
|
||||
</view>
|
||||
<view
|
||||
class="load-more-content"
|
||||
v-else-if="hasMoreData && meetingList.length > 0"
|
||||
>
|
||||
<text class="load-more-text">上拉加载更多</text>
|
||||
</view>
|
||||
<view
|
||||
class="load-more-content"
|
||||
v-else-if="meetingList.length > 0 && !isLoadingMore"
|
||||
>
|
||||
<text class="load-more-text">没有更多数据了</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue";
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import api from "@/api/api.js";
|
||||
import navBar from "@/components/navBar/navBar.vue";
|
||||
import select from "@/static/triangle_normal.png";
|
||||
import dayjs from "dayjs";
|
||||
import timeImg from "@/static/play_long.png"
|
||||
import empty from "@/components/empty/empty.vue";
|
||||
|
||||
const searchKeyword = ref('');
|
||||
// 下拉刷新和上拉加载状态
|
||||
const isRefreshing = ref(false);
|
||||
const isLoadingMore = ref(false);
|
||||
const hasMoreData = ref(true);
|
||||
const showLoadMore = ref(true);
|
||||
const currentPage = ref(1);
|
||||
const pageSize = ref(10);
|
||||
|
||||
// 会议列表数据
|
||||
const meetingList = ref([]);
|
||||
|
||||
const goSearch=()=>{
|
||||
if(!searchKeyword.value){
|
||||
uni.showToast({
|
||||
title: '请输入搜索内容',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
currentPage.value = 1;
|
||||
hasMoreData.value = true;
|
||||
meetingList.value = [];
|
||||
loadMeetingData();
|
||||
}
|
||||
|
||||
const goBack=()=>{
|
||||
uni.navigateBack({
|
||||
fail:()=>{
|
||||
uni.redirectTo({
|
||||
url:'/pages/index/index'
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 加载会议数据
|
||||
const loadMeetingData = async (isRefresh = false) => {
|
||||
if (isLoadingMore.value && !isRefresh) return;
|
||||
|
||||
if (isRefresh) {
|
||||
isRefreshing.value = true;
|
||||
} else {
|
||||
isLoadingMore.value = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize: pageSize.value,
|
||||
year:'',
|
||||
title: searchKeyword.value,
|
||||
month: '',
|
||||
};
|
||||
|
||||
console.log("获取会议列表参数:", params);
|
||||
const response = await api.meetingHistoryList(params);
|
||||
|
||||
if (response && response.code === 200) {
|
||||
const { list, totalPage, pageNumber } = response.data || {};
|
||||
|
||||
if (isRefresh) {
|
||||
meetingList.value = list || [];
|
||||
currentPage.value = 1;
|
||||
} else {
|
||||
meetingList.value = [...meetingList.value, ...(list || [])];
|
||||
}
|
||||
console.log("会议列表数据:", meetingList.value);
|
||||
hasMoreData.value = totalPage > pageNumber;
|
||||
showLoadMore.value = meetingList.value.length > 0;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载会议数据失败:", error);
|
||||
} finally {
|
||||
isRefreshing.value = false;
|
||||
isLoadingMore.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下拉刷新
|
||||
const onRefresh = () => {
|
||||
currentPage.value = 1;
|
||||
hasMoreData.value = true;
|
||||
loadMeetingData(true);
|
||||
};
|
||||
|
||||
// 上拉加载更多
|
||||
const onLoadMore = () => {
|
||||
if (!hasMoreData.value || isLoadingMore.value) return;
|
||||
currentPage.value++;
|
||||
loadMeetingData();
|
||||
};
|
||||
|
||||
// 显示时间选择弹窗
|
||||
const showTimePopup = () => {
|
||||
isTimePopupShow.value = !isTimePopupShow.value;
|
||||
};
|
||||
|
||||
// 隐藏时间选择弹窗
|
||||
const hideTimePopup = () => {
|
||||
isTimePopupShow.value = false;
|
||||
};
|
||||
|
||||
// 选择年份
|
||||
const selectMonth = (month) => {
|
||||
selectedMonth.value = month.value;
|
||||
console.log("选择年份:", month.label);
|
||||
|
||||
// 选择年份后重新生成月份列表
|
||||
generateMonthList();
|
||||
|
||||
// 重置月份选择
|
||||
selectedType.value = "";
|
||||
|
||||
// 选择年份后重新加载数据
|
||||
loadMeetingData(true);
|
||||
hideTimePopup();
|
||||
};
|
||||
|
||||
// 显示地区选择弹窗
|
||||
const showLocationPopup = () => {
|
||||
if (selectedMonth.value === "") {
|
||||
uni.showToast({
|
||||
title: "请先选择年份",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
isLocationPopupShow.value = !isLocationPopupShow.value;
|
||||
};
|
||||
|
||||
// 隐藏地区选择弹窗
|
||||
const hideLocationPopup = () => {
|
||||
isLocationPopupShow.value = false;
|
||||
};
|
||||
|
||||
// 选择月份
|
||||
const selectLocation = (location) => {
|
||||
selectedType.value = location.code;
|
||||
console.log("选择月份:", location.name);
|
||||
// 选择月份后重新加载数据
|
||||
loadMeetingData(true);
|
||||
hideLocationPopup();
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateStr) => {
|
||||
if (!dateStr) return "";
|
||||
return dayjs(dateStr).format("YYYY.MM.DD");
|
||||
};
|
||||
const goDetail=(item)=>{
|
||||
const encoded = encodeURIComponent(item.path);
|
||||
let imgPath=encodeURIComponent('https://doc.igandan.com/app/html/img/2016/20160714132557.png');
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/webview/webview?url=${encoded}&sharetitle=${item.title}&bg=1&type=live_old&imgPath=${imgPath}&share=1&title=会议详情`
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$white: #fff;
|
||||
$gray: #999;
|
||||
$gray-dark: #666;
|
||||
$gray-light: #eee;
|
||||
$border-color: #e0e0e0;
|
||||
$theme-color: #8b2316;
|
||||
|
||||
.page {
|
||||
background-color: #f5f5f5;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
// 头部搜索栏
|
||||
.search-header {
|
||||
|
||||
background-color: #eeeeee;
|
||||
|
||||
display: flex;
|
||||
height:44px;
|
||||
align-items: center;
|
||||
padding:0 30rpx;
|
||||
gap: 20rpx;
|
||||
|
||||
|
||||
.search-input-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
height:70rpx;
|
||||
|
||||
.search-icon {
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
margin-left: 15rpx;
|
||||
padding: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
padding: 10rpx 20rpx;
|
||||
background:#8B2316;
|
||||
border-radius: 10rpx;
|
||||
|
||||
.cancel-text {
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动内容区域
|
||||
.scroll-content {
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
background-color: $white;
|
||||
|
||||
}
|
||||
|
||||
// 会议列表
|
||||
.meeting-list {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.meeting-item {
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.meeting-content {
|
||||
.meeting-title {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 16rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.meeting-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 8rpx;
|
||||
|
||||
.meeting-time,
|
||||
.meeting-location {
|
||||
.timebox{
|
||||
margin-top: -4rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 0;
|
||||
|
||||
.empty-icon {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
.load-more {
|
||||
padding: 30rpx 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.load-more-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
|
||||
.load-more-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 时间选择弹窗
|
||||
.time-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
|
||||
.popup-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.time-popup-content {
|
||||
margin-top: 271rpx;
|
||||
position: relative;
|
||||
background-color: $white;
|
||||
width: 100%;
|
||||
height: calc(100vh - 275rpx);
|
||||
|
||||
.time-list {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.time-item {
|
||||
padding: 25rpx 60rpx;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #f8f8f8;
|
||||
color: $theme-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
+291
-83
@@ -1,47 +1,53 @@
|
||||
<template>
|
||||
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="消息"
|
||||
right-text="清除"
|
||||
@clickRight="clearMsg"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
:title="'消息'"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
<template v-slot:right>
|
||||
<view class="nav-right" >
|
||||
<view class="collect-img" @click="clearMsg" >
|
||||
<image class="img-icon" :src="clearImg" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
<view class="msg-page">
|
||||
|
||||
|
||||
<!-- 四宫格入口 -->
|
||||
<view class="shortcut-grid">
|
||||
<view class="grid-item" @click="goBenefit">
|
||||
<view class="icon-wrap gift">
|
||||
<uni-icons type="gift" size="34" color="#fff"></uni-icons>
|
||||
<view class="icon-wrap">
|
||||
<image :src="fuliImg" class="imgcell"/>
|
||||
<view class="badge" v-if="badgeData.Module_Welfare > 0">{{ badgeData.Module_Welfare }}</view>
|
||||
</view>
|
||||
<text class="label">福利</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goOrder">
|
||||
<view class="icon-wrap order">
|
||||
<uni-icons type="list" size="34" color="#fff"></uni-icons>
|
||||
<view class="icon-wrap ">
|
||||
<image :src="orderImg" class="imgcell"/>
|
||||
<view class="badge" v-if="badgeData.Module_Order > 0">{{ badgeData.Module_Order }}</view>
|
||||
</view>
|
||||
<text class="label">订单</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goFollow">
|
||||
<view class="icon-wrap visit">
|
||||
<uni-icons type="heart" size="34" color="#fff"></uni-icons>
|
||||
<view class="icon-wrap">
|
||||
<image :src="followImg" class="imgcell"/>
|
||||
<view class="badge" v-if="badgeData.Module_Relation > 0">{{ badgeData.Module_Relation }}</view>
|
||||
</view>
|
||||
<text class="label">随访</text>
|
||||
</view>
|
||||
<view class="grid-item" @click="goReply">
|
||||
<view class="icon-wrap reply">
|
||||
<uni-icons type="chatbubble" size="34" color="#fff"></uni-icons>
|
||||
<view class="icon-wrap">
|
||||
<image :src="replyImg" class="imgcell"/>
|
||||
<view class="badge" v-if="badgeData.Module_Comment > 0">{{ badgeData.Module_Comment }}</view>
|
||||
</view>
|
||||
<text class="label">回复我的</text>
|
||||
@@ -53,15 +59,15 @@
|
||||
class="msg-list"
|
||||
scroll-y="true"
|
||||
:show-scrollbar="false"
|
||||
refresher-enabled="true"
|
||||
:refresher-enabled="true"
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="onRefresh"
|
||||
@scrolltolower="onLoadMore"
|
||||
lower-threshold="80"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<!-- 回复我的模块 - 聊天列表样式 -->
|
||||
<view v-if="currentModule === 4" class="chat-list">
|
||||
<view class="chat-item" v-for="(msg, idx) in msgList" :key="msg.id">
|
||||
<view class="chat-item" v-for="(msg, idx) in msgList" :key="msg.id" @click="goMsgDetail(msg)">
|
||||
<view class="avatar">
|
||||
<image :src="msg.avatar || '/static/default-avatar.png'" mode="aspectFill" @error="handleImageError"></image>
|
||||
</view>
|
||||
@@ -77,24 +83,28 @@
|
||||
|
||||
<!-- 其他模块 - 卡片样式 -->
|
||||
<view v-else>
|
||||
<view class="card" v-for="(msg, idx) in msgList" :key="msg.id">
|
||||
<view class="card-title">{{ msg.title }}</view>
|
||||
<view class="card-content">{{ msg.content }}</view>
|
||||
<view class="card-cell" v-for="(msg, idx) in msgList" :key="msg.id" @click="goMsgDetail(msg)">
|
||||
<view class="card-time">{{ msg.create_date }}</view>
|
||||
<view class="card" >
|
||||
<view class="card-title" :class="{'active':msg.is_read==0}">{{ msg.title }}</view>
|
||||
<view class="card-content">{{ msg.content }}</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="msgList.length === 0" class="empty-state">
|
||||
<text class="empty-text">暂无消息</text>
|
||||
<view v-if="msgList.length === 0 && !loading && !refreshing" class="empty-state">
|
||||
<empty></empty>
|
||||
</view>
|
||||
<!-- 加载更多提示 -->
|
||||
<view v-if="loading" class="loading-more">
|
||||
<view v-if="loading && msgList.length > 0" class="loading-more">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
<!-- 没有更多数据提示 -->
|
||||
<view v-if="noMore" class="no-more">
|
||||
<text class="no-more-text">没有更多数据了</text>
|
||||
<view v-if="noMore && msgList.length > 0 && !loading" class="no-more">
|
||||
<text class="no-more-text">— 没有更多数据了 —</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -104,6 +114,18 @@
|
||||
import { onMounted, ref } from 'vue';
|
||||
import api from '@/api/api.js';
|
||||
import docUrl from '@/utils/docUrl';
|
||||
import navTo from '@/utils/navTo';
|
||||
import clearImg from '@/static/clear_message.png';
|
||||
import empty from '@/components/empty/empty.vue';
|
||||
import fuliImg from '@/static/fu_message_big.png';
|
||||
import orderImg from '@/static/ding_message_big.png';
|
||||
import followImg from '@/static/sui_message_big.png';
|
||||
import replyImg from '@/static/hui_message_big.png';
|
||||
import {onBackPress} from '@dcloudio/uni-app';
|
||||
onBackPress(() => {
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
});
|
||||
|
||||
// 角标数据
|
||||
const badgeData = ref({
|
||||
@@ -122,81 +144,183 @@
|
||||
const loading = ref(false);
|
||||
const noMore = ref(false);
|
||||
const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const pageSize = 10;
|
||||
|
||||
// 重置分页状态
|
||||
const resetPagination = () => {
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
msgList.value = [];
|
||||
};
|
||||
|
||||
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack({
|
||||
fail() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/index/index'
|
||||
plus.runtime.quit();
|
||||
};
|
||||
|
||||
// 切换模块
|
||||
const switchModule = (module) => {
|
||||
if (currentModule.value === module && msgList.value.length > 0) return; // 避免重复加载
|
||||
currentModule.value = module;
|
||||
resetPagination();
|
||||
getAppMesageList(true);
|
||||
};
|
||||
|
||||
const goBenefit = () => switchModule(1);
|
||||
const goOrder = () => switchModule(2);
|
||||
const goFollow = () => switchModule(3);
|
||||
const goReply = () => switchModule(4);
|
||||
const readMsg = (id) => {
|
||||
api.appMesageRead({
|
||||
id: id
|
||||
}).then(res => {
|
||||
if(res.code==200){
|
||||
msgList.value.forEach(item => {
|
||||
if(item.id==id){
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "read_message",
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
item.is_read=1;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const goBenefit = () => {
|
||||
currentModule.value = 1;
|
||||
getAppMesageList(1);
|
||||
};
|
||||
const goOrder = () => {
|
||||
currentModule.value = 2;
|
||||
getAppMesageList(2);
|
||||
};
|
||||
const goFollow = () => {
|
||||
currentModule.value = 3;
|
||||
getAppMesageList(3);
|
||||
};
|
||||
const goReply = () => {
|
||||
currentModule.value = 4;
|
||||
getAppMesageList(4);
|
||||
};
|
||||
|
||||
}
|
||||
const clearMsg = () => {
|
||||
uni.showModal({
|
||||
title: '提醒',
|
||||
content: '是否要清除所有未读消息?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
api.appMesageRead({}).then(res => {
|
||||
api.appMesageRead().then(res => {
|
||||
console.log(res);
|
||||
|
||||
getUnReadList();
|
||||
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "clear_message",
|
||||
},
|
||||
},
|
||||
(ret) => {
|
||||
console.log(ret);
|
||||
});
|
||||
});
|
||||
getUnReadList();
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
const goMsgDetail = (msg) => {
|
||||
console.log(msg);
|
||||
if(msg.is_read==0){
|
||||
readMsg(msg.id);
|
||||
};
|
||||
//readMsg(msg.id);
|
||||
if(msg.extra.module==4){
|
||||
if(msg.extra.type==17 || msg.extra.type==40){
|
||||
uni.showToast({
|
||||
title: '暂停中',
|
||||
icon: 'none'
|
||||
});
|
||||
}else{
|
||||
uni.sendNativeEvent('goCourseDetail', {
|
||||
msg: {
|
||||
id:msg.extra.id
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}else if(msg.extra.module==2){
|
||||
if(msg.extra.type==19){
|
||||
let url=`/pages_app/myCourseware/myCourseware?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}else if(msg.extra.type==18){
|
||||
let url=`/pages_app/myFlower/myFlower?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
}else{
|
||||
let url="";
|
||||
if(msg.extra.module==1 && msg.extra.type==36){
|
||||
url=`/pages_app/myPoint/myPoint?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}else if(msg.extra.module==1 && msg.extra.type==31){
|
||||
url=`/pages_app/myPoint/myPoint?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}else if(msg.extra.module==1 && msg.extra.type==35){
|
||||
//uni.setStorageSync('lookWelfare', 'useWelfare');
|
||||
url=`/pages_app/myWelfareCard/myWelfareCard?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}else if(msg.extra.module==3 && msg.extra.type==12){
|
||||
url=`/pages_app/myPatient/myPatient?from=msg`
|
||||
navTo({
|
||||
url: url
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// 下拉刷新
|
||||
const onRefresh = async () => {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
// 重新获取当前模块的消息列表
|
||||
getAppMesageList(currentModule.value);
|
||||
// 重新获取未读消息数量
|
||||
getUnReadList();
|
||||
// 重置分页并重新获取数据
|
||||
resetPagination();
|
||||
await Promise.all([
|
||||
getAppMesageList(true),
|
||||
getUnReadList()
|
||||
]);
|
||||
} catch (err) {
|
||||
console.error('刷新失败:', err);
|
||||
uni.showToast({
|
||||
title: '刷新失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
refreshing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 上拉加载
|
||||
// 上拉加载更多
|
||||
const onLoadMore = async () => {
|
||||
if (loading.value || noMore.value) return;
|
||||
if (loading.value || noMore.value || refreshing.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
// 这里可以根据需要实现分页加载
|
||||
// 目前接口返回的数据已经包含了分页信息
|
||||
// 如果需要加载更多,可以调用 getAppMesageList 并传入页码参数
|
||||
noMore.value = true; // 暂时设置为没有更多数据
|
||||
page.value++;
|
||||
await getAppMesageList(false);
|
||||
} catch (err) {
|
||||
// 加载失败时回退页码
|
||||
page.value = Math.max(1, page.value - 1);
|
||||
console.error('加载更多失败:', err);
|
||||
uni.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const getUnReadList = () => {
|
||||
api.unReadList({}).then(res => {
|
||||
return api.unReadList({}).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data) {
|
||||
// 更新角标数据
|
||||
@@ -207,17 +331,24 @@
|
||||
Module_Relation: parseInt(res.data.Module_Relation) || 0
|
||||
};
|
||||
}
|
||||
return res;
|
||||
}).catch(err => {
|
||||
console.error('获取未读消息列表失败:', err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
const getAppMesageList = (module) => {
|
||||
api.appMesageList({module: module}).then(res => {
|
||||
// 获取消息列表
|
||||
// isRefresh: true 表示刷新,false 表示加载更多
|
||||
const getAppMesageList = (isRefresh = false) => {
|
||||
return api.appMesageList({
|
||||
module: currentModule.value,
|
||||
page: page.value,
|
||||
pageSize: pageSize
|
||||
}).then(res => {
|
||||
console.log(res);
|
||||
if (res.code === 200 && res.data && res.data.list) {
|
||||
// 更新消息列表数据
|
||||
msgList.value = res.data.list.map(item => ({
|
||||
const newList = res.data.list.map(item => ({
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
content: item.content,
|
||||
@@ -232,9 +363,31 @@
|
||||
`${getBaseUrl()}${item.extra.user_photo}`) :
|
||||
'/static/default-avatar.png'
|
||||
}));
|
||||
|
||||
// 刷新时替换数据,加载更多时追加数据
|
||||
if (isRefresh || page.value === 1) {
|
||||
msgList.value = newList;
|
||||
} else {
|
||||
msgList.value = [...msgList.value, ...newList];
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
if (res.isLastPage || newList.length < pageSize) {
|
||||
noMore.value = true;
|
||||
} else {
|
||||
noMore.value = false;
|
||||
}
|
||||
} else if (res.code === 200 && (!res.data || !res.data.list || res.data.list.length === 0)) {
|
||||
// 没有数据的情况
|
||||
if (isRefresh || page.value === 1) {
|
||||
msgList.value = [];
|
||||
}
|
||||
noMore.value = true;
|
||||
}
|
||||
return res;
|
||||
}).catch(err => {
|
||||
console.error('获取消息列表失败:', err);
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -251,7 +404,7 @@
|
||||
|
||||
onMounted(() => {
|
||||
getUnReadList();
|
||||
getAppMesageList(1);
|
||||
getAppMesageList(true); // 初始加载视为刷新
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -270,16 +423,31 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.imgcell{
|
||||
width:74rpx;
|
||||
height: 74rpx;
|
||||
}
|
||||
.nav-right{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.collect-img {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
.img-icon{
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.msg-page {
|
||||
min-height: 100vh;
|
||||
background: $bg;
|
||||
padding-top: $nav-h; // 与导航栏高度一致
|
||||
|
||||
}
|
||||
|
||||
.shortcut-grid {
|
||||
position: fixed;
|
||||
top: $nav-h;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
@@ -333,7 +501,7 @@
|
||||
.msg-list {
|
||||
position: fixed;
|
||||
// 减去导航与宫格的高度
|
||||
top: 360rpx; // 让列表起始位置在宫格下方
|
||||
top: calc(var(--status-bar-height) + 44px + 230rpx);
|
||||
padding: 20rpx 24rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
bottom: 0rpx;
|
||||
@@ -347,6 +515,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态样式
|
||||
.empty-state {
|
||||
flex-direction: column;
|
||||
padding: 100rpx 0;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
// 加载动画
|
||||
.loading-more {
|
||||
gap: 16rpx;
|
||||
|
||||
.loading-spinner {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border: 3rpx solid #eee;
|
||||
border-top-color: $theme;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.card-cell{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
margin-bottom: 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.card-time {
|
||||
width:100%;
|
||||
margin:10rpx 0;
|
||||
font-size: 30rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
@@ -359,6 +568,9 @@
|
||||
color: $text-primary;
|
||||
font-weight: 600;
|
||||
margin-bottom: 14rpx;
|
||||
&.active{
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
@@ -368,11 +580,7 @@
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
|
||||
.card-time {
|
||||
font-size: 24rpx;
|
||||
color: $muted;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 聊天列表样式
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<view class="bill-detail-page">
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="详情"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<view class="detail-content">
|
||||
<view class="detail-row">
|
||||
<text class="label">交易号:</text>
|
||||
<text class="value">{{ detail.tradeNo || '-' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">类型:</text>
|
||||
<text class="value">{{ detail.typeName || '-' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">金额:</text>
|
||||
<text class="value amount" :class="amountClass">{{ detail.accountStr || '-' }}元</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">用户:</text>
|
||||
<text class="value">{{ detail.userName || '-' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">时间:</text>
|
||||
<text class="value">{{ formatDateTime(detail.createTime) }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">备注:</text>
|
||||
<text class="value">{{ detail.remark || '' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
const detail = ref({})
|
||||
const from = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.from) {
|
||||
from.value = decodeURIComponent(options.from)
|
||||
}
|
||||
})
|
||||
|
||||
const amountClass = computed(() => {
|
||||
const amount = Number(detail.value?.accountStr || 0)
|
||||
return amount < 0 ? 'negative' : 'positive'
|
||||
})
|
||||
|
||||
const formatDateTime = (value) => {
|
||||
if (!value) return '-'
|
||||
const text = String(value).trim()
|
||||
const date = new Date(text)
|
||||
if (Number.isNaN(date.getTime())) return text
|
||||
const y = date.getFullYear()
|
||||
const m = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const d = String(date.getDate()).padStart(2, '0')
|
||||
const hh = String(date.getHours()).padStart(2, '0')
|
||||
const mm = String(date.getMinutes()).padStart(2, '0')
|
||||
const ss = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
|
||||
}
|
||||
|
||||
const goBack = () => {
|
||||
if (from.value === 'billDetails') {
|
||||
uni.navigateBack()
|
||||
return
|
||||
}
|
||||
uni.redirectTo({
|
||||
url: '/pages_app/myAccount/billDetails?from=myAccount'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const cache = uni.getStorageSync('billDetailItem')
|
||||
detail.value = cache || {}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bill-detail-page {
|
||||
min-height: 100vh;
|
||||
background: #f3f3f3;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
bottom: 0;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
background: #ffffff;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
min-height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1rpx solid #efefef;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 30rpx;
|
||||
color: #2c2c2c;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
font-size: 30rpx;
|
||||
color: #666666;
|
||||
margin-left: 20rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.amount {
|
||||
&.positive {
|
||||
color: #8B2316;
|
||||
}
|
||||
|
||||
&.negative {
|
||||
color: #3f3f3f;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,16 +1,19 @@
|
||||
<template>
|
||||
<view class="bill-details-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="账单明细"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 表格头部 -->
|
||||
<view class="table-header">
|
||||
@@ -32,7 +35,7 @@
|
||||
@scrolltolower="onLoadMore"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<view class="transaction-item" v-for="(item, index) in orderList" :key="item.id">
|
||||
<view class="transaction-item" v-for="(item, index) in orderList" :key="item.id" @click="goToDetail(item)">
|
||||
<view class="cell business-type">{{ item.typeName }}</view>
|
||||
<view class="cell user">{{ item.userName }}</view>
|
||||
<view class="cell date-amount">
|
||||
@@ -62,6 +65,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import api from '@/api/api.js'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
// 响应式数据
|
||||
const orderList = ref([])
|
||||
@@ -71,10 +75,24 @@ const page = ref(1)
|
||||
const total = ref(0)
|
||||
const isFirstPage = ref(true)
|
||||
const isLastPage = ref(false)
|
||||
const from = ref('')
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.from) {
|
||||
from.value = decodeURIComponent(options.from)
|
||||
}
|
||||
})
|
||||
|
||||
const stopRefresh = () => {
|
||||
refreshing.value = false
|
||||
}
|
||||
|
||||
// 获取订单列表
|
||||
const getOrderList = async (isRefresh = false) => {
|
||||
if (loading.value) return
|
||||
if (loading.value) {
|
||||
if (isRefresh) stopRefresh()
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
@@ -93,15 +111,18 @@ const getOrderList = async (isRefresh = false) => {
|
||||
}
|
||||
|
||||
// 处理订单数据
|
||||
const processedList = list.map(item => ({
|
||||
const safeList = Array.isArray(list) ? list : []
|
||||
const processedList = safeList.map(item => ({
|
||||
id: item.trade_no,
|
||||
tradeNo: item.trade_no,
|
||||
typeName: item.type_name,
|
||||
userName: item.user_name,
|
||||
createTime: item.create_time,
|
||||
accountStr: item.accountstr,
|
||||
payChannel: item.pay_channel,
|
||||
orderType: item.order_type,
|
||||
status: item.status
|
||||
status: item.status,
|
||||
remark: item.remark || item.message || ''
|
||||
}))
|
||||
|
||||
orderList.value.push(...processedList)
|
||||
@@ -117,12 +138,16 @@ const getOrderList = async (isRefresh = false) => {
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
stopRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
const onRefresh = () => {
|
||||
if (loading.value) {
|
||||
stopRefresh()
|
||||
return
|
||||
}
|
||||
refreshing.value = true
|
||||
page.value = 1
|
||||
isLastPage.value = false
|
||||
@@ -149,9 +174,23 @@ const formatDate = (dateStr) => {
|
||||
|
||||
// 返回上一页
|
||||
const goBack = () => {
|
||||
if (from.value === 'myAccount') {
|
||||
uni.redirectTo({
|
||||
url: '/pages_app/myAccount/myAccount?from=billDetails'
|
||||
})
|
||||
return
|
||||
}
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
const goToDetail = (item) => {
|
||||
uni.setStorageSync('billDetailItem', item || {})
|
||||
const fromPage = encodeURIComponent('billDetails')
|
||||
uni.navigateTo({
|
||||
url: `/pages_app/myAccount/billDetail?from=${fromPage}`
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getOrderList()
|
||||
})
|
||||
@@ -182,14 +221,17 @@ onMounted(() => {
|
||||
|
||||
// 表格头部样式
|
||||
.table-header {
|
||||
background-color: #e0e0e0;
|
||||
background-color: #fff;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 20rpx 30rpx;
|
||||
margin-top: 170rpx; /* 为固定导航栏留出空间 */
|
||||
box-sizing: border-box;
|
||||
top:calc(var(--status-bar-height) + 44px); /* 为固定导航栏留出空间 */
|
||||
border-bottom: 1rpx solid #ccc;
|
||||
|
||||
.header-cell {
|
||||
font-size: 28rpx;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -224,17 +266,22 @@ onMounted(() => {
|
||||
|
||||
// 交易记录列表样式
|
||||
.transaction-list {
|
||||
background-color: #f5f5f5;
|
||||
top:calc(var(--status-bar-height) + 44px + 130rpx);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.transaction-item {
|
||||
background-color: #f8f8f8;
|
||||
|
||||
display: flex;
|
||||
padding: 20rpx 30rpx;
|
||||
border-bottom: 1rpx solid #e5e5e5;
|
||||
|
||||
.cell {
|
||||
font-size: 26rpx;
|
||||
font-size: 30rpx;
|
||||
|
||||
&.business-type {
|
||||
flex: 1;
|
||||
@@ -245,7 +292,7 @@ onMounted(() => {
|
||||
&.user {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #ff0000;
|
||||
color: #8B2316;
|
||||
}
|
||||
|
||||
&.date-amount {
|
||||
@@ -257,7 +304,7 @@ onMounted(() => {
|
||||
|
||||
.date {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
color: #999;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
@@ -265,11 +312,11 @@ onMounted(() => {
|
||||
font-size: 24rpx;
|
||||
|
||||
&.positive {
|
||||
color: #ff0000;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&.negative {
|
||||
color: #666;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<view class="my-account-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的账户"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 账户余额区域 -->
|
||||
<view class="contentbox">
|
||||
<!-- 账户余额区域 -->
|
||||
<view class="account-summary">
|
||||
<view class="profile-section">
|
||||
<image class="profile-avatar" :src="avatar" mode="aspectFill"></image>
|
||||
@@ -21,7 +23,7 @@
|
||||
<text class="balance-amount">{{ (accountBalance/100).toFixed(2) }}</text>
|
||||
|
||||
<!-- 账户信息详情 -->
|
||||
<view class="account-details">
|
||||
<!-- <view class="account-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">单次提现限额</text>
|
||||
<text class="detail-value">{{ (withdrawalBalanceMaxOnce/100).toFixed(2) }}元</text>
|
||||
@@ -34,35 +36,36 @@
|
||||
<text class="detail-label">最低提现金额</text>
|
||||
<text class="detail-value">{{ (lessWithdrawalBalance/100).toFixed(2) }}元</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 操作选项 -->
|
||||
<view class="action-items">
|
||||
<view class="action-item" @click="handleWithdrawal">
|
||||
<view class="action-icon withdrawal-icon">
|
||||
<text class="icon-text">💰</text>
|
||||
<image class="icon-img" :src="withdrawalsIcon" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="action-content">
|
||||
<text class="action-title">提现</text>
|
||||
<text class="action-subtitle">提现金额不得少于{{ (lessWithdrawalBalance/100).toFixed(2) }}元</text>
|
||||
</view>
|
||||
<text class="action-arrow">></text>
|
||||
<uni-icons type="right" size="25" color="#999"></uni-icons>
|
||||
</view>
|
||||
|
||||
<view class="action-item" @click="handleBillDetails">
|
||||
<view class="action-icon bill-icon">
|
||||
<text class="icon-text">📋</text>
|
||||
<image class="icon-img" :src="accountIcon" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="action-content">
|
||||
<text class="action-title">账单明细</text>
|
||||
</view>
|
||||
<text class="action-arrow">></text>
|
||||
<uni-icons type="right" size="25" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部指示器 -->
|
||||
<view class="bottom-indicator"></view>
|
||||
<!-- <view class="bottom-indicator"></view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -70,6 +73,27 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import api from '@/api/api.js'
|
||||
import docUrl from '@/utils/docUrl'
|
||||
import withdrawalsIcon from '@/static/withdrawals.png'
|
||||
import accountIcon from '@/static/account_icon.png'
|
||||
import { onLoad,onBackPress,onShow } from '@dcloudio/uni-app';
|
||||
const from = ref('');
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "我的账户",
|
||||
},
|
||||
});
|
||||
});
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 响应式数据
|
||||
const accountBalance = ref(0)
|
||||
const withdrawalBalanceMaxOnce = ref(0)
|
||||
@@ -77,7 +101,7 @@ const withdrawalBalanceFee = ref(0)
|
||||
const lessWithdrawalBalance = ref(0)
|
||||
const avatar = ref('')
|
||||
|
||||
onMounted(() => {
|
||||
onShow(() => {
|
||||
getMyAccount()
|
||||
|
||||
let userInfo= uni.getStorageSync('userInfo')
|
||||
@@ -86,13 +110,17 @@ onMounted(() => {
|
||||
|
||||
// 方法
|
||||
const goBack = () => {
|
||||
uni.navigateBack()
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
}
|
||||
|
||||
const handleWithdrawal = () => {
|
||||
if(accountBalance.value < lessWithdrawalBalance.value){
|
||||
uni.showToast({
|
||||
title: `提现金额不得少于${(lessWithdrawalBalance/100).toFixed(2)}元`,
|
||||
title: `提现金额不得少于${(lessWithdrawalBalance.value/100).toFixed(2)}元`,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -111,8 +139,9 @@ const handleWithdrawal = () => {
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if(res.confirm){
|
||||
const returnTo = encodeURIComponent('/pages_app/myAccount/myAccount')
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/idcardAuth/bankCardList'
|
||||
url: `/pages_app/idcardAuth/idcardAuth?returnTo=${returnTo}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -123,8 +152,9 @@ const handleWithdrawal = () => {
|
||||
}
|
||||
|
||||
const handleBillDetails = () => {
|
||||
const from = encodeURIComponent('myAccount')
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/myAccount/billDetails'
|
||||
url: `/pages_app/myAccount/billDetails?from=${from}`
|
||||
})
|
||||
}
|
||||
|
||||
@@ -142,6 +172,14 @@ const getMyAccount = async () => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.contentbox{
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
}
|
||||
.my-account-page {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
@@ -151,20 +189,19 @@ const getMyAccount = async () => {
|
||||
// 账户余额区域样式
|
||||
.account-summary {
|
||||
background: linear-gradient(135deg, #8B2316, #A0522D);
|
||||
margin: 30rpx;
|
||||
border-radius: 20rpx;
|
||||
padding: 60rpx 40rpx;
|
||||
// margin: 30rpx;
|
||||
// border-radius: 20rpx;
|
||||
padding: 30rpx 40rpx 10rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 8rpx 24rpx rgba(139, 35, 22, 0.3);
|
||||
position: relative;
|
||||
|
||||
.profile-section {
|
||||
margin-bottom: 40rpx;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.profile-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
border-radius: 20rpx;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||
object-fit: cover;
|
||||
}
|
||||
@@ -174,18 +211,18 @@ const getMyAccount = async () => {
|
||||
display: block;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 20rpx;
|
||||
margin-bottom: 10rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.balance-amount {
|
||||
display: block;
|
||||
color: #ffffff;
|
||||
font-size: 72rpx;
|
||||
font-size: 50rpx;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
|
||||
letter-spacing: 2rpx;
|
||||
margin-bottom: 40rpx;
|
||||
margin-bottom: 0rpx;
|
||||
}
|
||||
|
||||
// 账户信息详情样式
|
||||
@@ -223,15 +260,15 @@ const getMyAccount = async () => {
|
||||
// 操作选项样式
|
||||
.action-items {
|
||||
background-color: #ffffff;
|
||||
margin: 0 30rpx;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 0rpx;
|
||||
// border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
// box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 40rpx 30rpx;
|
||||
padding: 20rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background-color 0.2s ease;
|
||||
|
||||
@@ -256,6 +293,11 @@ const getMyAccount = async () => {
|
||||
.icon-text {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.icon-img {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.withdrawal-icon {
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<template>
|
||||
<view class="withdrawal-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="提现"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
></uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<view class="main-content">
|
||||
@@ -25,20 +26,27 @@
|
||||
<text class="section-title">结算银行卡</text>
|
||||
<text class="withdrawal-rules" @click="showWithdrawalRules">提现规则</text>
|
||||
</view>
|
||||
<view class="divider"></view>
|
||||
<view class="bank-card-info" @click="selectBankCard" v-if="selectedBankCard">
|
||||
<view class="bank-logo">
|
||||
<text class="bank-icon">{{ selectedBankCard.bankName ? selectedBankCard.bankName.charAt(0) : '工' }}</text>
|
||||
<image
|
||||
v-if="getBankLogoImg(getBankName(selectedBankCard))"
|
||||
class="bank-logo-img"
|
||||
:src="getBankLogoImg(getBankName(selectedBankCard))"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
<view v-else class="logo-bg">
|
||||
<text class="bank-icon">{{ getBankLogo(getBankName(selectedBankCard)) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bank-details">
|
||||
<text class="bank-name">{{ selectedBankCard.bankName || '工商银行' }}</text>
|
||||
<text class="bank-card-number">尾号为{{ selectedBankCard.cardNumber ? selectedBankCard.cardNumber.slice(-4) : '8937' }}储蓄卡</text>
|
||||
<text class="bank-name">{{ getBankName(selectedBankCard) || '工商银行' }}</text>
|
||||
<text class="bank-card-number">尾号为{{ getCardTail(selectedBankCard) }}储蓄卡</text>
|
||||
</view>
|
||||
<text class="arrow-icon">›</text>
|
||||
<uni-icons type="right" size="25" color="#999"></uni-icons>
|
||||
</view>
|
||||
<view class="no-bank-card" v-else>
|
||||
<text class="no-card-text">请先添加银行卡</text>
|
||||
<text class="arrow-icon">›</text>
|
||||
<uni-icons type="right" size="25" color="#999"></uni-icons>
|
||||
</view>
|
||||
<view class="divider"></view>
|
||||
</view>
|
||||
@@ -48,12 +56,12 @@
|
||||
<text class="amount-title">提现金额</text>
|
||||
<view class="amount-display">
|
||||
<text class="currency-symbol">¥</text>
|
||||
<text class="amount-value">{{ withdrawalAmount }}</text>
|
||||
<text class="amount-value">{{ withdrawalAmount}}</text>
|
||||
</view>
|
||||
<view class="amount-details">
|
||||
<text class="tax-info">扣除个人所得税<text class="highlight-red">{{ (incomeTax / 100).toFixed(2) }}元</text></text>
|
||||
<text class="fee-info">扣除提现手续费<text class="highlight-red">{{ (withdrawalBalanceFee / 100).toFixed(2) }}元</text></text>
|
||||
<text class="actual-amount">此次提现实际到账<text class="highlight-red">{{ actualAmount }}元</text></text>
|
||||
<text class="tax-info">扣除个人所得税<text class="highlight-red">{{ incomeTax}}元</text></text>
|
||||
<!-- <text class="fee-info">扣除提现手续费<text class="highlight-red">{{ (withdrawalBalanceFee / 100).toFixed(2) }}元</text></text> -->
|
||||
<text class="actual-amount">此次提现实际到账<text class="highlight-red">{{ actualAmount}}元</text></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -132,10 +140,11 @@ onMounted(() => {
|
||||
// 计算提现金额
|
||||
const calculateAmounts = () => {
|
||||
// 提现金额 = 账户余额 - 个人所得税 - 提现手续费
|
||||
const totalDeduction = incomeTax.value + withdrawalBalanceFee.value
|
||||
const amount = accountBalance.value - totalDeduction
|
||||
withdrawalAmount.value = accountBalance.value > 0 ? (accountBalance.value/100).toFixed(2) : '0.00'
|
||||
actualAmount.value = amount > 0 ? (amount/100).toFixed(2) : '0.00'
|
||||
// const totalDeduction = incomeTax.value + withdrawalBalanceFee.value
|
||||
// const amount = accountBalance.value - totalDeduction
|
||||
// withdrawalAmount.value = accountBalance.value > 0 ? (accountBalance.value/100).toFixed(2) : '0.00'
|
||||
// actualAmount.value = amount > 0 ? (amount/100).toFixed(2) : '0.00'
|
||||
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
@@ -162,6 +171,63 @@ const goBack = () => {
|
||||
uni.navigateBack()
|
||||
}
|
||||
|
||||
const bankLogoMap = {
|
||||
'工商银行': '/static/icon_bankcard_gongshang.png',
|
||||
'中国银行': '/static/icon_bankcard_zhongguo.png',
|
||||
'建设银行': '/static/icon_bankcard_jianseyinhang.png',
|
||||
'农业银行': '/static/icon_bankcard_nongyeyinhang.png',
|
||||
'交通银行': '/static/icon_bankcard_jiatong.png',
|
||||
'招商银行': '/static/icon_bankcard_zhaoshangyinhang.png',
|
||||
'民生银行': '/static/icon_bankcard_minshneg.png',
|
||||
'兴业银行': '/static/icon_bankcard_xingye.png',
|
||||
'浦发银行': '/static/icon_bankcard_shanghaipudongfazhanyinhang.png',
|
||||
'光大银行': '/static/icon_bankcard_guangda.png',
|
||||
'华夏银行': '/static/icon_bankcard_huaxiayinhnag.png',
|
||||
'中信银行': '/static/icon_bankcard_zhongxinshiye.png',
|
||||
'平安银行': '/static/icon_bankcard_pingan.png',
|
||||
'广发银行': '/static/icon_bankcard_guangfa.png',
|
||||
'邮储银行': '/static/icon_bankcard_youzheng.png',
|
||||
'上海银行': '/static/icon_bankcard_shanghai.png',
|
||||
'北京银行': '/static/icon_bankcard_beijingyinhang.png'
|
||||
}
|
||||
|
||||
const getBankName = (card) => {
|
||||
if (!card) return ''
|
||||
return card.bankName || card.open_bank || ''
|
||||
}
|
||||
|
||||
const getCardTail = (card) => {
|
||||
if (!card) return '8937'
|
||||
const raw = card.cardNumber || card.card_number || ''
|
||||
return raw ? String(raw).slice(-4) : '8937'
|
||||
}
|
||||
|
||||
const getBankLogoImg = (bankName) => {
|
||||
return bankLogoMap[bankName] || ''
|
||||
}
|
||||
|
||||
const getBankLogo = (bankName) => {
|
||||
const bankLogos = {
|
||||
'工商银行': '工',
|
||||
'中国银行': '中',
|
||||
'建设银行': '建',
|
||||
'农业银行': '农',
|
||||
'交通银行': '交',
|
||||
'招商银行': '招',
|
||||
'民生银行': '民',
|
||||
'兴业银行': '兴',
|
||||
'浦发银行': '浦',
|
||||
'光大银行': '光',
|
||||
'华夏银行': '华',
|
||||
'中信银行': '信',
|
||||
'平安银行': '平',
|
||||
'广发银行': '广',
|
||||
'邮储银行': '邮'
|
||||
}
|
||||
if (!bankName) return '工'
|
||||
return bankLogos[bankName] || bankName.charAt(0)
|
||||
}
|
||||
|
||||
// 获取我的账户信息
|
||||
const getMyAccount = async () => {
|
||||
try {
|
||||
@@ -173,7 +239,7 @@ const getMyAccount = async () => {
|
||||
withdrawalBalanceFee.value = res.data.withdrawalBalanceFee
|
||||
lessWithdrawalBalance.value = res.data.lessWithdrawalBalance
|
||||
// 获取账户信息后计算金额
|
||||
calculateAmounts()
|
||||
//calculateAmounts()
|
||||
// 然后获取个人所得税
|
||||
getIncomeTax(accountBalance.value)
|
||||
}
|
||||
@@ -187,10 +253,13 @@ const getIncomeTax = async (amount) => {
|
||||
try {
|
||||
const res = await api.getIncomeTax({amount: amount})
|
||||
console.log('个人所得税:', res)
|
||||
if (res && res.code === 200 && res.data) {
|
||||
incomeTax.value = res.data.incomeTax || 0
|
||||
if (res.code ==200) {
|
||||
incomeTax.value = (res.data.tax/100).toFixed(2) || 0
|
||||
withdrawalAmount.value = (amount/100).toFixed(2) || 0
|
||||
actualAmount.value = (res.data.actual_amount/100).toFixed(2) || 0
|
||||
|
||||
// 获取税费后重新计算金额
|
||||
calculateAmounts()
|
||||
//calculateAmounts()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取个人所得税失败:', error)
|
||||
@@ -214,8 +283,9 @@ const getBankCardList = async () => {
|
||||
confirmText: '去添加',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) {
|
||||
const returnTo = encodeURIComponent('/pages_app/myAccount/withdrawal?from=bankCardList')
|
||||
uni.navigateTo({
|
||||
url: '/pages_app/idcardAuth/bankCardList'
|
||||
url: `/pages_app/idcardAuth/bankCardList?from=withdrawal&returnTo=${returnTo}`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -238,7 +308,7 @@ const selectBankCard = () => {
|
||||
|
||||
// 这里可以实现银行卡选择逻辑
|
||||
uni.showActionSheet({
|
||||
itemList: bankCardList.value.map(card => `${card.bankName} 尾号${card.cardNumber.slice(-4)}`),
|
||||
itemList: bankCardList.value.map(card => `${getBankName(card)} 尾号${getCardTail(card)}`),
|
||||
success: (res) => {
|
||||
selectedBankCard.value = bankCardList.value[res.tapIndex]
|
||||
}
|
||||
@@ -252,8 +322,8 @@ const showWithdrawalRules = () => {
|
||||
const feeAmount = (withdrawalBalanceFee.value / 100).toFixed(2)
|
||||
|
||||
uni.showModal({
|
||||
title: '提现规则',
|
||||
content: `1. 提现金额不得少于${minAmount}元\n2. 单次提现限额为${maxAmount}元\n3. 提现手续费为${feeAmount}元\n4. 工作日24小时内到账`,
|
||||
title: '温馨提示',
|
||||
content: `提交成功后会有工作人员与您联系`,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
})
|
||||
@@ -278,15 +348,7 @@ const confirmWithdrawal = () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查单次提现限额
|
||||
const maxAmount = withdrawalBalanceMaxOnce.value / 100
|
||||
if (parseFloat(withdrawalAmount.value) > maxAmount) {
|
||||
uni.showToast({
|
||||
title: `单次提现限额为${maxAmount.toFixed(2)}元`,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 弹出短信验证码弹框
|
||||
showSmsDialog.value = true
|
||||
@@ -337,7 +399,8 @@ const onGetSmsCode = async () => {
|
||||
} catch (error) {
|
||||
console.error('发送短信验证码失败:', error)
|
||||
uni.showToast({
|
||||
title: '网络错误,请重试',
|
||||
title:error.data.message || error.message || error.data.msg || error.msg || '频繁发送短信,请稍后再试'
|
||||
,
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
@@ -405,7 +468,9 @@ const onCancelSms = () => {
|
||||
|
||||
// 主内容区域
|
||||
.main-content {
|
||||
padding: 0 30rpx;
|
||||
padding-top: calc(var(--status-bar-height) + 44px);
|
||||
padding-bottom: 180rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 加载状态
|
||||
@@ -433,7 +498,7 @@ const onCancelSms = () => {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
padding: 30rpx;
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
@@ -448,30 +513,43 @@ const onCancelSms = () => {
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1rpx;
|
||||
background-color: #f0f0f0;
|
||||
height: 2rpx;
|
||||
background-color: #bab7b7;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.bank-card-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
padding: 30rpx;
|
||||
background-color: #ffffff;
|
||||
|
||||
.bank-logo {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background-color: #8B2316;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 24rpx;
|
||||
|
||||
.bank-icon {
|
||||
font-size: 32rpx;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
|
||||
.bank-logo-img {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.logo-bg {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
background: #E60012;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #E60012;
|
||||
|
||||
.bank-icon {
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,7 +571,7 @@ const onCancelSms = () => {
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
font-size: 32rpx;
|
||||
font-size: 62rpx;
|
||||
color: #cccccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -520,8 +598,8 @@ const onCancelSms = () => {
|
||||
|
||||
// 金额区域
|
||||
.amount-section {
|
||||
padding: 40rpx 0;
|
||||
|
||||
padding: 40rpx 30rpx;
|
||||
background-color: #ffffff;
|
||||
.amount-title {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
@@ -556,7 +634,7 @@ const onCancelSms = () => {
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.highlight-red {
|
||||
color: #8B2316;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -668,6 +746,10 @@ const onCancelSms = () => {
|
||||
color: #8B2316;
|
||||
font-size: 26rpx;
|
||||
border: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:disabled {
|
||||
background: #f5f5f5;
|
||||
|
||||
+436
-238
@@ -1,272 +1,470 @@
|
||||
<template>
|
||||
<view class="my-answer-page">
|
||||
<navBar title="我的意见" />
|
||||
<view class="my-answer-page">
|
||||
<navBar title="我的意见" />
|
||||
|
||||
<scroll-view scroll-y class="content-scroll">
|
||||
<!-- 文本输入 -->
|
||||
<view class="card">
|
||||
<view class="card-title">我的意见 <text class="required">*</text></view>
|
||||
<view class="textarea-wrap">
|
||||
<textarea
|
||||
v-model="form.note"
|
||||
class="textarea"
|
||||
:maxlength="300"
|
||||
placeholder="请依据患者的个人信息、疾病资料及患者所咨询的问题详细解答患者的问题(信息仅提问患者及医生可见,最多输入300个字)"
|
||||
placeholder-class="ph"
|
||||
auto-height
|
||||
/>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="content-scroll">
|
||||
<!-- 文本输入 -->
|
||||
<view class="card">
|
||||
<view class="card-title">我的意见 <text class="required">*</text></view>
|
||||
<view class="textarea-wrap">
|
||||
<textarea
|
||||
v-model="note"
|
||||
class="textarea"
|
||||
:maxlength="300"
|
||||
placeholder="请依据患者的个人信息、疾病资料及患者所咨询的问题详细解答患者的问题(信息仅提问患者及医生可见,最多输入300个字)"
|
||||
placeholder-class="ph"
|
||||
auto-height
|
||||
:adjust-position="false"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图片上传 -->
|
||||
<view class="card">
|
||||
<view class="card-title">相关图片</view>
|
||||
<view class="sub-tip">可以用部分科普或文献来协助回答问题,最多6张</view>
|
||||
<view class="img-grid">
|
||||
<view
|
||||
v-if="imgList.length>0"
|
||||
v-for="(img, index) in imgList"
|
||||
:key="index"
|
||||
class="img-item"
|
||||
@click="preview(index)"
|
||||
>
|
||||
<image :src="docUrl+img" mode="aspectFill" class="img" />
|
||||
<view class="del" @click.stop="remove(index)">×</view>
|
||||
</view>
|
||||
<view v-if="imgList.length < maxImages" class="img-item add" @click="addImages">
|
||||
<view class="plus">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部提交 -->
|
||||
<view class="bottom-fixed">
|
||||
<view class="submit-btn" @click="submit">提交</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 图片上传 -->
|
||||
<view class="card">
|
||||
<view class="card-title">相关图片</view>
|
||||
<view class="sub-tip">可以用部分科普或文献来协助回答问题,最多6张</view>
|
||||
<!-- <view class="imgbox">
|
||||
<uni-file-picker limit="6" v-model="tempImageList" file-mediatype="image" :auto-upload="false" @select="selectImages" @delete="deleteImages" ></uni-file-picker>
|
||||
</view> -->
|
||||
<view class="img-grid">
|
||||
<view
|
||||
v-if="tempImageList.length > 0"
|
||||
v-for="(img, index) in tempImageList"
|
||||
:key="index"
|
||||
class="img-item"
|
||||
@click="preview(index)"
|
||||
>
|
||||
<image :src="img" mode="aspectFill" class="img" />
|
||||
<view class="del" @click.stop="remove(index)">×</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="tempImageList.length < maxImages"
|
||||
class="img-item add"
|
||||
@click="beforeAddImages"
|
||||
>
|
||||
<view class="plus">+</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- <button style="position: fixed;bottom: 200rpx;left: 50%;transform: translateX(-50%);z-index: 99999999999;" @click="test" >测试</button> -->
|
||||
<!-- 底部提交 -->
|
||||
<view class="bottom-fixed">
|
||||
<view class="submit-btn" @click="submit">提交</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import api from '@/api/api'
|
||||
import docUrl from '@/utils/docUrl'
|
||||
import { onLoad,onShow } from '@dcloudio/uni-app'
|
||||
const uuid=ref('');
|
||||
import { ref } from "vue";
|
||||
import navBar from "@/components/navBar/navBar.vue";
|
||||
import api from "@/api/api";
|
||||
import docUrl from "@/utils/docUrl";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import { pathToBase64 } from "image-tools";
|
||||
import { getCameraPermission } from "@/utils/permission.js";
|
||||
import isAndroid from "@/utils/platform.js";
|
||||
const uuid = ref("");
|
||||
const answer_uuid = ref("");
|
||||
const maxImages = 6;
|
||||
const imgList = ref([]);
|
||||
const form = ref({
|
||||
note: '',
|
||||
images: []
|
||||
})
|
||||
const isLock = ref(false);
|
||||
const tempImageList = ref([]);
|
||||
const note = ref("");
|
||||
onLoad((options) => {
|
||||
uuid.value = options.uuid || ''
|
||||
})
|
||||
const getInterrogation=()=>{
|
||||
api.getInterrogation({
|
||||
uuid:uuid.value
|
||||
}).then(res=>{
|
||||
console.log(res)
|
||||
if(res.code === '200' && res.data) {
|
||||
let user=uni.getStorageSync('userInfo');
|
||||
let arr=res.data.AnswerList.filter(item=>{
|
||||
return user.uuid == item.expert_uuid
|
||||
})
|
||||
|
||||
form.value= arr[0];
|
||||
imgList.value= form.value.imgs?form.value.imgs.split(','):[];
|
||||
}
|
||||
})
|
||||
}
|
||||
const updateInterrogationAnswer=()=>{
|
||||
let imgobj={};
|
||||
if(imgList.value.length>0){
|
||||
let count=0;
|
||||
imgList.value.forEach(item=>{
|
||||
imgobj['img'+count]=docUrl+item;
|
||||
})
|
||||
}
|
||||
api.updateInterrogationAnswer({
|
||||
answer_uuid: answer_uuid.value,
|
||||
note: form.value.note,
|
||||
imgsBean: imgobj
|
||||
}).then(res=>{
|
||||
if(res.code == 200){
|
||||
uni.showToast({title: '提交成功', icon: 'none'})
|
||||
uni.navigateBack()
|
||||
}
|
||||
})
|
||||
}
|
||||
const addInterrogationAnswer=()=>{
|
||||
api.addInterrogationAnswer({
|
||||
note: form.value.note,
|
||||
imgsBean: imgobj
|
||||
}).then(res=>{
|
||||
if(res.code == 200){
|
||||
uni.showToast({title: '提交成功', icon: 'none'})
|
||||
uni.navigateBack()
|
||||
}
|
||||
uuid.value = options.uuid || "";
|
||||
answer_uuid.value = options.answer_uuid || "";
|
||||
getInterrogation();
|
||||
});
|
||||
const beforeAddImages = () => {
|
||||
if (isAndroid) {
|
||||
getCameraPermission(addImages);
|
||||
} else {
|
||||
addImages();
|
||||
}
|
||||
};
|
||||
const getInterrogation = () => {
|
||||
api
|
||||
.getInterrogation({
|
||||
uuid: uuid.value,
|
||||
})
|
||||
}
|
||||
onShow(()=>{
|
||||
getInterrogation()
|
||||
})
|
||||
function addImages(){
|
||||
const remain = maxImages - form.value.images.length
|
||||
if(remain <= 0){
|
||||
uni.showToast({title: '最多6张', icon: 'none'})
|
||||
return
|
||||
}
|
||||
uni.chooseImage({
|
||||
count: remain,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album','camera'],
|
||||
success: (res)=>{
|
||||
const paths = (res.tempFilePaths || res.tempFiles?.map(f=>f.path) || [])
|
||||
imgList.value = imgList.value.concat(paths).slice(0, maxImages)
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
if (res.code === "200" && res.data) {
|
||||
let user = uni.getStorageSync("userInfo");
|
||||
let arr = res.data.AnswerList.filter((item) => {
|
||||
return user.uuid == item.expert_uuid;
|
||||
});
|
||||
imgList.value = [];
|
||||
if (arr && arr.length > 0) {
|
||||
note.value = arr[0].note || "";
|
||||
let imgs = arr[0].imgs ? arr[0].imgs.split(",") : [];
|
||||
tempImageList.value = imgs.map((item, index) => {
|
||||
return {
|
||||
name: "图片" + index + 1,
|
||||
url: docUrl + item,
|
||||
};
|
||||
});
|
||||
tempImageList.value = imgs.map((item) => docUrl + item);
|
||||
for (let i = 0; i < imgs.length; i++) {
|
||||
uni.request({
|
||||
url: docUrl + imgs[i],
|
||||
method: "GET",
|
||||
responseType: "arraybuffer",
|
||||
success: (res) => {
|
||||
const base64 = `${uni.arrayBufferToBase64(res.data)}`;
|
||||
imgList.value.push(base64);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const updateInterrogationAnswer = () => {
|
||||
if (note.value.trim().length < 5) {
|
||||
uni.showToast({ title: "输入意见至少5个字", icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (isLock.value) {
|
||||
return;
|
||||
}
|
||||
isLock.value = true;
|
||||
let imgobj = {};
|
||||
if (imgList.value.length > 0) {
|
||||
let count = 0;
|
||||
imgList.value.forEach((item, index) => {
|
||||
imgobj["img" + (index + 1)] = item;
|
||||
});
|
||||
}
|
||||
api
|
||||
.updateInterrogationAnswer({
|
||||
uuid: answer_uuid.value,
|
||||
note: note.value,
|
||||
imgsBean: imgobj,
|
||||
})
|
||||
.then((res) => {
|
||||
isLock.value = false;
|
||||
if (res.code == 200) {
|
||||
uni.showToast({ title: "提交成功", icon: "none" });
|
||||
uni.$emit("updateStatus", 1);
|
||||
uni.navigateBack();
|
||||
}
|
||||
});
|
||||
};
|
||||
const test = () => {
|
||||
uni.navigateTo({
|
||||
url: "/pages/upload/upload",
|
||||
});
|
||||
};
|
||||
const addInterrogationAnswer = () => {
|
||||
if (note.value.trim().length < 5) {
|
||||
uni.showToast({ title: "输入意见至少5个字", icon: "none" });
|
||||
return;
|
||||
}
|
||||
if (isLock.value) {
|
||||
return;
|
||||
}
|
||||
isLock.value = true;
|
||||
let imgobj = {};
|
||||
if (imgList.value.length > 0) {
|
||||
imgList.value.forEach((item, index) => {
|
||||
imgobj["img" + (index + 1)] = item;
|
||||
});
|
||||
}
|
||||
api
|
||||
.addInterrogationAnswer({
|
||||
step1_uuid: uuid.value,
|
||||
note: note.value,
|
||||
imgsBean: imgobj,
|
||||
})
|
||||
.then((res) => {
|
||||
isLock.value = false;
|
||||
if (res.code == 200) {
|
||||
uni.$emit("updateStatus", 1);
|
||||
uni.showToast({ title: "提交成功", icon: "none" });
|
||||
uni.navigateBack();
|
||||
}
|
||||
});
|
||||
};
|
||||
const selectImages = (e) => {
|
||||
let tempFilePaths = e.tempFiles;
|
||||
console.log(e);
|
||||
tempImageList.value = [...tempImageList.value, ...tempFilePaths];
|
||||
for (let i = 0; i < tempFilePaths.length; i++) {
|
||||
pathToBase64(tempFilePaths[i].url)
|
||||
.then((base64) => {
|
||||
console.log("转base64成功");
|
||||
imgList.value.push(base64.split(",")[1]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("转base64成功");
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
console.log(tempImageList.value);
|
||||
console.log(imgList.value);
|
||||
};
|
||||
const addImages = () => {
|
||||
const remain = maxImages - imgList.value.length;
|
||||
if (remain <= 0) {
|
||||
uni.showToast({ title: "最多6张", icon: "none" });
|
||||
return;
|
||||
}
|
||||
console.log("执行选择图片");
|
||||
console.log('isAndroid:'+isAndroid)
|
||||
if (isAndroid) {
|
||||
uni.chooseImage({
|
||||
count: remain,
|
||||
sizeType: ["original", "compressed"],
|
||||
sourceType: ["album", "camera"],
|
||||
success: (res) => {
|
||||
console.log("获取到照片");
|
||||
console.log(res.tempFilePaths);
|
||||
tempImageList.value = [...tempImageList.value, ...res.tempFilePaths];
|
||||
for (let i = 0; i < res.tempFilePaths.length; i++) {
|
||||
uni.saveFile({
|
||||
tempFilePath: res.tempFilePaths[i],
|
||||
success: (res1) => {
|
||||
pathToBase64(res1.savedFilePath)
|
||||
.then((base64) => {
|
||||
console.log("转base64成功");
|
||||
imgList.value.push(base64.split(",")[1]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("转base64失败");
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
} else {
|
||||
uni.chooseImage({
|
||||
count: remain,
|
||||
sourceType: ["album", "camera"],
|
||||
crop: {
|
||||
width: 375,
|
||||
height: 500,
|
||||
resize: true,
|
||||
quality:100,
|
||||
},
|
||||
success: (res) => {
|
||||
console.log("获取到照片");
|
||||
console.log(res.tempFilePaths);
|
||||
tempImageList.value = [...tempImageList.value, ...res.tempFilePaths];
|
||||
for (let i = 0; i < res.tempFilePaths.length; i++) {
|
||||
uni.getImageInfo({
|
||||
src: res.tempFilePaths[i],
|
||||
success: (result) => {
|
||||
console.log(result);
|
||||
if (result.width > 1000) {
|
||||
uni.compressImage({
|
||||
quality:100,
|
||||
src: res.tempFilePaths[i],
|
||||
success: (result2) => {
|
||||
console.log("压缩成功");
|
||||
console.log(result2.tempFilePath);
|
||||
pathToBase64(result2.tempFilePath)
|
||||
.then((base64) => {
|
||||
console.log("转base64成功");
|
||||
imgList.value.push(base64.split(",")[1]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("转base64失败");
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("压缩失败:" + err.errMsg);
|
||||
},
|
||||
});
|
||||
} else {
|
||||
pathToBase64(res.tempFilePaths[i])
|
||||
.then((base64) => {
|
||||
console.log("转base64成功");
|
||||
imgList.value.push(base64.split(",")[1]);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("转base64失败");
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.log("获取图片信息失败:");
|
||||
console.error(err.errMsg);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function preview(index) {
|
||||
uni.previewImage({
|
||||
urls: tempImageList.value,
|
||||
current: index,
|
||||
});
|
||||
}
|
||||
|
||||
function preview(index){
|
||||
uni.previewImage({
|
||||
urls:imgList.map(path=> docUrl + path),
|
||||
current: index
|
||||
})
|
||||
function remove(index) {
|
||||
imgList.value.splice(index, 1);
|
||||
tempImageList.value.splice(index, 1);
|
||||
}
|
||||
const deleteImages = (e) => {
|
||||
let index = e.index;
|
||||
imgList.value.splice(index, 1);
|
||||
tempImageList.value.splice(index, 1);
|
||||
};
|
||||
|
||||
function remove(index){
|
||||
imgList.valuesplice(index, 1)
|
||||
}
|
||||
|
||||
function submit(){
|
||||
if(!form.value.note.trim()){
|
||||
uni.showToast({title:'请输入意见', icon:'none'})
|
||||
return
|
||||
}
|
||||
if(answer_uuid.value){
|
||||
updateInterrogationAnswer()
|
||||
}else{
|
||||
addInterrogationAnswer()
|
||||
}
|
||||
function submit() {
|
||||
if (answer_uuid.value) {
|
||||
updateInterrogationAnswer();
|
||||
} else {
|
||||
addInterrogationAnswer();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-answer-page{
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.my-answer-page {
|
||||
background-color: #fff;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.content-scroll{
|
||||
flex: 1;
|
||||
position: fixed;
|
||||
top: 135rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 160rpx;
|
||||
padding: 24rpx 24rpx 0;
|
||||
box-sizing: border-box;
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
position: fixed;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 160rpx;
|
||||
padding: 24rpx 24rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card{
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.card-title{
|
||||
font-size: 32rpx;
|
||||
color: #8B2316;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
color: #8b2316;
|
||||
font-weight: 500;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
.required{ color: #ff4d4f; }
|
||||
|
||||
.textarea-wrap{
|
||||
position: relative;
|
||||
background: #f7f7f7;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 88rpx 16rpx 16rpx;
|
||||
}
|
||||
.textarea{
|
||||
min-height: 180rpx;
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
.ph{ color:#999; }
|
||||
.voice-btn{
|
||||
position: absolute;
|
||||
right: 16rpx;
|
||||
bottom: 16rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 32rpx;
|
||||
background: #b90f0f;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
.required {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.sub-tip{
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
.textarea-wrap {
|
||||
position: relative;
|
||||
background: #f7f7f7;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx 16rpx 16rpx 16rpx;
|
||||
}
|
||||
.textarea {
|
||||
min-height: 180rpx;
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
.ph {
|
||||
color: #999;
|
||||
}
|
||||
.voice-btn {
|
||||
position: absolute;
|
||||
right: 16rpx;
|
||||
bottom: 16rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 32rpx;
|
||||
background: #b90f0f;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.img-grid{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16rpx;
|
||||
}
|
||||
.img-item{
|
||||
position: relative;
|
||||
width:150rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.img{ width: 100%; height: 100%; }
|
||||
.add{ display:flex; align-items:center; justify-content:center; }
|
||||
.plus{ font-size: 80rpx; color:#c0c0c0; line-height: 1; }
|
||||
.del{
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 22rpx;
|
||||
background: rgba(0,0,0,.5);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 44rpx;
|
||||
font-size: 28rpx;
|
||||
.sub-tip {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.bottom-fixed{
|
||||
position: fixed;
|
||||
left: 0; right: 0; bottom: 0;
|
||||
background: #fff;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0,0,0,.06);
|
||||
.img-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16rpx;
|
||||
}
|
||||
.submit-btn{
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
text-align: center;
|
||||
background: #00bcd4;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
.img-item {
|
||||
position: relative;
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.plus {
|
||||
font-size: 80rpx;
|
||||
color: #c0c0c0;
|
||||
line-height: 1;
|
||||
}
|
||||
.del {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
border-radius: 22rpx;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 44rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.bottom-fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
padding: 24rpx;
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
text-align: center;
|
||||
background: #3cc7c0;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<view class="my-application-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
<view class="navBox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的应用"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -17,6 +19,7 @@
|
||||
}}</text>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
</view>
|
||||
|
||||
<scroll-view class="content" scroll-y>
|
||||
<!-- 我的应用部分 -->
|
||||
@@ -102,6 +105,14 @@
|
||||
|
||||
// 获取用户图标数据
|
||||
const addUserIcon = () => {
|
||||
if(myApps.value.length <3){
|
||||
uni.showToast({
|
||||
title: '至少添加3个应用',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
});
|
||||
return false;
|
||||
}
|
||||
api.addUserIcon({
|
||||
idStr:myApps.value.map(item => item.id).join(',')
|
||||
}).then(res => {
|
||||
@@ -190,7 +201,7 @@
|
||||
navTo({
|
||||
url:url
|
||||
})
|
||||
}else if(app.name=="肝病新闻"){
|
||||
}else if(app.name=="肝胆新闻"){
|
||||
url='/pages_app/news/news'
|
||||
navTo({
|
||||
url:url
|
||||
|
||||
+673
-89
@@ -1,13 +1,45 @@
|
||||
<template>
|
||||
<view class="my-code-page">
|
||||
<view class="navbox" v-if="!jieping">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的二维码"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
<template #right>
|
||||
<view class="nav-actions">
|
||||
<view class="collect-img" @click="shareToggle" >
|
||||
<image
|
||||
class="share-img-icon"
|
||||
:src="shareIcon"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</uni-nav-bar>
|
||||
|
||||
</view>
|
||||
<!-- <navBar title="我的二维码" v-if="!jieping"/> -->
|
||||
<!-- 自己实现的 html2canvas 截图组件 -->
|
||||
<MyHtml2canvas
|
||||
ref="shotRef"
|
||||
domId="render-dom"
|
||||
@renderOver="onRenderOver"
|
||||
/>
|
||||
<view class="my-code-page renderDom" id="render-dom" :class="{'active':jieping}">
|
||||
<!-- <webview src="https://dev-wx.igandan.com/expert/expertcodeimg?expert_uuid=9UFkll2Xo57km6224XE&fromtype=doctor"></webview> -->
|
||||
<!-- 顶部导航栏 -->
|
||||
<navBar title="我的二维码" />
|
||||
|
||||
|
||||
<!-- 内容 -->
|
||||
<scroll-view scroll-y class="page-scroll">
|
||||
<scroll-view scroll-y class="page-scroll" id="pageContent">
|
||||
<!-- 顶部蓝色横幅 -->
|
||||
<view class="blue-banner">
|
||||
<up-image :src="bgImg" width="100%" mode="widthFix" ></up-image>
|
||||
<up-image :src="bgBase64 || bgImg" width="100%" mode="widthFix" ></up-image>
|
||||
</view>
|
||||
|
||||
<!-- 白色信息卡 -->
|
||||
@@ -16,10 +48,17 @@
|
||||
<view class="leftCircle"></view>
|
||||
<view class="rightCircle"></view>
|
||||
<view class="halfCircle"></view>
|
||||
<view class="avatar-wrapper">
|
||||
<image class="avatar" :src="docUrl+userInfo.photo" mode="aspectFill" />
|
||||
<view class="star" v-if="userInfo.isStar==1">
|
||||
咨询专家
|
||||
</view>
|
||||
<view class="name-viewne">{{ userInfo.realName }} {{ userInfo.positionName }}</view>
|
||||
<view class="avatar-wrapper">
|
||||
<image
|
||||
class="avatar"
|
||||
:src="userInfo.avatarBase64 || userInfo.localPhoto || (docUrl+userInfo.photo)"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
<view class="name-viewne">{{ userInfo.realName }} <text class="position-name">{{ userInfo.positionName }}</text></view>
|
||||
<view class="org-viewne">{{ userInfo.hospitalName }}</view>
|
||||
<view class="dash-viewne"></view>
|
||||
<view class="slogan">
|
||||
@@ -28,10 +67,10 @@
|
||||
</view>
|
||||
<view class="contact-qr">
|
||||
<view class="contact-btn">
|
||||
<up-image :src="viewnkImg" width="430rpx" height="131rpx" ></up-image>
|
||||
<up-image :src="viewnkBase64 || viewnkImg" width="430rpx" height="131rpx" ></up-image>
|
||||
|
||||
</view>
|
||||
<image class="qr-img" :src="docUrl+userInfo.qrcode" mode="aspectFit" />
|
||||
<image class="qr-img" :src="userInfo.localQrcode || (docUrl+userInfo.qrcode)" mode="aspectFit" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -44,8 +83,8 @@
|
||||
<view class="s-bottom">
|
||||
<view>
|
||||
<view class="descrow"><text>1</text>微信扫一扫上方二维码,关注“肝胆相照一家人”公众号</view>
|
||||
<view class="descrow"><text>2</text>点击“邹建东专家工作室”,选择微信登录,注册后直接发送随访申请</view>
|
||||
<view class="descrow"><text>3</text>若未弹出“随访申请发送成功”提示,请再次点击“邹建东专家工作室”发送随访申请</view>
|
||||
<view class="descrow"><text>2</text>点击“{{ userInfo.realName }}专家工作室”,选择微信登录,注册后直接发送随访申请</view>
|
||||
<view class="descrow"><text>3</text>若未弹出“随访申请发送成功”提示,请再次点击“{{ userInfo.realName }}专家工作室”发送随访申请</view>
|
||||
<view class="descrow"><text>4</text>审核通过后,点击“就医服务-随访交流”,与专家进行图文交流</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -58,100 +97,470 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部保存按钮 -->
|
||||
<view class="save-bar">
|
||||
<button class="save-btn" @click="onSave">保存二维码到手机</button>
|
||||
<view class="save-bar" v-if="!jieping">
|
||||
<button class="save-btn" @click="onSave">保存到手机相册</button>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 分享弹窗 -->
|
||||
<uni-popup ref="shareRef" type="bottom" safeArea backgroundColor="#fff">
|
||||
<view class="share-popup">
|
||||
<view class="share-title">分享到</view>
|
||||
<view class="share-content">
|
||||
<view class="share-item" @click="shareToWechat">
|
||||
<view class="share-icon wechat-icon">
|
||||
<image class="share-img" :src="wxImg" mode="aspectFill" />
|
||||
</view>
|
||||
<text class="share-text">微信</text>
|
||||
</view>
|
||||
<view class="share-item" @click="shareToMoments">
|
||||
<view class="share-icon moments-icon">
|
||||
<image class="share-img" :src="friendImg" mode="aspectFill" />
|
||||
</view>
|
||||
<text class="share-text">朋友圈</text>
|
||||
</view>
|
||||
<view class="share-item" @click="shareToWeibo">
|
||||
<view class="share-icon weibo-icon">
|
||||
<image class="share-img" :src="sinaImg" mode="aspectFill" />
|
||||
</view>
|
||||
<text class="share-text">新浪微博</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="share-cancel" @click="closeShare">
|
||||
<text>取消</text>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup >
|
||||
import { base64ToPath } from 'image-tools'
|
||||
import { urlToBase64 } from '@/uni_modules/sp-html2canvas-render/utils/index.js'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import { onShow,onBackPress,onLoad} from "@dcloudio/uni-app";
|
||||
import { ref } from 'vue';
|
||||
import MyHtml2canvas from '@/components/MyHtml2canvas.vue'
|
||||
import docUrl from '@/utils/docUrl'
|
||||
import bgImg from "@/static/background.jpg"
|
||||
import otherHost from '@/utils/otherHost'
|
||||
import shareIcon from "@/static/icon_share.png";
|
||||
import sinaImg from "@/static/share_sina.png";
|
||||
import wxImg from "@/static/share_weixin.png";
|
||||
import friendImg from "@/static/share_wxc.png";
|
||||
import logoImg from "@/static/weiboShare.png";
|
||||
import isAndroid from "@/utils/platform.js";
|
||||
// 背景图使用线上地址
|
||||
const bgImg = 'https://oss.igandan.com/images/expertcode_background.jpg?v=1'
|
||||
import viewnkImg from "@/static/arr.png"
|
||||
|
||||
const userInfo = ref({})
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
onShow(()=>{
|
||||
userInfo.value = uni.getStorageSync('userInfo')
|
||||
})
|
||||
const onSave = () => {
|
||||
// 检查是否有二维码图片
|
||||
if (!userInfo.value.qrcode) {
|
||||
uni.showToast({ title: '二维码不存在', icon: 'none' });
|
||||
return;
|
||||
const jieping = ref(false)
|
||||
const shotRef = ref(null)
|
||||
const bgBase64 = ref('')
|
||||
const viewnkBase64 = ref('')
|
||||
const from=ref('');
|
||||
const title=ref('');
|
||||
const summary=ref('参与爱肝行动,共创美好前程');
|
||||
const link=ref('');
|
||||
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
const goBack = () => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
|
||||
// 显示加载提示
|
||||
uni.showLoading({ title: '保存中...' });
|
||||
|
||||
// 下载二维码图片
|
||||
uni.downloadFile({
|
||||
url: docUrl + userInfo.value.qrcode,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
// 保存到相册
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('保存失败:', err);
|
||||
|
||||
// 根据错误类型给出不同提示
|
||||
if (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize')) {
|
||||
uni.showModal({
|
||||
title: '权限提示',
|
||||
content: '需要相册权限才能保存图片,请在设置中开启权限',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '下载失败,请检查网络',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('下载失败:', err);
|
||||
uni.showToast({
|
||||
title: '下载失败,请检查网络',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
};
|
||||
onLoad((options) => {
|
||||
from.value = options.from;
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "我的二维码",
|
||||
},
|
||||
});
|
||||
})
|
||||
|
||||
// 页面显示时拉取用户信息,并尽量把图片转成 base64,避免 html2canvas 跨域污染
|
||||
onShow(async () => {
|
||||
const info = uni.getStorageSync('userInfo') || {}
|
||||
console.log('[myCode] onShow userInfo:', info)
|
||||
title.value = '不方便到医院就诊,'+info.realName+'医生在肝胆相照平台帮助您!';
|
||||
link.value = otherHost+'/expert/expertcodeimg?expert_uuid='+info.uuid+'&fromtype=doctor'
|
||||
// 背景图转 base64
|
||||
if (!bgBase64.value) {
|
||||
try {
|
||||
console.log('[myCode] 准备将背景图转为 base64:', bgImg)
|
||||
const bg = await urlToBase64(bgImg, 'jpg')
|
||||
bgBase64.value = bg
|
||||
console.log('[myCode] 背景图转 base64 成功,长度:', bg && bg.length)
|
||||
} catch (e) {
|
||||
console.error('[myCode] 背景图转 base64 失败:', e)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 按钮图转 base64
|
||||
if (!viewnkBase64.value) {
|
||||
try {
|
||||
console.log('[myCode] 准备将按钮图转为 base64:', viewnkImg)
|
||||
const btn = await urlToBase64(viewnkImg, 'png')
|
||||
viewnkBase64.value = btn
|
||||
console.log('[myCode] 按钮图转 base64 成功,长度:', btn && btn.length)
|
||||
} catch (e) {
|
||||
console.error('[myCode] 按钮图转 base64 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 头像:远程地址转 base64,写入 avatarBase64,优先被使用
|
||||
if (info.photo && !info.avatarBase64) {
|
||||
const avatarUrl = docUrl + info.photo
|
||||
try {
|
||||
console.log('[myCode] 准备将头像转为 base64:', avatarUrl)
|
||||
const avatarBase64 = await urlToBase64(avatarUrl, 'jpg')
|
||||
info.avatarBase64 = avatarBase64
|
||||
console.log('[myCode] 头像转 base64 成功,长度:', avatarBase64 && avatarBase64.length)
|
||||
} catch (e) {
|
||||
console.error('[myCode] 头像转 base64 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 二维码:远程地址转 base64,写入 localQrcode,模板已优先使用该字段
|
||||
if (info.qrcode && !info.localQrcode) {
|
||||
const qrUrl = docUrl + info.qrcode
|
||||
try {
|
||||
console.log('[myCode] 准备将二维码转为 base64:', qrUrl)
|
||||
const qrBase64 = await urlToBase64(qrUrl, 'png')
|
||||
info.localQrcode = qrBase64
|
||||
console.log('[myCode] 二维码转 base64 成功,长度:', qrBase64 && qrBase64.length)
|
||||
} catch (e) {
|
||||
console.error('[myCode] 二维码转 base64 失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
userInfo.value = info
|
||||
})
|
||||
|
||||
// 保存失败时统一处理
|
||||
const handleSaveError = (err) => {
|
||||
if (err && err.errMsg && (err.errMsg.includes('auth deny') || err.errMsg.includes('authorize'))) {
|
||||
uni.showModal({
|
||||
title: '权限提示',
|
||||
content: '需要相册权限才能保存图片,请在系统设置中开启相册权限',
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 点击“保存到手机相册”
|
||||
const onSave = () => {
|
||||
console.log('[myCode] onSave 点击,准备开始截图')
|
||||
|
||||
// 使用自定义组件触发 html2canvas(内部通过 renderjs 在视图层执行)
|
||||
jieping.value = true
|
||||
|
||||
// 调用自定义组件方法开始渲染
|
||||
if (shotRef.value && shotRef.value.h2cRenderDom) {
|
||||
shotRef.value.h2cRenderDom()
|
||||
} else {
|
||||
console.error('[myCode] shotRef 或 h2cRenderDom 不存在')
|
||||
jieping.value = false
|
||||
uni.showToast({
|
||||
title: '截图组件未准备好',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
// 自定义组件截图完成回调(拿到 base64)
|
||||
const onRenderOver = (base64) => {
|
||||
console.log('[myCode] onRenderOver base64 长度:', base64 && base64.length)
|
||||
if (!base64) {
|
||||
jieping.value = false
|
||||
uni.showToast({
|
||||
title: '生成图片失败',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
base64ToPath(base64)
|
||||
.then((res) => {
|
||||
const path = res.path || res
|
||||
console.log('[myCode] base64ToPath 转换成功,path:', path)
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: path,
|
||||
success() {
|
||||
uni.showToast({
|
||||
title: '保存图片成功',
|
||||
mask: false,
|
||||
duration: 1500
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
console.error('[myCode] 保存到相册失败:', err)
|
||||
handleSaveError(err)
|
||||
},
|
||||
complete() {
|
||||
jieping.value = false
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('[myCode] base64ToPath 失败:', err)
|
||||
handleSaveError(err)
|
||||
jieping.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const shareRef = ref();
|
||||
// 分享APP
|
||||
const shareToggle = () => {
|
||||
shareRef.value.open();
|
||||
};
|
||||
|
||||
// 关闭分享弹窗
|
||||
const closeShare = () => {
|
||||
shareRef.value.close();
|
||||
};
|
||||
|
||||
// 分享到微信
|
||||
const shareToWechat = () => {
|
||||
// #ifdef APP-PLUS
|
||||
// 使用系统分享
|
||||
uni.downloadFile({
|
||||
url:'https://doc.igandan.com/app/html/img/2016/20160714132557.png',
|
||||
success: function (res) {
|
||||
uni.compressImage({
|
||||
src: res.tempFilePath,
|
||||
quality: 60,
|
||||
success: function (res2) {
|
||||
uni.share({
|
||||
provider: "weixin",
|
||||
scene: "WXSceneSession",
|
||||
type: 0,
|
||||
title: title.value,
|
||||
summary: summary.value,
|
||||
href: link.value,
|
||||
imageUrl: res2.tempFilePath,
|
||||
success: function (res) {
|
||||
console.log("success:" + JSON.stringify(res));
|
||||
},
|
||||
fail: function (err) {
|
||||
console.log("fail:" + JSON.stringify(err));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
// uni.share({
|
||||
// provider: "weixin",
|
||||
// scene: "WXSceneSession",
|
||||
// type: 0,
|
||||
// title: videoInfo.value.name,
|
||||
// summary: videoInfo.value.note,
|
||||
// href: shareLink.value,
|
||||
// imageUrl: docUrl + videoInfo.value.imgpath,
|
||||
// success: function (res) {
|
||||
// //console.log("success:" + JSON.stringify(res));
|
||||
// },
|
||||
// fail: function (err) {
|
||||
// //console.log("fail:" + JSON.stringify(err));
|
||||
// },
|
||||
// });
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// H5环境下的分享
|
||||
if (navigator.share) {
|
||||
navigator
|
||||
.share({
|
||||
title: "肝胆相照APP",
|
||||
text: "专业的医疗健康平台,快来下载体验吧!",
|
||||
url: shareLink.value,
|
||||
})
|
||||
.then(() => {
|
||||
uni.showToast({
|
||||
title: "分享成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
uni.showToast({
|
||||
title: "分享失败",
|
||||
icon: "none",
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 复制到剪贴板
|
||||
uni.setClipboardData({
|
||||
data:
|
||||
"肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接:" +
|
||||
shareLink.value,
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: "已复制到剪贴板",
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序分享
|
||||
uni.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ["shareAppMessage", "shareTimeline"],
|
||||
});
|
||||
// #endif
|
||||
|
||||
closeShare();
|
||||
};
|
||||
|
||||
// 分享到朋友圈
|
||||
const shareToMoments = () => {
|
||||
// #ifdef APP-PLUS
|
||||
uni.downloadFile({
|
||||
url: 'https://doc.igandan.com/app/html/img/2016/20160714132557.png',
|
||||
success: function (res) {
|
||||
uni.compressImage({
|
||||
src: res.tempFilePath,
|
||||
quality: 60,
|
||||
success: function (res2) {
|
||||
uni.share({
|
||||
provider: "weixin",
|
||||
scene: "WXSceneTimeline",
|
||||
type: 0,
|
||||
title: title.value,
|
||||
summary: summary.value,
|
||||
href: link.value,
|
||||
imageUrl: res2.tempFilePath,
|
||||
success: function (res) {
|
||||
//console.log("success:" + JSON.stringify(res));
|
||||
},
|
||||
fail: function (err) {
|
||||
//console.log("fail:" + JSON.stringify(err));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// 复制到剪贴板
|
||||
uni.setClipboardData({
|
||||
data: "肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接:https://www.igandan.com",
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: "已复制到剪贴板,可分享到朋友圈",
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.showShareMenu({
|
||||
withShareTicket: true,
|
||||
menus: ["shareAppMessage", "shareTimeline"],
|
||||
});
|
||||
// #endif
|
||||
|
||||
closeShare();
|
||||
};
|
||||
|
||||
// 分享到新浪微博
|
||||
const shareToWeibo = () => {
|
||||
// #ifdef APP-PLUS
|
||||
uni.share({
|
||||
provider: "sinaweibo",
|
||||
type: 0,
|
||||
title: title.value,
|
||||
summary: summary.value,
|
||||
href: link.value,
|
||||
imageUrl: logoImg,
|
||||
success: function (res) {
|
||||
//console.log("分享成功");
|
||||
},
|
||||
fail: function (err) {
|
||||
//console.log("fail:" + JSON.stringify(err));
|
||||
},
|
||||
});
|
||||
// plus.share.sendWithSystem({
|
||||
// type: 'text',
|
||||
// content: '肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接:https://www.igandan.com'
|
||||
// }, () => {
|
||||
// uni.showToast({
|
||||
// title: '分享成功',
|
||||
// icon: 'success'
|
||||
// })
|
||||
// }, (err) => {
|
||||
// console.log('分享失败:', err)
|
||||
// uni.showToast({
|
||||
// title: '分享失败',
|
||||
// icon: 'none'
|
||||
// })
|
||||
// })
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// 复制到剪贴板
|
||||
uni.setClipboardData({
|
||||
data: "肝胆相照APP - 专业的医疗健康平台,快来下载体验吧!\n下载链接:https://www.igandan.com",
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: "已复制到剪贴板,可分享到微博",
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
});
|
||||
// #endif
|
||||
|
||||
closeShare();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.share-img {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
}
|
||||
.share-img-icon {
|
||||
width: 40rpx;
|
||||
height:40rpx;
|
||||
}
|
||||
.nav-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
.my-code-page {
|
||||
min-height: 100vh;
|
||||
background-color: #0d7dfd;
|
||||
|
||||
.active{
|
||||
transform: scale(0.8);
|
||||
margin-top: -calc(var(--status-bar-height) + 44px);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.squrebox{
|
||||
margin:0 30rpx;
|
||||
|
||||
@@ -226,7 +635,8 @@ const onSave = () => {
|
||||
}
|
||||
}
|
||||
.page-scroll {
|
||||
height: calc(100vh - 100rpx);
|
||||
margin-top: calc(var(--status-bar-height) + 44px);
|
||||
// height: calc(100vh - var(--status-bar-height) - 44px);
|
||||
padding-bottom: 140rpx;
|
||||
}
|
||||
|
||||
@@ -251,7 +661,7 @@ const onSave = () => {
|
||||
|
||||
.qr-card {
|
||||
position: relative;
|
||||
margin: -120rpx 30rpx 30rpx;
|
||||
margin: -80rpx 30rpx 30rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 20rpx;
|
||||
padding: 140rpx 30rpx 30rpx;
|
||||
@@ -275,6 +685,22 @@ const onSave = () => {
|
||||
border-radius: 50%;
|
||||
background-color: #0d7dfd;
|
||||
}
|
||||
.star{
|
||||
position: absolute;
|
||||
top: 48rpx;
|
||||
height: 40rpx;
|
||||
padding:0 16rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background-color:#ff9f1a;
|
||||
color: #fff;
|
||||
border-radius: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index:10;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.halfCircle{
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
@@ -312,13 +738,17 @@ const onSave = () => {
|
||||
|
||||
.name-viewne {
|
||||
text-align: center;
|
||||
font-size: 34rpx;
|
||||
font-size: 36rpx;
|
||||
color: #1a76d2;
|
||||
font-weight: bold;
|
||||
margin-top: 10rpx;
|
||||
.position-name{
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
.org-viewne {
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-size: 36rpx;
|
||||
color: #4a90e2;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
@@ -400,4 +830,158 @@ const onSave = () => {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 分享弹窗样式 */
|
||||
.share-popup {
|
||||
background-color: #fff;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
padding: 40rpx 0 0;
|
||||
}
|
||||
|
||||
.share-title {
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
margin-bottom: 40rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.share-content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 0 40rpx 40rpx;
|
||||
}
|
||||
|
||||
.share-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.wechat-icon {
|
||||
background-color: #07c160;
|
||||
}
|
||||
|
||||
.moments-icon {
|
||||
background-color: #07c160;
|
||||
}
|
||||
|
||||
.weibo-icon {
|
||||
background-color: #e6162d;
|
||||
}
|
||||
|
||||
.qq-icon {
|
||||
background-color: #12b7f5;
|
||||
}
|
||||
|
||||
.share-icon-text {
|
||||
font-size: 50rpx;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.share-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.share-cancel {
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.share-cancel:active {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
// 删除确认弹窗
|
||||
.delete-modal-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.delete-modal-content {
|
||||
width: 600rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 60rpx 40rpx 40rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.delete-modal-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.delete-modal-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 50rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.delete-modal-buttons {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.delete-modal-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
|
||||
&:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #8b2316;
|
||||
color: #fff;
|
||||
|
||||
&:active {
|
||||
background-color: #6b1a0f;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -265,9 +265,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.journal-list {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: 180rpx;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
padding-bottom: 100rpx; /* 为底部操作栏留出空间 */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -166,9 +166,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.document-list {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: 180rpx;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -172,7 +172,7 @@ const onLoadMore = () => {
|
||||
}
|
||||
|
||||
.history-list {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
position: fixed;
|
||||
top:140rpx;
|
||||
bottom:0;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@clickLeft="goBack()"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -177,9 +177,9 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.news-list {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: 180rpx;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
@@ -172,7 +172,7 @@ const onLoadMore = () => {
|
||||
}
|
||||
|
||||
.history-list {
|
||||
height: calc(100vh - 140rpx);
|
||||
height: calc(100vh - 180rpx);
|
||||
position: fixed;
|
||||
top:140rpx;
|
||||
bottom:0;
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
<template>
|
||||
<view class="detail-page">
|
||||
<navBar title="订单详情" />
|
||||
|
||||
<view class="order-card">
|
||||
<view class="order-top">
|
||||
<text class="download-no">下载课件号: {{ detail.downloadNo || "--" }}</text>
|
||||
<text class="pay-status">{{ detail.statusText || "--" }}</text>
|
||||
</view>
|
||||
|
||||
<view class="section-divider"></view>
|
||||
|
||||
<view class="course-title">{{ detail.title || "--" }}</view>
|
||||
|
||||
|
||||
|
||||
<view class="info-list">
|
||||
<view class="info-row">
|
||||
<text class="info-label">课件作者:</text>
|
||||
<text class="info-value">{{ detail.author || "--" }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">金额:</text>
|
||||
<text class="info-value amount">{{ detail.amountText || "--" }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">创建时间:</text>
|
||||
<text class="info-value">{{ detail.createTime || "--" }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">支付方式:</text>
|
||||
<text class="info-value">{{ detail.payType}}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="info-label">支付时间:</text>
|
||||
<text class="info-value">{{ detail.payTime || "--" }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import api from "@/api/api.js";
|
||||
|
||||
const coursewareId = ref("");
|
||||
const detail = ref({
|
||||
downloadNo: "",
|
||||
statusText: "",
|
||||
title: "",
|
||||
author: "",
|
||||
amountText: "",
|
||||
createTime: "",
|
||||
payType: "",
|
||||
payTime: "",
|
||||
});
|
||||
|
||||
const formatDateTime = (value) => {
|
||||
if (!value) return "";
|
||||
if (typeof value === "string" && value.includes("-")) return value;
|
||||
const timeNum = Number(value);
|
||||
if (!timeNum) return "";
|
||||
const ms = timeNum < 10000000000 ? timeNum * 1000 : timeNum;
|
||||
const d = new Date(ms);
|
||||
const y = d.getFullYear();
|
||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(d.getDate()).padStart(2, "0");
|
||||
const h = String(d.getHours()).padStart(2, "0");
|
||||
const min = String(d.getMinutes()).padStart(2, "0");
|
||||
const s = String(d.getSeconds()).padStart(2, "0");
|
||||
return `${y}-${m}-${day} ${h}:${min}:${s}`;
|
||||
};
|
||||
|
||||
const formatAmount = (value) => {
|
||||
if (value === undefined || value === null || value === "") return "";
|
||||
const num = Number(value);
|
||||
if (Number.isNaN(num)) return "";
|
||||
const amount = num / 100;
|
||||
return `${amount.toFixed(2)}元`;
|
||||
};
|
||||
|
||||
const formatStatus = (raw) => {
|
||||
if (raw === undefined || raw === null) return "";
|
||||
const text = String(raw).toLowerCase();
|
||||
if (text === "paid" || text === "success" || text === "1" || text === "2") return "已支付";
|
||||
if (text === "unpaid" || text === "0" || text === "created") return "未支付";
|
||||
return String(raw);
|
||||
};
|
||||
|
||||
const formatPayType = (raw) => {
|
||||
if(raw=='balance'){
|
||||
return '余额支付';
|
||||
}else if(raw=='FREE'){
|
||||
return '免费'
|
||||
}else if(raw=='USEWELFARENUM'){
|
||||
return '免费次数';
|
||||
}else if(raw=='wx'){
|
||||
return '微信支付';
|
||||
}
|
||||
};
|
||||
|
||||
const fetchCoursewareDetail = async () => {
|
||||
if (!coursewareId.value) return;
|
||||
try {
|
||||
const res = await api.getGanDanFileOrder({
|
||||
order_id: coursewareId.value,
|
||||
});
|
||||
if (res.code !== 200 || !res.data) return;
|
||||
|
||||
const data = res.data;
|
||||
detail.value = {
|
||||
downloadNo: data.order_id || data.download_no || data.gandanfile_order_id || data.id || "",
|
||||
statusText: formatStatus(data.order_status || data.status || data.pay_status || ""),
|
||||
title: data.title || data.name || data.file_name || "",
|
||||
author: data.provider_name || data.author || data.nickname || "",
|
||||
amountText: formatAmount(data.pay_amount || data.total_fee || data.amount || data.price || 0),
|
||||
createTime: formatDateTime(data.create_date || data.create_time || data.order_time || ""),
|
||||
payType: formatPayType(data.pay_channel),
|
||||
payTime: formatDateTime(data.pay_date || data.pay_time || ""),
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
uni.showToast({
|
||||
title: "获取详情失败",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
coursewareId.value = options.id;
|
||||
fetchCoursewareDetail();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.detail-page {
|
||||
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
background: #fff;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right:0;
|
||||
z-index: 10;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.order-top {
|
||||
min-height: 88rpx;
|
||||
padding: 0 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.download-no {
|
||||
font-size: 30rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.pay-status {
|
||||
font-size: 32rpx;
|
||||
color: #8b2316;
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
height: 16rpx;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.course-title {
|
||||
padding: 20rpx 30rpx;
|
||||
color: #8b2316;
|
||||
font-size: 32rpx;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
border-bottom: 2rpx solid #ccc;
|
||||
}
|
||||
|
||||
.info-list {
|
||||
padding: 24rpx 30rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
min-height: 56rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 30rpx;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
max-width: 68%;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.amount {
|
||||
color:red;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<!-- <navBar title="我的课件" /> -->
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的课件"
|
||||
@clickLeft="goBack"
|
||||
color="#8B2316"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
/>
|
||||
</view>
|
||||
<view class="my-courseware-page">
|
||||
<!-- 顶部导航栏 -->
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的课件"
|
||||
@cviewckLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
|
||||
</uni-nav-bar>
|
||||
|
||||
<!-- 标签页导航 -->
|
||||
<view class="tab-nav">
|
||||
@@ -37,11 +37,11 @@
|
||||
<view class="summary-bar">
|
||||
<view class="summary-item">
|
||||
<up-image :src="downLoadImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="summary-text">{{ activeTab === 'download' ? '下载账户' : '分享账户' }}: {{ downloadCount }}</text>
|
||||
<text class="summary-text">{{ totalAmount}}</text>
|
||||
</view>
|
||||
<view class="summary-item">
|
||||
<up-image :src="moneyImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="summary-text">{{ activeTab === 'download' ? '文件数量' : '分享文件' }}: {{ totalAmount }}</text>
|
||||
<text class="summary-text">{{ downloadCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -49,12 +49,15 @@
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="courseware-list"
|
||||
:scroll-top="listScrollTop"
|
||||
:scroll-into-view="scrollIntoViewId"
|
||||
refresher-enabled
|
||||
@refresherrefresh="onRefresh"
|
||||
:refresher-triggered="refreshing"
|
||||
@scrolltolower="onLoadMore"
|
||||
:lower-threshold="100"
|
||||
>
|
||||
<view id="courseware-top"></view>
|
||||
<!-- 空状态 -->
|
||||
<view v-if="coursewareList.length === 0 && !loading" class="empty-state">
|
||||
<text>{{ activeTab === 'download' ? '暂无下载数据' : '暂无分享数据' }}</text>
|
||||
@@ -62,21 +65,22 @@
|
||||
|
||||
<view class="courseware-item" v-for="(item, index) in coursewareList" :key="index" @click="onItemClick(item)">
|
||||
<view class="item-content">
|
||||
<view class="courseware-provider" v-if="activeTab === 'share'">
|
||||
<text class="label">下载医生</text>
|
||||
<text class="value">:{{ item.providername }}</text>
|
||||
</view>
|
||||
<view class="courseware-name">
|
||||
<text class="label">课件名称:</text>
|
||||
<text class="value">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="courseware-provider" v-if="item.providername">
|
||||
<text class="label">{{ activeTab === 'download' ? '提供者' : '下载者' }}:</text>
|
||||
<text class="value">{{ item.providername }}</text>
|
||||
<text class="label">课件名称</text>
|
||||
<text class="value">:{{ item.name }}</text>
|
||||
</view>
|
||||
|
||||
<view class="courseware-time">
|
||||
<text class="label">时间:</text>
|
||||
<text class="value">{{ item.time }}</text>
|
||||
<text class="label">时间</text>
|
||||
<text class="value">:{{ item.time }}</text>
|
||||
</view>
|
||||
<view class="courseware-status">
|
||||
<text class="label">状态:</text>
|
||||
<text class="value status-paid">{{ item.status }}</text>
|
||||
<view class="courseware-status" v-if="activeTab === 'download'">
|
||||
<text class="label">状态</text>
|
||||
<text class="value status-paid">:{{item.status}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -95,31 +99,76 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, nextTick } from 'vue';
|
||||
import api from '@/api/api';
|
||||
import navTo from '@/utils/navTo.js';
|
||||
import { onLoad,onBackPress } from '@dcloudio/uni-app';
|
||||
import downLoadImg from "@/static/course_download.png"
|
||||
import moneyImg from "@/static/course_yuan.png"
|
||||
const activeTab = ref('download');
|
||||
const listScrollTop = ref(0);
|
||||
const scrollIntoViewId = ref('');
|
||||
const refreshing = ref(false);
|
||||
const loading = ref(false);
|
||||
const noMore = ref(false);
|
||||
const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const downloadCount = ref(4);
|
||||
const totalAmount = ref('20.00');
|
||||
const downloadCount = ref(0);
|
||||
const totalAmount = ref(0);
|
||||
|
||||
const coursewareList = ref([]);
|
||||
|
||||
const from = ref('');
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "我的课件",
|
||||
},
|
||||
});
|
||||
});
|
||||
onMounted(() => {
|
||||
onRefresh();
|
||||
});
|
||||
|
||||
const getStatusText = (status) => {
|
||||
console.log(status);
|
||||
if(status === 'paid'){
|
||||
return '已支付';
|
||||
}else if(status === 'unpaid'){
|
||||
return '未支付';
|
||||
}else{
|
||||
return '已分享';
|
||||
}
|
||||
};
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
//from.value = options.from;
|
||||
switchTab('share')
|
||||
}
|
||||
})
|
||||
const switchTab = (tab) => {
|
||||
activeTab.value = tab;
|
||||
listScrollTop.value = 0;
|
||||
scrollIntoViewId.value = '';
|
||||
nextTick(() => {
|
||||
scrollIntoViewId.value = 'courseware-top';
|
||||
});
|
||||
// 切换标签时重置数据
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
@@ -132,37 +181,10 @@ const onItemClick = (item) => {
|
||||
console.log('点击课件:', item);
|
||||
|
||||
if (activeTab.value === 'download') {
|
||||
// 下载标签页的处理逻辑
|
||||
if (item.download_path) {
|
||||
uni.downloadFile({
|
||||
url: item.download_path,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
uni.openDocument({
|
||||
filePath: res.tempFilePath,
|
||||
success: () => {
|
||||
console.log('打开文档成功');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('打开文档失败:', err);
|
||||
uni.showToast({ title: '无法打开此文件', icon: 'none' });
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('下载失败:', err);
|
||||
uni.showToast({ title: '下载失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.showToast({ title: `点击了下载课件: ${item.name}`, icon: 'none' });
|
||||
}
|
||||
} else {
|
||||
// 分享标签页的处理逻辑
|
||||
uni.showToast({ title: `点击了分享课件: ${item.name}`, icon: 'none' });
|
||||
// 这里可以添加分享相关的操作,比如查看分享详情、重新分享等
|
||||
}
|
||||
navTo({
|
||||
url: `/pages_app/myCourseware/coursewareDetail?id=${item.order_id}`
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = () => {
|
||||
@@ -175,7 +197,7 @@ const onRefresh = () => {
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 更新摘要信息
|
||||
downloadCount.value = res.data.downloadTotalAccount || 0;
|
||||
downloadCount.value = (res.data.downloadTotalAccount/100).toFixed(2) || 0;
|
||||
totalAmount.value = res.data.downloadFileCount || 0;
|
||||
|
||||
// 处理课件列表数据
|
||||
@@ -186,7 +208,7 @@ const onRefresh = () => {
|
||||
uuid: item.uuid,
|
||||
order_id: item.order_id,
|
||||
type: item.type,
|
||||
providername: item.providername
|
||||
providername: item.downloadername
|
||||
}));
|
||||
|
||||
// 判断是否还有更多数据
|
||||
@@ -203,7 +225,7 @@ const onRefresh = () => {
|
||||
if (res.code === 200 && res.data) {
|
||||
const data = res.data.list;
|
||||
// 更新摘要信息 - 分享数据使用不同的字段
|
||||
downloadCount.value = res.data.shareTotalAccount || 0;
|
||||
downloadCount.value = (res.data.shareTotalAccount/100).toFixed(2) || 0;
|
||||
totalAmount.value = res.data.shareloadFileCount || 0;
|
||||
|
||||
// 处理分享列表数据
|
||||
@@ -305,7 +327,7 @@ const onLoadMore = () => {
|
||||
background: #ffffff;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
position: fixed;
|
||||
top: 140rpx;
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
@@ -332,20 +354,21 @@ const onLoadMore = () => {
|
||||
|
||||
.summary-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
align-items: center;
|
||||
background: #8B2316;
|
||||
padding: 20rpx 30rpx;
|
||||
position: fixed;
|
||||
top: 260rpx; // 标签页导航下方
|
||||
top: calc(var(--status-bar-height) + 44px + 124rpx); // 标签页导航下方
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
|
||||
.summary-item {
|
||||
flex:1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
justify-content: flex-start;
|
||||
.summary-text {
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
@@ -355,9 +378,9 @@ const onLoadMore = () => {
|
||||
}
|
||||
|
||||
.courseware-list {
|
||||
height: calc(100vh - 140rpx - 116rpx - 80rpx);
|
||||
// height: calc(100vh - 180rpx - 116rpx - 80rpx);
|
||||
position: fixed;
|
||||
top: 336rpx; // 调整顶部位置,为固定的摘要栏腾出空间
|
||||
top: calc(var(--status-bar-height) + 44px + 124rpx + 80rpx); // 调整顶部位置,为固定的摘要栏腾出空间
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -383,6 +406,15 @@ const onLoadMore = () => {
|
||||
width: 120rpx;
|
||||
color: #8B2316;
|
||||
font-size: 28rpx;
|
||||
display: inline-block;
|
||||
text-align: justify;
|
||||
text-align-last: justify;
|
||||
text-justify: inter-ideograph;
|
||||
}
|
||||
.label::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.value {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@clickLeft="goBack()"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
height="180rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
>
|
||||
|
||||
+263
-72
@@ -2,33 +2,38 @@
|
||||
|
||||
<view class="flower-page">
|
||||
<!-- 顶部统计栏(与截图一致:两项) -->
|
||||
<uni-nav-bar
|
||||
<view class="navbox">
|
||||
<view class="status_bar"></view>
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的鲜花"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="stats-bar">
|
||||
<view class="stat">
|
||||
<up-image :src="flowerImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="num">{{ stat.totalCount }}</text>
|
||||
<view class="fixed-top-block">
|
||||
<view class="stats-bar">
|
||||
<view class="stat">
|
||||
<up-image :src="flowerImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="num">{{ stat.totalCount }}</text>
|
||||
</view>
|
||||
<view class="stat">
|
||||
<up-image :src="moneyImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="num">{{ stat.totalAmount.toFixed(2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="stat">
|
||||
<up-image :src="moneyImg" width="36rpx" height="36rpx" ></up-image>
|
||||
<text class="num">{{ stat.totalAmount.toFixed(2) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表头条(红底白字) -->
|
||||
<view class="table-header">
|
||||
<text class="col name">姓名</text>
|
||||
<text class="col time">时间</text>
|
||||
<text class="col qty">数量</text>
|
||||
<!-- 表头条(红底白字) -->
|
||||
<view class="table-header">
|
||||
<text class="col name">姓名</text>
|
||||
<text class="col time">时间</text>
|
||||
<text class="col qty">数量</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表体/列表或空状态 -->
|
||||
@@ -43,37 +48,62 @@
|
||||
lower-threshold="100"
|
||||
:scroll-top="scrollTop"
|
||||
>
|
||||
<view v-if="records.length === 0" class="empty-wrap">
|
||||
<up-image :src="emptyImg" width="176rpx" height="204rpx" ></up-image>
|
||||
<text class="empty-text">您暂未收到鲜花</text>
|
||||
</view>
|
||||
<view class="list-content">
|
||||
<view v-if="records.length === 0" class="empty-wrap">
|
||||
<up-image :src="emptyImg" width="176rpx" height="204rpx" ></up-image>
|
||||
<text class="empty-text">您暂未收到鲜花</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="row" v-for="(item, idx) in records" :key="idx">
|
||||
<text class="cell name">{{ item.name }}</text>
|
||||
<text class="cell time">{{ item.time }}</text>
|
||||
<text class="cell qty" :class="{ plus: item.amount > 0, minus: item.amount < 0 }">{{ item.amount }}</text>
|
||||
</view>
|
||||
<view v-else class="row" v-for="(item, idx) in records" :key="idx">
|
||||
<text class="cell name">{{ item.name }}</text>
|
||||
<text class="cell time">{{ item.time }}</text>
|
||||
<text class="cell qty" :class="{ plus: item.amount > 0, minus: item.amount < 0 }">{{ item.amount }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="loading">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<view v-if="noMore && records.length > 0" class="no-more">
|
||||
<text>没有更多数据了</text>
|
||||
</view>
|
||||
<view class="debug-actions">
|
||||
<!-- <button @click="testLoadMore" size="mini" type="primary">测试加载更多</button>
|
||||
<text class="debug-info">当前页: {{ page }}, 加载中: {{ loading }}, 无更多: {{ noMore }}</text> -->
|
||||
<view v-if="loading" class="loading">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
<view v-if="noMore && records.length > 0" class="no-more">
|
||||
<text>没有更多数据了</text>
|
||||
</view>
|
||||
<!-- <view class="debug-actions">
|
||||
<button @click="testLoadMore" size="mini" type="primary">测试加载更多</button>
|
||||
<text class="debug-info">当前页: {{ page }}, 加载中: {{ loading }}, 无更多: {{ noMore }}</text>
|
||||
</view> -->
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, nextTick } from 'vue';
|
||||
import flowerImg from "@/static/flowers.png"
|
||||
import moneyImg from "@/static/mind_totle_money.png"
|
||||
import emptyImg from "@/static/icon_empty.png"
|
||||
import api from '@/api/api.js';
|
||||
import { onBackPress,onLoad } from '@dcloudio/uni-app';
|
||||
const from=ref('');
|
||||
const user_uuid=ref('');
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
let userInfo= uni.getStorageSync('userInfo')
|
||||
user_uuid.value = userInfo.uuid;
|
||||
loadFirstTwoPages();
|
||||
uni.sendNativeEvent("portraitReport",{
|
||||
msg:{
|
||||
event_nickname: "list_page",
|
||||
page_type: "我的鲜花",
|
||||
},
|
||||
});
|
||||
});
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 与截图一致的顶部两项统计:总鲜花数与累计金额
|
||||
const stat = ref({ totalCount: 0, totalAmount: 0.0 });
|
||||
|
||||
@@ -87,19 +117,44 @@ const noMore = ref(false);
|
||||
const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const scrollTop = ref(0);
|
||||
const autoLoading = ref(false);
|
||||
|
||||
const formatDateToYDM = (value) => {
|
||||
if (!value) return '-';
|
||||
const raw = String(value).trim();
|
||||
const directMatch = raw.match(/^(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})/);
|
||||
if (directMatch) {
|
||||
const [, year, month, day] = directMatch;
|
||||
return `${year}-${day.padStart(2, '0')}-${month.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
const parsedDate = new Date(raw);
|
||||
if (Number.isNaN(parsedDate.getTime())) return '-';
|
||||
|
||||
const year = parsedDate.getFullYear();
|
||||
const month = String(parsedDate.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(parsedDate.getDate()).padStart(2, '0');
|
||||
return `${year}-${day}-${month}`;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack({
|
||||
fail() {
|
||||
uni.redirectTo({ url: '/pages/index/index' });
|
||||
}
|
||||
});
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
};
|
||||
|
||||
const getFlowerList = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('[myFlower] getFlowerList:start', {
|
||||
page: page.value,
|
||||
loading: loading.value,
|
||||
refreshing: refreshing.value,
|
||||
noMore: noMore.value
|
||||
});
|
||||
// 只在第一页时设置loading状态,避免与onLoadMore冲突
|
||||
if (page.value === 1) {
|
||||
loading.value = true;
|
||||
@@ -107,20 +162,30 @@ const getFlowerList = () => {
|
||||
|
||||
console.log('正在获取第', page.value, '页数据...');
|
||||
|
||||
api.getFlowerList({page: page.value}).then(res => {
|
||||
api.getFlowerList({
|
||||
page: page.value,
|
||||
user_uuid: user_uuid.value,
|
||||
}).then(res => {
|
||||
console.log('接口返回数据:', res);
|
||||
if (res.code === 200 && res.data) {
|
||||
const { flower_data, total_amount, total_num } = res.data;
|
||||
console.log('[myFlower] getFlowerList:response', {
|
||||
reqPage: page.value,
|
||||
pageNum: flower_data?.pageNum,
|
||||
pages: flower_data?.pages,
|
||||
isLastPage: flower_data?.isLastPage,
|
||||
listLength: flower_data?.list?.length || 0
|
||||
});
|
||||
|
||||
// 更新统计数据
|
||||
stat.value.totalCount = total_num || 0;
|
||||
stat.value.totalAmount = total_amount || 0;
|
||||
|
||||
// 处理列表数据
|
||||
if (flower_data && flower_data.list) {
|
||||
if (flower_data && Array.isArray(flower_data.list)) {
|
||||
const newRecords = flower_data.list.map(item => ({
|
||||
name: item.patient_name || '未知',
|
||||
time: item.create_date || '',
|
||||
name: item.patient_name || '账号已注销',
|
||||
time: formatDateToYDM(item.create_date),
|
||||
amount: item.num || 0,
|
||||
// 保留原始数据以备后用
|
||||
original: item
|
||||
@@ -135,12 +200,28 @@ const getFlowerList = () => {
|
||||
console.log('第', page.value, '页数据,追加到列表,新增', newRecords.length, '条');
|
||||
}
|
||||
|
||||
// 判断是否还有更多数据
|
||||
noMore.value = flower_data.isLastPage;
|
||||
console.log('是否最后一页:', flower_data.isLastPage, ',总页数:', flower_data.pages);
|
||||
// 判断是否还有更多数据,兼容不同接口字段
|
||||
if (typeof flower_data.isLastPage === 'boolean') {
|
||||
noMore.value = flower_data.isLastPage;
|
||||
} else if (Number(flower_data.pages) > 0) {
|
||||
noMore.value = page.value >= Number(flower_data.pages);
|
||||
} else {
|
||||
// 未返回分页字段时,仅在本页无数据时判定到底
|
||||
noMore.value = newRecords.length === 0;
|
||||
}
|
||||
console.log('是否最后一页:', noMore.value, ',总页数:', flower_data.pages);
|
||||
}
|
||||
console.log('[myFlower] getFlowerList:end', {
|
||||
page: page.value,
|
||||
records: records.value.length,
|
||||
noMore: noMore.value
|
||||
});
|
||||
resolve(res);
|
||||
} else {
|
||||
console.log('[myFlower] getFlowerList:invalid', {
|
||||
code: res?.code,
|
||||
msg: res?.msg
|
||||
});
|
||||
reject(new Error('接口返回错误'));
|
||||
}
|
||||
}).catch(err => {
|
||||
@@ -156,18 +237,11 @@ const getFlowerList = () => {
|
||||
});
|
||||
});
|
||||
};
|
||||
onMounted(() => {
|
||||
getFlowerList();
|
||||
});
|
||||
|
||||
const onRefresh = async () => {
|
||||
if (refreshing.value) return;
|
||||
if (refreshing.value || loading.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
records.value = []; // 清空数据
|
||||
getFlowerList(); // 重新获取第一页数据
|
||||
await loadFirstTwoPages();
|
||||
uni.showToast({ title: '刷新成功', icon: 'none' });
|
||||
} catch (error) {
|
||||
console.error('刷新失败:', error);
|
||||
@@ -177,39 +251,136 @@ const onRefresh = async () => {
|
||||
|
||||
const onLoadMore = async () => {
|
||||
console.log('触发上拉加载更多事件');
|
||||
console.log('[myFlower] onLoadMore:enter', {
|
||||
page: page.value,
|
||||
loading: loading.value,
|
||||
refreshing: refreshing.value,
|
||||
noMore: noMore.value
|
||||
});
|
||||
|
||||
// 检查各种状态
|
||||
if (loading.value) {
|
||||
if (loading.value || refreshing.value) {
|
||||
console.log('正在加载中,忽略重复请求');
|
||||
console.log('[myFlower] onLoadMore:blockByState');
|
||||
return;
|
||||
}
|
||||
|
||||
if (noMore.value) {
|
||||
console.log('已经没有更多数据了');
|
||||
console.log('[myFlower] onLoadMore:blockByNoMore');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('开始加载下一页,当前页码:', page.value);
|
||||
|
||||
loading.value = true;
|
||||
const currentPage = page.value;
|
||||
try {
|
||||
page.value += 1;
|
||||
page.value = currentPage + 1;
|
||||
console.log('[myFlower] onLoadMore:request', {
|
||||
fromPage: currentPage,
|
||||
toPage: page.value
|
||||
});
|
||||
await getFlowerList(); // 等待数据加载完成
|
||||
console.log('加载完成,当前页码:', page.value);
|
||||
console.log('[myFlower] onLoadMore:done', {
|
||||
page: page.value,
|
||||
records: records.value.length,
|
||||
noMore: noMore.value
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('加载更多失败:', error);
|
||||
page.value -= 1; // 恢复页码
|
||||
page.value = currentPage; // 恢复页码
|
||||
console.log('[myFlower] onLoadMore:rollback', { page: page.value });
|
||||
uni.showToast({ title: '加载失败', icon: 'error' });
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const getListLayoutInfo = () => {
|
||||
return new Promise((resolve) => {
|
||||
const query = uni.createSelectorQuery();
|
||||
query.select('.table-body').boundingClientRect();
|
||||
query.select('.list-content').boundingClientRect();
|
||||
query.exec((res = []) => {
|
||||
const bodyHeight = Number(res?.[0]?.height || 0);
|
||||
const contentHeight = Number(res?.[1]?.height || 0);
|
||||
resolve({ bodyHeight, contentHeight });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const ensureListCanScroll = async () => {
|
||||
if (autoLoading.value || loading.value || refreshing.value || noMore.value) return;
|
||||
autoLoading.value = true;
|
||||
try {
|
||||
while (!noMore.value) {
|
||||
await nextTick();
|
||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||
const { bodyHeight, contentHeight } = await getListLayoutInfo();
|
||||
if (!bodyHeight || !contentHeight) break;
|
||||
if (contentHeight > bodyHeight) break;
|
||||
await onLoadMore();
|
||||
if (loading.value) break;
|
||||
}
|
||||
} finally {
|
||||
autoLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const loadFirstTwoPages = async () => {
|
||||
console.log('[myFlower] loadFirstTwoPages:start');
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
records.value = [];
|
||||
console.log('[myFlower] loadFirstTwoPages:reset', {
|
||||
page: page.value,
|
||||
records: records.value.length,
|
||||
noMore: noMore.value
|
||||
});
|
||||
await getFlowerList();
|
||||
// 第1页 Promise resolve 早于 finally 复位 loading,这里手动兜底复位
|
||||
loading.value = false;
|
||||
console.log('[myFlower] loadFirstTwoPages:afterPage1', {
|
||||
page: page.value,
|
||||
records: records.value.length,
|
||||
noMore: noMore.value
|
||||
});
|
||||
if (!noMore.value) {
|
||||
console.log('[myFlower] loadFirstTwoPages:triggerPage2');
|
||||
const firstPage = page.value;
|
||||
try {
|
||||
page.value = firstPage + 1;
|
||||
console.log('[myFlower] loadFirstTwoPages:requestPage2', {
|
||||
fromPage: firstPage,
|
||||
toPage: page.value,
|
||||
refreshing: refreshing.value
|
||||
});
|
||||
await getFlowerList();
|
||||
loading.value = false;
|
||||
} catch (error) {
|
||||
page.value = firstPage;
|
||||
console.log('[myFlower] loadFirstTwoPages:page2FailedRollback', { page: page.value });
|
||||
throw error;
|
||||
}
|
||||
} else {
|
||||
console.log('[myFlower] loadFirstTwoPages:skipPage2(noMore=true)');
|
||||
}
|
||||
console.log('[myFlower] loadFirstTwoPages:end', {
|
||||
page: page.value,
|
||||
records: records.value.length,
|
||||
noMore: noMore.value
|
||||
});
|
||||
};
|
||||
|
||||
// 测试加载更多功能
|
||||
const testLoadMore = () => {
|
||||
console.log('手动测试加载更多');
|
||||
onLoadMore();
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -221,13 +392,27 @@ $card: #ffffff;
|
||||
|
||||
.flower-page {
|
||||
background: $bg;
|
||||
--nav-offset: calc(var(--status-bar-height) + 44px);
|
||||
--stats-height: 86rpx;
|
||||
--header-height: 74rpx;
|
||||
/* 导航栏下方固定区域总高度:统计栏 + 表头 */
|
||||
--fixed-block-height: calc(var(--stats-height) + var(--header-height));
|
||||
}
|
||||
|
||||
.fixed-top-block {
|
||||
position: fixed;
|
||||
top: var(--nav-offset);
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.stats-bar {
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
padding: 24rpx 30rpx;
|
||||
height: var(--stats-height);
|
||||
padding: 0 30rpx;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
border-bottom: 2rpx solid #eee;
|
||||
|
||||
@@ -244,20 +429,25 @@ $card: #ffffff;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 22rpx 30rpx;
|
||||
align-items: center;
|
||||
height: var(--header-height);
|
||||
padding: 0 30rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 30rpx;
|
||||
position: sticky;
|
||||
top: 140rpx; /* nav 高度 */
|
||||
z-index: 5;
|
||||
|
||||
.col { width: 33%; }
|
||||
.name { text-align: left; }
|
||||
.time { text-align: center; }
|
||||
.qty { text-align: right; }
|
||||
.qty { text-align: center; }
|
||||
}
|
||||
|
||||
.table-body {
|
||||
height: calc(100vh - 140rpx - 88rpx - 70rpx);
|
||||
position: fixed;
|
||||
top: calc(var(--nav-offset) + var(--fixed-block-height));
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
box-sizing: border-box;
|
||||
/* 充满剩余高度,避免滚动穿透 */
|
||||
}
|
||||
|
||||
@@ -266,16 +456,17 @@ $card: #ffffff;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 26rpx 30rpx;
|
||||
border-bottom: 2rpx solid #f2f2f2;
|
||||
background: #fff;
|
||||
border-bottom: 2rpx solid #ccc;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
.cell { width: 33%; }
|
||||
.name { text-align: left; }
|
||||
.time { text-align: center; color: #666; }
|
||||
.qty { text-align: right; }
|
||||
.qty.plus { color: #2dbd85; }
|
||||
.qty.minus { color: #e34d4d; }
|
||||
.qty { text-align: center; }
|
||||
.qty.plus { color: #333; }
|
||||
.qty.minus { color: #333; }
|
||||
}
|
||||
|
||||
.empty-wrap { padding-top: 200rpx; display: flex; flex-direction: column; align-items: center; color: #bdbdbd; }
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">scroll-view 上拉加载 Demo</text>
|
||||
<text class="sub">下拉刷新 + 触底加载更多</text>
|
||||
</view>
|
||||
|
||||
<scroll-view
|
||||
class="list-scroll"
|
||||
scroll-y
|
||||
lower-threshold="80"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="onRefresh"
|
||||
@scrolltolower="onLoadMore"
|
||||
>
|
||||
<view v-for="item in list" :key="item.id" class="list-item">
|
||||
<text class="item-title">{{ item.title }}</text>
|
||||
<text class="item-time">{{ item.time }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="loading" class="tip">加载中...</view>
|
||||
<view v-else-if="noMore && list.length > 0" class="tip">没有更多数据了</view>
|
||||
<view v-else-if="list.length === 0" class="tip">暂无数据</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
const page = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const list = ref([]);
|
||||
const loading = ref(false);
|
||||
const refreshing = ref(false);
|
||||
const noMore = ref(false);
|
||||
|
||||
const totalMockCount = 37;
|
||||
const fullData = Array.from({ length: totalMockCount }, (_, i) => {
|
||||
const index = i + 1;
|
||||
return {
|
||||
id: index,
|
||||
title: `第 ${index} 条数据`,
|
||||
time: `2026-03-${String((index % 28) + 1).padStart(2, '0')}`
|
||||
};
|
||||
});
|
||||
|
||||
const getPageData = (pageNum, size) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const start = (pageNum - 1) * size;
|
||||
const end = start + size;
|
||||
resolve(fullData.slice(start, end));
|
||||
}, 350);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchList = async (isRefresh = false) => {
|
||||
if (loading.value) return;
|
||||
loading.value = true;
|
||||
try {
|
||||
if (isRefresh) {
|
||||
page.value = 1;
|
||||
noMore.value = false;
|
||||
}
|
||||
const rows = await getPageData(page.value, pageSize.value);
|
||||
if (isRefresh) {
|
||||
list.value = rows;
|
||||
} else {
|
||||
list.value = [...list.value, ...rows];
|
||||
}
|
||||
noMore.value = rows.length < pageSize.value;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
refreshing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = async () => {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
await fetchList(true);
|
||||
};
|
||||
|
||||
const onLoadMore = async () => {
|
||||
if (loading.value || refreshing.value || noMore.value) return;
|
||||
page.value += 1;
|
||||
await fetchList(false);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchList(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
height: 100vh;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 30rpx;
|
||||
background: #ffffff;
|
||||
border-bottom: 1rpx solid #ededed;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: block;
|
||||
font-size: 34rpx;
|
||||
color: #222;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.sub {
|
||||
display: block;
|
||||
margin-top: 8rpx;
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.list-scroll {
|
||||
height: calc(100vh - 130rpx);
|
||||
}
|
||||
|
||||
.list-item {
|
||||
margin: 20rpx 24rpx 0;
|
||||
padding: 24rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.item-time {
|
||||
display: block;
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.tip {
|
||||
padding: 28rpx 0 40rpx;
|
||||
text-align: center;
|
||||
color: #9aa0a6;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,24 +1,11 @@
|
||||
<template>
|
||||
|
||||
<navBar :title="'新的患者'" />
|
||||
<view class="new-patient-page">
|
||||
|
||||
|
||||
<uni-nav-bar
|
||||
left-icon="left"
|
||||
title="我的患者"
|
||||
@clickLeft="goBack"
|
||||
fixed
|
||||
color="#8B2316"
|
||||
height="140rpx"
|
||||
:border="false"
|
||||
backgroundColor="#eeeeee"
|
||||
/>
|
||||
|
||||
|
||||
<!-- 提醒区域 -->
|
||||
<view class="reminder-section">
|
||||
<view class="contentbox">
|
||||
<view class="reminder-section">
|
||||
<view class="reminder-icon">
|
||||
<uni-icons type="notification" size="16" color="#ff9500"></uni-icons>
|
||||
<up-image :src="tipImg" width="35rpx" height="42rpx"></up-image>
|
||||
</view>
|
||||
<text class="reminder-text">提醒: 为了避免不必要的纠纷,请您务必选择线下就诊过的患者</text>
|
||||
</view>
|
||||
@@ -29,15 +16,15 @@
|
||||
<view class="pending-request" v-for="(item, index) in applyList" :key="index">
|
||||
<view class="request-item">
|
||||
<view class="avatar">
|
||||
<up-image :src="docUrl+item.photo" radius="10rpx" width="80rpx" height="80rpx" ></up-image>
|
||||
<up-image :src="docUrl+item.photo" radius="10rpx" width="120rpx" height="120rpx" ></up-image>
|
||||
</view>
|
||||
<view class="request-content">
|
||||
<view class="request-time">{{ item.createDate }}</view>
|
||||
<view class="request-text">{{ item.content }}</view>
|
||||
|
||||
<view class="action-buttons">
|
||||
<button class="reject-btn" @click="applyListOperate(item.uuid,3)">拒绝</button>
|
||||
<button class="agree-btn" @click="applyListOperate(item.uuid,2)">同意</button>
|
||||
<button class="reject-btn" @click="applyListOperate(item.uuid,3,item.content,item.patientUuid)">拒绝</button>
|
||||
<button class="agree-btn" @click="applyListOperate(item.uuid,2,item.content,item.patientUuid)">同意</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -48,14 +35,14 @@
|
||||
<view class="history-section" v-if="historyList.length > 0">
|
||||
<view class="section-title">申请记录(近一月)</view>
|
||||
<view class="history-list">
|
||||
<view class="history-item" v-for="(item, index) in historyList" :key="index">
|
||||
<view class="history-item" v-for="(item, index) in historyList" :key="index" @click="goPatientDetail(item.patient_uuid,item.status)">
|
||||
<view class="avatar">
|
||||
<up-image v-if="docUrl+item.patient_photo" :src="docUrl + item.patient_photo" radius="10rpx" width="80rpx" height="80rpx"></up-image>
|
||||
<up-image v-if="docUrl+item.patient_photo" :src="docUrl + item.patient_photo" radius="10rpx" width="120rpx" height="120rpx"></up-image>
|
||||
|
||||
</view>
|
||||
<view class="history-content">
|
||||
<view class="history-time">{{ formatDate(item.createDate) }}</view>
|
||||
<view class="nickname">{{ item.nickname || item.patient_name }}</view>
|
||||
<view class="history-time">{{ formatDate2(item.create_date) }}</view>
|
||||
<view class="nickname">昵称:{{ item.patient_name || item.nickname }}</view>
|
||||
<view class="history-text">{{ item.content}}</view>
|
||||
<view class="status-info">
|
||||
<up-image :src="goImg" width="30rpx" height="30rpx" v-if="item.status==2"></up-image>
|
||||
@@ -65,7 +52,10 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<empty v-if="applyList.length == 0 && historyList.length == 0" :emptyDesc="'暂无新随访申请患者'" />
|
||||
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<view class="bottom-button">
|
||||
<button class="add-patient-btn" @click="addPatient">加患者</button>
|
||||
@@ -75,11 +65,27 @@
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onLoad,onShow} from '@dcloudio/uni-app';
|
||||
import { onLoad,onShow,onBackPress} from '@dcloudio/uni-app';
|
||||
import goImg from "@/static/go_big.png"
|
||||
import api from '@/api/api.js'
|
||||
import docUrl from "@/utils/docUrl"
|
||||
import dayjs from 'dayjs'
|
||||
import navTo from "@/utils/navTo.js"
|
||||
import empty from "@/components/empty/empty.vue"
|
||||
import navBar from "@/components/navBar/navBar.vue"
|
||||
import tipImg from "@/static/sendgroup_tishi_big.png"
|
||||
const from=ref('');
|
||||
onLoad((options) => {
|
||||
if(options.from){
|
||||
from.value = options.from;
|
||||
}
|
||||
});
|
||||
onBackPress(() => {
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
// 响应式数据
|
||||
const pendingRequest = ref({
|
||||
name: '陈新华',
|
||||
@@ -91,7 +97,11 @@ const historyList = ref([]);
|
||||
|
||||
// 方法
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
if(!from.value){
|
||||
plus.runtime.quit();
|
||||
}else{
|
||||
uni.navigateBack();
|
||||
}
|
||||
};
|
||||
|
||||
const rejectRequest = () => {
|
||||
@@ -162,20 +172,27 @@ const getApplyList = async () => { // 申请列表
|
||||
});
|
||||
}
|
||||
};
|
||||
const applyListOperate = async (uuid,status) => {
|
||||
const applyListOperate = async (uuid,status,content,patientUuid) => {
|
||||
let data = {
|
||||
uuid: uuid,
|
||||
status: status
|
||||
}
|
||||
const res = await api.applyListOperate(data);
|
||||
if(res.code === 200){
|
||||
|
||||
uni.showToast({
|
||||
title: '操作成功',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
});
|
||||
let nickname = content.split(',')[0].replace('我是', '');
|
||||
getApplyList();
|
||||
getRelationRecordLately();
|
||||
if(status == 2){
|
||||
navTo({
|
||||
url: `/pages_app/patientRemark/patientRemark?uuid=${patientUuid}&&nickname=${nickname}`
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
onShow(() => {
|
||||
@@ -184,6 +201,15 @@ const getApplyList = async () => { // 申请列表
|
||||
|
||||
});
|
||||
|
||||
const goPatientDetail = (uuid,status) => {
|
||||
|
||||
if(status == 2){
|
||||
navTo({
|
||||
url: `/pages_app/patientDetail/patientDetail?uuid=${uuid}&from=myPatient`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
@@ -196,6 +222,9 @@ const formatDate = (dateString) => {
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
};
|
||||
const formatDate2 = (dateString) => {
|
||||
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
@@ -208,7 +237,7 @@ const getStatusText = (status) => {
|
||||
|
||||
const addPatient = () => {
|
||||
navTo({
|
||||
url:'/pages_app/myCode/myCode'
|
||||
url:'/pages_app/myCode/myCode?from=myPatient'
|
||||
});
|
||||
// 这里可以跳转到添加患者页面
|
||||
};
|
||||
@@ -216,7 +245,7 @@ const addPatient = () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.new-patient-page {
|
||||
min-height: 100vh;
|
||||
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
@@ -311,34 +340,47 @@ const addPatient = () => {
|
||||
margin-right: 60rpx; // 为了保持标题居中
|
||||
}
|
||||
}
|
||||
|
||||
.contentbox{
|
||||
top: calc(var(--status-bar-height) + 44px);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 100rpx;
|
||||
overflow-y: scroll;
|
||||
z-index: 1;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.reminder-section {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
align-items:center;
|
||||
padding: 30rpx;
|
||||
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
|
||||
.reminder-icon {
|
||||
width: 35rpx;
|
||||
height: 42rpx;
|
||||
margin-right: 20rpx;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.reminder-text {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.follow-up-section {
|
||||
background-color: #ffffff;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
|
||||
.section-title {
|
||||
padding: 30rpx 30rpx 20rpx;
|
||||
padding: 30rpx 30rpx 30rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #f0f0f0;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
@@ -349,11 +391,12 @@ const addPatient = () => {
|
||||
|
||||
.request-item {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
|
||||
|
||||
.avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-top: 30rpx;
|
||||
background-color: #ffb6c1;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
@@ -361,8 +404,8 @@ const addPatient = () => {
|
||||
justify-content: center;
|
||||
|
||||
.avatar-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
background-color: #ffffff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
@@ -370,7 +413,7 @@ const addPatient = () => {
|
||||
|
||||
.request-content {
|
||||
flex: 1;
|
||||
|
||||
margin-left: 20rpx;
|
||||
.request-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
@@ -432,18 +475,19 @@ const addPatient = () => {
|
||||
margin-bottom: 120rpx; // 为底部按钮留出空间
|
||||
|
||||
.section-title {
|
||||
padding: 30rpx 30rpx 20rpx;
|
||||
padding: 30rpx 30rpx 30rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: normal;
|
||||
background-color: #f0f0f0;
|
||||
color: #333;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.history-list {
|
||||
margin-bottom: 100rpx;
|
||||
margin-bottom: 30rpx;
|
||||
.history-item {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
@@ -452,8 +496,9 @@ const addPatient = () => {
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
margin-top: 30rpx;
|
||||
background-color: #ffb6c1;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
@@ -470,18 +515,24 @@ const addPatient = () => {
|
||||
|
||||
.history-content {
|
||||
flex: 1;
|
||||
|
||||
margin-left: 20rpx;
|
||||
min-width: 0;
|
||||
.nickname {
|
||||
font-size: 28rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: normal;
|
||||
color: #8B2316;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.history-text {
|
||||
font-size: 28rpx;
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
+1351
-995
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user