初始化

This commit is contained in:
JiXinHui 2025-06-30 14:43:02 +08:00
parent f9418c40b9
commit 631525e44e
659 changed files with 101005 additions and 0 deletions

434
App.vue Normal file
View File

@ -0,0 +1,434 @@
<script>
import router from "./static/common/js/router";
import config from "./static/common/js/config.js"
var jweixin = require("jweixin-module");
export default {
data() {
return {
show: false,
}
},
globalData: {},
created() {
},
onLaunch() {
if (typeof window.entryUrl === 'undefined' || window.entryUrl === '') {
window.entryUrl = location.href.split('#')[0]
}
router.initApp(this);
//
let isUrl = this._route.fullPath.split('?')[0]
let notNeed = config.whiteList.includes(isUrl)
if (notNeed) {
uni.navigateTo({
url: this._route.fullPath,
});
return
}
var that = this;
uni.getSystemInfo({
success: function (res) {
// model
if (res.model.indexOf("iPhone") >= 0) {
that.$u.vuex("vuex_iPhone", true);
}
},
});
if (!that.vuex_user.isFill) {
this.$u.vuex("vuex_msgList", "");
this.$u.vuex("vuex_user", "");
this.$u.vuex("vuex_token", "");
this.$u.vuex("vuex_userInfo", "");
uni.clearStorage();
this.$u.route({
url: "/pages/login/login/login",
});
return;
uni.navigateTo({
url: "/pages/login/roleSelection",
});
return
}
},
// onShow(){
// console.log('onShow')
// },
methods: {
getLocation() {
var that = this;
if (this.isWechat()) {
const isiOS = !!navigator.userAgent.match(
/\(i[^;]+;( U;)? CPU.+Mac OS X/
); //ios
// Android 使 ios
const signLink = isiOS
? window.entryUrl
: window.location.href.split("#")[0];
//url使
// const url =encodeURIComponent(signLink);
const url = signLink;
const data = {
url: url,
};
this.$u.api.GetInfoMation(data).then((res) => {
jweixin.config({
debug: false,
appId: res.appId,
timestamp: res.timestamp,
nonceStr: res.noncestr,
signature: res.signature,
jsApiList: [
//
"getLocation", //
"openLocation", //
],
});
// jweixin.config
jweixin.error((err) => {
uni.hideLoading();
console.log("授权失败,您可能无法使用部分功能", err);
});
jweixin.ready(function () {
jweixin.getLocation({
type: "gcj02", // wgs84gps openLocation'gcj02'
success: (res) => {
uni.hideLoading();
that.$u.vuex('vuex_userLocation', res)
var data = {
userId: that.vuex_user.id,
longitude: res.longitude + "",
latitude: res.latitude + "",
};
that.$u.api.upPosition(data)
},
fail: function (res) {
uni.hideLoading();
console.log(res, "err");
},
complete: function (res) {
uni.hideLoading();
console.log(res, "is");
},
});
});
});
} else {
uni.getLocation({
type: "gcj02 ",
isHighAccuracy: true,
highAccuracyExpireTime: 3000,
success: (res) => {
uni.hideLoading();
this.$u.vuex('vuex_userLocation', res)
var data = {
userId: this.vuex_user.id,
longitude: res.longitude + "",
latitude: res.latitude + "",
};
this.$u.api.upPosition(data)
},
fail: (err) => {
uni.hideLoading();
console.log("地理位置获取失败", err);
},
});
}
},
isWechat() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/micromessenger/i) == "micromessenger") {
// console.log()
return true;
} else {
// console.log()
return false;
}
},
charLink() {
var that = this;
(function start(ms) {
setTimeout(() => {
try {
that.$connection
.start()
.then(() => {
// console.log(that.$connection.connection.transport.webSocket._webSocket.url)
// that.connectionId = that.$connection.connection.transport.url.split(
// "=")[1]
that.connectionId = that.$connection.connection.transport.webSocket._webSocket.url.split(
"=")[1]
that.CharLogin()
})
.catch((e) => {
//
that.$connection.sto
console.log("websocket连接失败", e);
return start(5000);
});
} catch (e) {
//
return start(5000);
}
}, ms);
})(0)
//
this.$connection.on("ReceiveMessage", (user, message, type) => {
if (this._route.fullPath.indexOf('dialogBox') < 0) {
var tab = this.vuex_tabbar;
tab[1].isDot = true;
this.$u.vuex('vuex_tabbar', tab);
var msgList = this.vuex_tabbar
var msgList = this.vuex_msgList
//
if (type == 4) {
user = 'admin'
}
if (type == 3) {
user += 'user'
}
if (msgList.indexOf(user) < 0) {
msgList += (user + ',');
}
this.$u.vuex('vuex_msgList', msgList)
}
});
//
this.$connection.on("SystemMessage", (title, content, time) => {
if (this._route.fullPath.indexOf('sysList') < 0) {
var tab = this.vuex_tabbar;
tab[1].isDot = true;
this.$u.vuex('vuex_tabbar', tab);
var msgList = this.vuex_tabbar
var msgList = this.vuex_msgList
if (msgList.indexOf('SystemMessage') < 0) {
msgList += 'SystemMessage,';
}
this.$u.vuex('vuex_msgList', msgList)
}
});
//
this.$connection.on("InteractMessage", (data, type) => {
if (this._route.fullPath.indexOf('interactionList') < 0) {
var tab = this.vuex_tabbar;
tab[1].isDot = true;
this.$u.vuex('vuex_tabbar', tab);
var msgList = this.vuex_tabbar
var msgList = this.vuex_msgList
if (msgList.indexOf('InteractMessage') < 0) {
msgList += 'InteractMessage,';
}
this.$u.vuex('vuex_msgList', msgList)
}
});
},
CharLogin() {
//connectionId
if (this.vuex_user.id) {
this.$connection
.invoke("login", this.connectionId, this.vuex_user.id)
.then((res) => {
})
.catch((err) => {
});
//
this.getLocation()
} else {
setTimeout(() => {
this.CharLogin()
}, 1000)
}
},
},
mounted() {
this.charLink()
},
};
</script>
<style lang="scss">
@import "uview-ui/index.scss";
@import "common/demo.scss";
.u-tabbar__content__item__button {
top: 0.07rem !important;
}
.u-navbar-placeholder,
.u-navbar-inner {
height: 0.44rem !important;
}
.u-tabbar__content__item__text {
font-size: 20rpx !important;
}
.u-tabbar__content__item__button .u-icon__img {
width: 44rpx !important;
height: 44rpx !important;
}
.u-size-mini {
font-size: 0.12rem !important;
}
uni-modal .uni-modal__hd {
padding: 0.1rem;
}
uni-modal .uni-modal__bd {
padding-top: 20rpx;
// font-weight: bold;
font-size: 34rpx;
color: rgba(0, 0, 0, 0.9);
}
uni-modal .uni-modal__btn {
border-radius: 16rpx;
font-size: 28rpx;
}
uni-modal .uni-modal__btn:after {
border: none !important;
}
uni-modal .uni-modal__btn_default {
background: #e6f6ff;
color: #3CB5FB !important;
margin-right: 20rpx;
}
uni-modal .uni-modal__ft {
line-height: 80rpx;
}
uni-modal .uni-modal__ft:after {
border: none !important;
}
uni-modal .uni-modal__btn_primary {
background: #3cb5fb;
color: #ffffff !important;
}
uni-modal .uni-modal {
padding: 40rpx;
box-sizing: border-box;
border-radius: 30rpx;
}
.u-tabbar__content {
height: 0.5rem !important;
}
.phone .u-tabbar__content {
padding-bottom: 0.14rem;
}
.u-tabs-scorll-flex .u-tabs-item {
transition: all 0.1s;
font-size: 0.15rem !important;
}
* {
font-family: "pingfang";
}
html {
font-size: 200rpx;
}
uni-page-body {
height: 100%;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
"Microsoft Yahei", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
// max-width: 1536rpx;
margin: 0 auto;
background-color: #f6f7fa;
}
view,
image,
text {
box-sizing: border-box;
flex-shrink: 0;
}
#app {
width: 100vw;
height: 100vh;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-col {
display: flex;
flex-direction: column;
}
.justify-start {
display: flex;
justify-content: flex-start;
}
.justify-center {
display: flex;
justify-content: center;
}
.justify-end {
display: flex;
justify-content: flex-end;
}
.justify-evenly {
display: flex;
justify-content: space-evenly;
}
.justify-around {
display: flex;
justify-content: space-around;
}
.justify-between {
display: flex;
justify-content: space-between;
}
.items-start {
display: flex;
align-items: flex-start;
}
.items-center {
display: flex;
align-items: center;
}
.items-end {
display: flex;
align-items: flex-end;
}
</style>

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

36
README.en.md Normal file
View File

@ -0,0 +1,36 @@
# 校柚H5
#### Description
校柚H5
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -0,0 +1 @@
### 项目初始化

1087
common/classify.data.js Normal file

File diff suppressed because it is too large Load Diff

86
common/demo.scss Normal file
View File

@ -0,0 +1,86 @@
/* #ifndef APP-NVUE */
view,
text {
box-sizing: border-box;
}
/* #endif */
/* start--演示页面使用的统一样式--start */
.u-demo {
padding: 25px 20px;
}
.u-demo-wrap {
border-width: 1px;
border-color: #ddd;
border-style: dashed;
background-color: rgb(250, 250, 250);
padding: 20px 10px;
border-radius: 3px;
}
.u-demo-area {
text-align: center;
}
.u-no-demo-here {
color: $u-tips-color;
font-size: 13px;
}
.u-demo-result-line {
border-width: 1px;
border-color: #ddd;
border-style: dashed;
padding: 5px 20px;
margin-top: 30px;
border-radius: 5px;
background-color: rgb(240, 240, 240);
color: $u-content-color;
font-size: 16px;
/* #ifndef APP-NVUE */
word-break: break-word;
display: inline-block;
/* #endif */
text-align: left;
}
.u-demo-title,
.u-config-title {
text-align: center;
font-size: 16px;
font-weight: bold;
margin-bottom: 20px;
}
.u-config-item {
margin-top: 25px;
}
.u-config-title {
margin-top: 20px;
padding-bottom: 5px;
}
.u-item-title {
position: relative;
font-size: 15px;
padding-left: 8px;
line-height: 1;
margin-bottom: 11px;
}
.u-item-title:after {
position: absolute;
width: 4px;
top: -1px;
height: 16px;
/* #ifndef APP-NVUE */
content: '';
/* #endif */
left: 0;
border-radius: 10px;
background-color: $u-content-color;
}
/* end--演示页面使用的统一样式--end */

137
common/http.api.js Normal file
View File

@ -0,0 +1,137 @@
// 此处第二个参数vm就是我们在页面使用的this你可以通过vm获取vuex等操作
const install = (Vue, vm) => {
// 登录
let LoginApp = (params = {}) => vm.$u.post('api/Token/LoginApp', params)
// 注册
let RegisterUser = (params = {}) => vm.$u.post('api/Token/RegisterUser', params);
// 基础资料以及保存用户头像
let saveUserInfo = (params = {}) => vm.$u.post('app/User/UploadingFormFileHead', params);
// 更新用户定位信息
let upPosition = (params = {}) => vm.$u.post('app/Position/InsertPosition', params);
// 获取用户当前定位信息
let getPosition = (params = {}) => vm.$u.get('app/Position/GetPositionByUser', {
userId: vm.vuex_user.id
});
// 获取所有学校
let GetAllSchool = (params = {}) => vm.$u.get('app/User/GetSchoolList', params);
//获取首页地图信息
let HomeMap = (params = {}) => vm.$u.get('/app/User/HomeMap', params);
//修改密码
let ChangePassword = (params = {}) => vm.$u.post('app/User/ChangePassword', params);
//修改密码
let myChangePassword = (params = {}) => vm.$u.post('app/My/ChangePassword', params);
// 获取搜索页面相关信息
let SearchInfo = (params = {}) => vm.$u.get('app/User/SearchRelevant', params);
//获取搜索结果页面
let getSearch = (params = {}) => vm.$u.get('app/User/GetSearchList', params);
// 获取用户信息
let getUserInfo = (params = {}) => vm.$u.get('app/User/HomePage', params);
// 获取校友帮帮列表
let GetHelpList = (params = {}) => vm.$u.get('app/HelpArticle/GetHelpArticleListByKey', params);
// 获取学校资讯
let GetSchoolList = (params = {}) => vm.$u.get('app/AlumnRange/AlumnRangeSchool', params);
//获取最新的用户信息(更新用户数据)
let getUser = (params = {}) => vm.$u.get('app/User/GetUser', {userId: vm.vuex_user.id}).then(res => {
vm.$u.get('/app/User/GetUserSchool').then(ress => {
// res.isAttestationGLY = ress.isAttestationGLY
// res.isAttestationJZG = ress.isAttestationJZG
// res.isAttestationQY = ress.isAttestationQY
// res.isAttestationXY = res.isAttestationXY
// res.isAttestationZXS = ress.isAttestationZXS
res.schoolId = ress.items.schoolId
vm.$u.vuex('vuex_user', {...res.user,...res.userExtension})
vm.$u.vuex('vuex_user_hobby', res.lableList)
})
})
//获取用户消息列表
let getcharList = (params = {}) => vm.$u.get('app/Chat/GetUserMessageList', params);
//获取用户获取关注列表
let getFollowList = (params = {}) => vm.$u.get('app/Chat/GetFollowList', {id: vm.vuex_user.id});
// 获取系统消息列表
let getSysList = (params = {}) => vm.$u.get('app/Chat/GetSystemMessageList', {id: vm.vuex_user.id});
//获取管理消息列表
let getAdminList = (params = {}) => vm.$u.get('app/Chat/GetManageMessageList', {schoolId: vm.vuex_user.id});
//获取互动信息列表
let getinteractionList = (params) => vm.$u.get('app/Chat/GetInterMessageList', {id: vm.vuex_user.id, type: params});
//校友找找推荐列表
let getAlumnSearch = (params = {}) => vm.$u.get('app/AlumnRange/AlumnSearch', params);
//获取聊天记录
let getChatRecord = (params = {}) => vm.$u.get('app/Chat/GetChatRecord', params);
//校友找找列表
let AlumnSearchList = (params = {}) => vm.$u.get('app/AlumnRange/AlumnSearchList', params);
// 初始化的数据调用微信接口返回参数
let GetInfoMation = (params = {}) => vm.$u.get('api/Token/GetInfoMation', params);
// 回复绑定
let toBind = (params = {}) => vm.$u.get('app/Chat/ReplyBind', params);
//我的资讯
let MyAlumnRange = (params = {}) => vm.$u.get('app/My/MyAlumnRange', params);
// 解除绑定
let colseBind = (params = {}) => vm.$u.get('app/Chat/UnbindReply', params);
// 删除评论
let DelateComment = (params = {}) => vm.$u.get('app/AlumnRange/DelateComment', params);
let userVerify = (params = {}) => vm.$u.post('api/Token/IsIdentityCard', params)
// 获取人脸验证token
let getAPIToken = (params = {}) => vm.$u.post('app/My/GetVerifyToken', params)
// 查询人脸核验结果
let getVerifyInfo = (params = {}) => vm.$u.post('app/My/GetDetailInfo?VerifyToken=' + params)
// 根据身份证获取信息
let getInfoByCard = (params = {}) => vm.$u.get('app/User/GetCardByPreConfiguredUser', params);
// 更新身份信息
let updateCard = (params = {}) => vm.$u.post('api/Token/UpdateCard', params)
//【手机端】添加心愿
let PushWishDan = (params = {}) => vm.$u.post("app/My/PushWishDan", params)
//【手机端】获取个人心愿列表
let GetWishListAsync_mobile = (params = {}) => vm.$u.get("app/My/GetWishListAsync_mobile", params)
//【手机端】删除心愿 删除=失效
let DeleteWish = (params = {}) => vm.$u.post("app/My/DeleteWish", params)
//【管理端】获取当前是否开启匿名 开启true 关闭false
let CheckNM = (params = {}) => vm.$u.get("/app/My/CheckNM", params)
// 将各个定义的接口名称统一放进对象挂载到vm.$u.api(因为vm就是this也即this.$u.api)下
vm.$u.api = {
LoginApp,
RegisterUser,
saveUserInfo,
upPosition,
getPosition,
GetAllSchool,
HomeMap,
ChangePassword,
myChangePassword,
SearchInfo,
getSearch,
getUserInfo,
GetHelpList,
GetSchoolList,
getUser,
getcharList,
getFollowList,
getSysList,
getAdminList,
getinteractionList,
getAlumnSearch,
getChatRecord,
AlumnSearchList,
GetInfoMation,
toBind,
colseBind,
MyAlumnRange,
DelateComment,
userVerify,
GetWishListAsync_mobile,
DeleteWish,
CheckNM,
PushWishDan,
getAPIToken,
getVerifyInfo,
getInfoByCard,
updateCard
};
}
export default {
install
}

245
common/http.apiList.js Normal file
View File

@ -0,0 +1,245 @@
// 此处第二个参数vm就是我们在页面使用的this你可以通过vm获取vuex等操作
const install = (Vue, vm) => {
// 获取行业下所有子行业和标签
let GetLableList = (params = {}) => vm.$u.get('app/User/GetLableList', params)
// 获取兴趣标签
let GetInterestLable = (params = {}) => vm.$u.get('app/User/GetInterestLable', params)
// 修改个人资料
let UpdateUser = (params = {}) => vm.$u.post('app/User/UpdateUser', params);
// 获取所有工作领域
let GetWorkFile = (params = {}) => vm.$u.get('app/User/GetWorkFileList', params);
// 我的页面
let MyPage = (params = {}) => vm.$u.get('app/My/MyPage', params);
// 我的教育经历
let MyEducations = (params = {}) => vm.$u.get('app/My/MyEducations', params);
// 添加教育经历
let AddEducation = (params = {}) => vm.$u.post('app/My/AddEducation', params);
// 提交校友认证
let SubmitAttestationXY = (params = {}) => vm.$u.post('app/My/SubmitAttestationXY', params);
// 选择已认证的教育经历 返回学校ID
let SelectEducation = (params = {}) => vm.$u.post('app/My/SelectEducation', params);
// 我的发布
let Publishs = (params = {}) => vm.$u.get('app/My/Publish', params);
//用户发布学校资讯
let InsertJournaArticle = (params = {}) => vm.$u.post('app/AlumnRange/InsertJournaArticle', params);
//用户发布帮帮资讯
let InsertHelpArticle = (params = {}) => vm.$u.post('app/AlumnRange/InsertHelpArticle', params);
//管理员认证
let AttestationGLY = (params = {}) => vm.$u.get('app/My/AttestationGLY', params);
//提交管理员认证
let SubmitAttestationGLY = (params = {}) => vm.$u.post('app/My/SubmitAttestationGLY', params);
//教职工认证
let AttestationJZG = (params = {}) => vm.$u.get('app/My/AttestationJZG', params);
//提交教职工认证
let SubmitAttestationJZG = (params = {}) => vm.$u.post('app/My/SubmitAttestationJZG', params);
//基础资料以及教职工认证
let UpdateUserJZG = (params = {}) => vm.$u.post("app/User/UpdateUserJZG", params)
//企业认证
let AttestationQY = (params = {}) => vm.$u.get('app/My/AttestationQY', params);
//提交企业认证
let SubmitAttestationQY = (params = {}) => vm.$u.post('app/My/SubmitAttestationQY', params);
//定位、推荐、消息设置
let Setting = (params = {}) => vm.$u.post('app/My/Setting', params);
//获取当前登录用户
let GetUser = (params = {}) => vm.$u.get('app/User/GetUser', params);
//获取所有标签
let GetSign = (params = {}) => vm.$u.get('app/AlumnRange/GetSign', params);
//关注或取关
let InsertOrDelFollow = (params = {}) => vm.$u.post('app/Follow/InsertOrDelFollow', params);
//评论
let InsertComment = (params = {}) => vm.$u.post('app/AlumnRange/InsertComment', params);
//获取文章评论信息
let GetJournaArticle = (params = {}) => vm.$u.get('app/AlumnRange/GetJournaArticle', params);
//获取评论详细信息
let GetComment = (params = {}) => vm.$u.get('app/AlumnRange/GetComment', params);
//添加收藏(0资讯,1帮帮)
let LikeCollect = (params = {}) => vm.$u.get('app/AlumnRange/LikeCollect', params);
//点赞(0资讯,1帮帮,2评论) 或取消点赞
let LikeHe = (params = {}) => vm.$u.get('app/AlumnRange/LikeHe', params);
//用户转发帮帮资讯
let ForwardHelpArticle = (params = {}) => vm.$u.post('app/AlumnRange/ForwardHelpArticle', params);
//获取用户当前学校信息(未认证为空,未选中默认选择最新认证学校)
let GetUserSchool = (params = {}) => vm.$u.get('app/User/GetUserSchool', params);
//我的收藏
let Collection = (params = {}) => vm.$u.get('app/My/Collection', params)
//查看用户发布信息
let UserHelp = (params = {}) => vm.$u.get('app/User/UserHelp', params)
//审核列表
let AuditList = (params = {}) => vm.$u.get('app/My/AuditList', params)
//审核详情
let AuditDeatil = (params = {}) => vm.$u.get('app/My/AuditDeatil', params)
//审核
let Audit = (params = {}) => vm.$u.post('app/My/Audit', params);
//获取手机验证码
let GetPhoneValidateCode = (params = {}) => vm.$u.post('api/Token/GetPhoneValidateCode', params)
// 获取验证码
let Captcha = (params = {}) => vm.$u.get('api/Token/Captcha', params)
//根据页面类型获取手机验证码
let GetAppValidateCode = (params = {}) => vm.$u.post('api/Token/GetAppValidateCode', params)
//验证码是否正确
let IsPhoneCode = (params = {}) => vm.$u.get('api/Token/IsPhoneCode', params)
//学校资讯
let AlumnRangeSchool = (params = {}) => vm.$u.get('app/AlumnRange/AlumnRangeSchool', params)
//意见反馈
let SubmitFeedback = (params = {}) => vm.$u.post('app/My/SubmitFeedback', params)
//获取学校学院列表
let GetCollegeList = (params = {}) => vm.$u.get('app/User/GetCollegeList', params)
//获取专业列表
let GetMajorList = (params = {}) => vm.$u.get('app/User/GetMajorList', params)
//获取当前学校是否认证信息
let GetUserApproval = (params = {}) => vm.$u.get('app/User/GetUserApproval', params)
// 删除未认证教育经历
let DeleteEducation = (params = {}) => vm.$u.get('app/My/DeleteEducation', params)
// 删除文章
let DelateArticle = (params = {}) => vm.$u.get('app/AlumnRange/DelateArticle', params)
// 取消收藏
let CancleCollect = (params = {}) => vm.$u.get('app/My/CancleCollect', params)
//忘记密码
let ForgotPassword = (params = {}) => vm.$u.post('admin/User/ForgotPassword', params)
//手机申请返校预约
let AddReturnSchoolApi = (params = {}) => vm.$u.post('app/ReturnSchoolPrebook/AddReturnSchool', params);
// 返校预约列表 - 待审核
let SelectReturnSchoolList_dshApi = (params = {}) => vm.$u.get('app/ReturnSchoolPrebook/SelectReturnSchoolList_dsh', params)
// 返校预约列表 - 传状态
let SelectReturnSchoolList_typeApi = (params = {}) => vm.$u.get('app/ReturnSchoolPrebook/SelectReturnSchoolList_type', params)
// 获取返校预约设置
let SelectInfoSetApi = (params = {}) => vm.$u.get('/app/ReturnSchoolPrebook/SelectInfoSet', params)
// 获取返校预约设置 没token
let SelectInfoSetNoTokenApi = (params = {}) => vm.$u.get('/app/Share/SelectInfoSet', params)
// 返校预约详情
let SelectReturnSchoolInfoApi = (params = {}) => vm.$u.post('app/ReturnSchoolPrebook/SelectReturnSchoolInfo', params);
// 返校预约详情 没token
let SelectReturnSchoolInfoNotokenApi = (params = {}) => vm.$u.post('/app/Share/SelectReturnSchoolInfo', params);
// 取消返校预约
let DelReturnSchoolInfoApi = (params = {}) => vm.$u.post('app/ReturnSchoolPrebook/DelReturnSchoolInfo', params);
// 核验二维码
let SaveReturnSchoolInfoApi = (params = {}) => vm.$u.post('app/ReturnSchoolPrebook/SaveReturnSchoolInfo', params);
// 核验二维码 没token
let SaveReturnSchoolInfoNoTokenApi = (params = {}) => vm.$u.post('app/Share/SaveReturnSchoolInfo', params);
// 获取二维码
let SaveReturnSchoolVerifyApi = (params = {}) => vm.$u.post('app/ReturnSchoolPrebook/SaveReturnSchoolVerify', params);
// 获取二维码 没token
let SaveReturnSchoolVerifyNoTokenApi = (params = {}) => vm.$u.post('app/Share/SaveReturnSchoolVerify', params);
// 添加工作经历
let AddWordInfoApi = (params = {}) => vm.$u.post('/app/User/AddWordInfo', params);
// 修改工作经历
let UpdateWorkInfoApi = (params = {}) => vm.$u.post('/app/User/UpdateWorkInfo', params);
// 删除工作经历
let DelWorkInfoApi = (params = {}) => vm.$u.post('/app/User/DelWorkInfo', params);
// 添加项目经历
let AddProjectInfoApi = (params = {}) => vm.$u.post('/app/User/AddProjectInfo', params);
// 修改项目经历
let UpdateProjectInfoApi = (params = {}) => vm.$u.post('/app/User/UpdateProjectInfo', params);
// 删除项目经历
let DelProjectInfoApi = (params = {}) => vm.$u.post('/app/User/DelProjectInfo', params);
// 制作简历界面
let ResumeUserApi = (params = {}) => vm.$u.get('/app/User/ResumeUser', params);
// 附件简历列表
let GetUserFileApi = (params = {}) => vm.$u.get('/app/User/GetUserFile', params);
// 删除附件
let DelUserFileApi = (params = {}) => vm.$u.post('/app/User/DelUserFile', params);
// 设置展示简历
let UpdateUserFileApi = (params = {}) => vm.$u.post('/app/User/UpdateUserFile', params);
// 获取学校ID
let GetUserSchoolApi = (params = {}) => vm.$u.get('/app/User/GetUserSchool', params);
// 获取已预约的日期
let GetDateTimeReturnApi = (params = {}) => vm.$u.get('/app/ReturnSchoolPrebook/GetDateTimeReturn', params);
// 选择教职工认证
let SelectJZGApi = (params = {}) => vm.$u.post('/app/My/SelectJZG', params);
let ForgotPasswordValidate = (params = {}) => vm.$u.post('/admin/User/ForgotPasswordValidate', params);
//忘记密码-验证验证码
// 删除
let DeleteJZGApi = (params = {}) => vm.$u.get('/app/My/DeleteJZG', params);
// 返回判断用户身份信息
let SelectUserTypeApi = (params = {}) => vm.$u.get('/app/My/SelectUserType', params);
// 更新切换用户身份UserType
let UpdateUserTypeApi = (params = {}) => vm.$u.get('/app/My/UpdateUserType', params);
// 将各个定义的接口名称统一放进对象挂载到vm.$u.apiList(因为vm就是this也即this.$u.apiList)下
vm.$u.apiList = {
Captcha,
GetInterestLable,
GetLableList,
SelectUserTypeApi,
UpdateUserTypeApi,
ForgotPasswordValidate,
DeleteJZGApi,
SelectJZGApi,
GetDateTimeReturnApi,
AddReturnSchoolApi,
GetUserSchoolApi,
UpdateUserFileApi,
DelUserFileApi,
AddWordInfoApi,
GetUserFileApi,
DelWorkInfoApi,
UpdateProjectInfoApi,
DelProjectInfoApi,
AddProjectInfoApi,
UpdateWorkInfoApi,
ResumeUserApi,
SaveReturnSchoolVerifyApi,
SelectInfoSetApi,
SelectInfoSetNoTokenApi,
SelectReturnSchoolList_dshApi,
SelectReturnSchoolList_typeApi,
SelectReturnSchoolInfoApi,
SaveReturnSchoolInfoNoTokenApi,
SaveReturnSchoolVerifyNoTokenApi,
SelectReturnSchoolInfoNotokenApi,
DelReturnSchoolInfoApi,
SaveReturnSchoolInfoApi,
UpdateUser,
GetWorkFile,
MyPage,
MyEducations,
AddEducation,
SubmitAttestationXY,
SelectEducation,
Publishs,
InsertJournaArticle,
InsertHelpArticle,
AttestationGLY,
SubmitAttestationGLY,
AttestationJZG,
SubmitAttestationJZG,
AttestationQY,
SubmitAttestationQY,
Setting,
GetUser,
GetSign,
InsertOrDelFollow,
InsertComment,
GetJournaArticle,
GetComment,
LikeCollect,
LikeHe,
ForwardHelpArticle,
GetUserSchool,
Collection,
UserHelp,
AuditList,
AuditDeatil,
ForwardHelpArticle,
Audit,
GetPhoneValidateCode,
AlumnRangeSchool,
IsPhoneCode,
SubmitFeedback,
GetCollegeList,
GetMajorList,
GetUserApproval,
DeleteEducation,
DelateArticle,
CancleCollect,
GetAppValidateCode,
ForgotPassword,
UpdateUserJZG
};
}
export default {
install
}

View File

@ -0,0 +1,64 @@
// 这里的vm就是我们在vue文件里面的this所以我们能在这里获取vuex的变量比如存放在里面的token
// 同时我们也可以在此使用getApp().globalData如果你把token放在getApp().globalData的话也是可以使用的
const install = (Vue, vm) => {
Vue.prototype.$u.http.setConfig({
// baseUrl: 'https://xy.apps.service.zheke.com',
// imgUrl: 'https://xy.apps.service.zheke.com/',
baseUrl: 'http://sl.vrgon.com:8003',
imgUrl: 'http://sl.vrgon.com:8003/',
// imgUrl:'http://115.238.47.235:8987/',
// baseUrl: 'http://115.238.47.235:8993',
// 如果将此值设置为true拦截回调中将会返回服务端返回的所有数据response而不是response.data
// 设置为true后就需要在this.$u.http.interceptor.response进行多一次的判断请打印查看具体值
// originalData: true,
// 设置自定义头部content-type
// header: {
// 'content-type': 'xxx'
// }
});
// 请求拦截配置Token等参数
Vue.prototype.$u.http.interceptor.request = (config) => {
// config.header.Token = 'xxxxxx';
// 方式一存放在vuex的token假设 https://uviewui.com/components/globalVariable.html
config.header.Authorization = 'Bearer ' + vm.vuex_token;
// 方式二如果没有使用uView封装的vuex方法那么需要使用$store.state获取
// config.header.token = vm.$store.state.token;
// 方式三如果token放在了globalData通过getApp().globalData获取
// config.header.token = getApp().globalData.username;
// 方式四如果token放在了Storage本地存储中拦截是每次请求都执行的所以哪怕您重新登录修改了Storage下一次的请求将会是最新值
// const token = uni.getStorageSync('token');
// config.header.token = token;
uni.showLoading({
title: '加载中'
});
// setTimeout(function () {
// uni.hideLoading();
// }, 2000);
return config;
}
// 响应拦截,判断状态码是否通过
Vue.prototype.$u.http.interceptor.response = (res) => {
uni.hideLoading();
if (res.succeed == true || res.success == true) {
return res.data || res;
} else {
// uni.showToast({
// title: res.error,
// duration: 2000,
// icon: 'none'
// });
// uni.navigateTo({
// url: "/pages/login/login/login",
// });
return false;
}
}
}
export default {
install
}

585
common/index.list.js Normal file
View File

@ -0,0 +1,585 @@
module.exports = {
list: [{
"letter": "A",
"data": [{
"name": "阿拉斯加",
"mobile": "13588889999",
"keyword": "阿拉斯加ABA13588889999"
},
{
"name": "阿克苏",
"mobile": "0551-4386721",
"keyword": "阿克苏AKESU0551-4386721"
},
{
"name": "阿拉善",
"mobile": "4008009100",
"keyword": "阿拉善ALASHAN4008009100"
},
{
"name": "阿勒泰",
"mobile": "13588889999",
"keyword": "阿勒泰ALETAI13588889999"
},
{
"name": "阿里",
"mobile": "13588889999",
"keyword": "阿里ALI13588889999"
},
{
"name": "安阳",
"mobile": "13588889999",
"keyword": "13588889999安阳ANYANG"
}
]
},
{
"letter": "B",
"data": [{
"name": "白城",
"mobile": "该主子没有留电话~",
"keyword": "白城BAICHENG"
},
{
"name": "白山",
"mobile": "13588889999",
"keyword": "白山BAISHAN13588889999"
},
{
"name": "白银",
"mobile": "13588889999",
"keyword": "白银BAIYIN13588889999"
},
{
"name": "保定",
"mobile": "13588889999",
"keyword": "保定BAODING13588889999"
}
]
},
{
"letter": "C",
"data": [{
"name": "沧州",
"mobile": "13588889999",
"keyword": "沧州CANGZHOU13588889999"
},
{
"name": "长春",
"mobile": "13588889999",
"keyword": "长春CHANGCHUN13588889999"
}
]
},
{
"letter": "D",
"data": [{
"name": "大理",
"mobile": "13588889999",
"keyword": "大理DALI13588889999"
},
{
"name": "大连",
"mobile": "13588889999",
"keyword": "大连DALIAN13588889999"
}
]
},
{
"letter": "E",
"data": [{
"name": "鄂尔多斯",
"mobile": "13588889999",
"keyword": "鄂尔多斯EERDUOSI13588889999"
},
{
"name": "恩施",
"mobile": "13588889999",
"keyword": "恩施ENSHI13588889999"
},
{
"name": "鄂州",
"mobile": "13588889999",
"keyword": "鄂州EZHOU13588889999"
}
]
},
{
"letter": "F",
"data": [{
"name": "防城港",
"mobile": "该主子没有留电话~",
"keyword": "防城港FANGCHENGGANG"
},
{
"name": "抚顺",
"mobile": "13588889999",
"keyword": "抚顺FUSHUN13588889999"
},
{
"name": "阜新",
"mobile": "13588889999",
"keyword": "阜新FUXIN13588889999"
},
{
"name": "阜阳",
"mobile": "13588889999",
"keyword": "阜阳FUYANG13588889999"
},
{
"name": "抚州",
"mobile": "13588889999",
"keyword": "抚州FUZHOU13588889999"
},
{
"name": "福州",
"mobile": "13588889999",
"keyword": "福州FUZHOU13588889999"
}
]
},
{
"letter": "G",
"data": [{
"name": "甘南",
"mobile": "13588889999",
"keyword": "甘南GANNAN13588889999"
},
{
"name": "赣州",
"mobile": "13588889999",
"keyword": "赣州GANZHOU13588889999"
},
{
"name": "甘孜",
"mobile": "13588889999",
"keyword": "甘孜GANZI13588889999"
}
]
},
{
"letter": "H",
"data": [{
"name": "哈尔滨",
"mobile": "13588889999",
"keyword": "哈尔滨HAERBIN13588889999"
},
{
"name": "海北",
"mobile": "13588889999",
"keyword": "海北HAIBEI13588889999"
},
{
"name": "海东",
"mobile": "13588889999",
"keyword": "海东HAIDONG13588889999"
},
{
"name": "海口",
"mobile": "13588889999",
"keyword": "海口HAIKOU13588889999"
}
]
},
{
"letter": "I",
"data": [{
"name": "ice",
"mobile": "13588889999",
"keyword": "佳木斯JIAMUSI13588889999"
}]
},
{
"letter": "J",
"data": [{
"name": "佳木斯",
"mobile": "13588889999",
"keyword": "佳木斯JIAMUSI13588889999"
},
{
"name": "吉安",
"mobile": "13588889999",
"keyword": "吉安JIAN13588889999"
},
{
"name": "江门",
"mobile": "13588889999",
"keyword": "江门JIANGMEN13588889999"
}
]
},
{
"letter": "K",
"data": [{
"name": "开封",
"mobile": "13588889999",
"keyword": "开封KAIFENG13588889999"
},
{
"name": "喀什",
"mobile": "13588889999",
"keyword": "喀什KASHI13588889999"
},
{
"name": "克拉玛依",
"mobile": "13588889999",
"keyword": "克拉玛依KELAMAYI13588889999"
}
]
},
{
"letter": "L",
"data": [{
"name": "来宾",
"mobile": "13588889999",
"keyword": "来宾LAIBIN13588889999"
},
{
"name": "兰州",
"mobile": "13588889999",
"keyword": "兰州LANZHOU13588889999"
},
{
"name": "拉萨",
"mobile": "13588889999",
"keyword": "拉萨LASA13588889999"
},
{
"name": "乐山",
"mobile": "13588889999",
"keyword": "乐山LESHAN13588889999"
},
{
"name": "凉山",
"mobile": "13588889999",
"keyword": "凉山LIANGSHAN13588889999"
},
{
"name": "连云港",
"mobile": "13588889999",
"keyword": "连云港LIANYUNGANG13588889999"
},
{
"name": "聊城",
"mobile": "18322223333",
"keyword": "聊城LIAOCHENG18322223333"
},
{
"name": "辽阳",
"mobile": "18322223333",
"keyword": "辽阳LIAOYANG18322223333"
},
{
"name": "辽源",
"mobile": "18322223333",
"keyword": "辽源LIAOYUAN18322223333"
},
{
"name": "丽江",
"mobile": "18322223333",
"keyword": "丽江LIJIANG18322223333"
},
{
"name": "临沧",
"mobile": "18322223333",
"keyword": "临沧LINCANG18322223333"
},
{
"name": "临汾",
"mobile": "18322223333",
"keyword": "临汾LINFEN18322223333"
},
{
"name": "临夏",
"mobile": "18322223333",
"keyword": "临夏LINXIA18322223333"
},
{
"name": "临沂",
"mobile": "18322223333",
"keyword": "临沂LINYI18322223333"
},
{
"name": "林芝",
"mobile": "18322223333",
"keyword": "林芝LINZHI18322223333"
},
{
"name": "丽水",
"mobile": "18322223333",
"keyword": "丽水LISHUI18322223333"
}
]
},
{
"letter": "M",
"data": [{
"name": "眉山",
"mobile": "15544448888",
"keyword": "眉山MEISHAN15544448888"
},
{
"name": "梅州",
"mobile": "15544448888",
"keyword": "梅州MEIZHOU15544448888"
},
{
"name": "绵阳",
"mobile": "15544448888",
"keyword": "绵阳MIANYANG15544448888"
},
{
"name": "牡丹江",
"mobile": "15544448888",
"keyword": "牡丹江MUDANJIANG15544448888"
}
]
},
{
"letter": "N",
"data": [{
"name": "南昌",
"mobile": "15544448888",
"keyword": "南昌NANCHANG15544448888"
},
{
"name": "南充",
"mobile": "15544448888",
"keyword": "南充NANCHONG15544448888"
},
{
"name": "南京",
"mobile": "15544448888",
"keyword": "南京NANJING15544448888"
},
{
"name": "南宁",
"mobile": "15544448888",
"keyword": "南宁NANNING15544448888"
},
{
"name": "南平",
"mobile": "15544448888",
"keyword": "南平NANPING15544448888"
}
]
},
{
"letter": "O",
"data": [{
"name": "欧阳",
"mobile": "15544448888",
"keyword": "欧阳ouyang15544448888"
}]
},
{
"letter": "P",
"data": [{
"name": "盘锦",
"mobile": "15544448888",
"keyword": "盘锦PANJIN15544448888"
},
{
"name": "攀枝花",
"mobile": "15544448888",
"keyword": "攀枝花PANZHIHUA15544448888"
},
{
"name": "平顶山",
"mobile": "15544448888",
"keyword": "平顶山PINGDINGSHAN15544448888"
},
{
"name": "平凉",
"mobile": "15544448888",
"keyword": "平凉PINGLIANG15544448888"
},
{
"name": "萍乡",
"mobile": "15544448888",
"keyword": "萍乡PINGXIANG15544448888"
},
{
"name": "普洱",
"mobile": "15544448888",
"keyword": "普洱PUER15544448888"
},
{
"name": "莆田",
"mobile": "15544448888",
"keyword": "莆田PUTIAN15544448888"
},
{
"name": "濮阳",
"mobile": "15544448888",
"keyword": "濮阳PUYANG15544448888"
}
]
},
{
"letter": "Q",
"data": [{
"name": "黔东南",
"mobile": "15544448888",
"keyword": "黔东南QIANDONGNAN15544448888"
},
{
"name": "黔南",
"mobile": "15544448888",
"keyword": "黔南QIANNAN15544448888"
},
{
"name": "黔西南",
"mobile": "15544448888",
"keyword": "黔西南QIANXINAN15544448888"
}
]
},
{
"letter": "R",
"data": [{
"name": "日喀则",
"mobile": "15544448888",
"keyword": "日喀则RIKAZE15544448888"
},
{
"name": "日照",
"mobile": "15544448888",
"keyword": "日照RIZHAO15544448888"
}
]
},
{
"letter": "S",
"data": [{
"name": "三门峡",
"mobile": "15544448888",
"keyword": "三门峡SANMENXIA15544448888"
},
{
"name": "三明",
"mobile": "15544448888",
"keyword": "三明SANMING15544448888"
},
{
"name": "三沙",
"mobile": "15544448888",
"keyword": "三沙SANSHA15544448888"
}
]
},
{
"letter": "T",
"data": [{
"name": "塔城",
"mobile": "15544448888",
"keyword": "塔城TACHENG15544448888"
},
{
"name": "漯河",
"mobile": "15544448888",
"keyword": "漯河TAHE15544448888"
},
{
"name": "泰安",
"mobile": "15544448888",
"keyword": "泰安TAIAN15544448888"
}
]
},
{
"letter": "W",
"data": [{
"name": "潍坊",
"mobile": "15544448888",
"keyword": "潍坊WEIFANG15544448888"
},
{
"name": "威海",
"mobile": "15544448888",
"keyword": "威海WEIHAI15544448888"
},
{
"name": "渭南",
"mobile": "15544448888",
"keyword": "渭南WEINAN15544448888"
},
{
"name": "文山",
"mobile": "15544448888",
"keyword": "文山WENSHAN15544448888"
}
]
},
{
"letter": "X",
"data": [{
"name": "厦门",
"mobile": "15544448888",
"keyword": "厦门XIAMEN15544448888"
},
{
"name": "西安",
"mobile": "15544448888",
"keyword": "西安XIAN15544448888"
},
{
"name": "湘潭",
"mobile": "15544448888",
"keyword": "湘潭XIANGTAN15544448888"
}
]
},
{
"letter": "Y",
"data": [{
"name": "雅安",
"mobile": "15544448888",
"keyword": "雅安YAAN15544448888"
},
{
"name": "延安",
"mobile": "15544448888",
"keyword": "延安YANAN15544448888"
},
{
"name": "延边",
"mobile": "15544448888",
"keyword": "延边YANBIAN15544448888"
},
{
"name": "盐城",
"mobile": "15544448888",
"keyword": "盐城YANCHENG15544448888"
}
]
},
{
"letter": "Z",
"data": [{
"name": "枣庄",
"mobile": "15544448888",
"keyword": "枣庄ZAOZHUANG15544448888"
},
{
"name": "张家界",
"mobile": "15544448888",
"keyword": "张家界ZHANGJIAJIE15544448888"
},
{
"name": "张家口",
"mobile": "15544448888",
"keyword": "张家口ZHANGJIAKOU15544448888"
}
]
},
{
"letter": "#",
"data": [{
"name": "其他.",
"mobile": "16666666666",
"keyword": "echo16666666666"
}]
}
]
}

21
common/locales/en.js Normal file
View File

@ -0,0 +1,21 @@
export default {
// 可以以页面为单位来写比如首页的内容写在index字段个人中心写在center共同部分写在common部分
components: {
desc: 'Numerous components cover the various requirements of the development process, and the components are rich in functions and compatible with multiple terminals. Let you integrate quickly, out of the box'
},
js: {
desc: 'Numerous intimate gadgets are a weapon that you can call upon during the development process, allowing you to dart in your hand and pierce the Yang with a hundred steps'
},
template: {
desc: 'Collection of many commonly used pages and layouts, reducing the repetitive work of developers, allowing you to focus on logic and get twice the result with half the effort'
},
nav: {
components: 'Components',
js: 'JS',
template: 'Template'
},
common: {
intro: 'UI framework for rapid development of multiple platforms',
title: 'uView UI',
},
}

21
common/locales/zh.js Normal file
View File

@ -0,0 +1,21 @@
export default {
// 可以以页面为单位来写比如首页的内容写在index字段个人中心写在center共同部分写在common部分
components: {
desc: '众多组件覆盖开发过程的各个需求,组件功能丰富,多端兼容。让你快速集成,开箱即用'
},
js: {
desc: '众多的贴心小工具,是你开发过程中召之即来的利器,让你飞镖在手,百步穿杨'
},
template: {
desc: '收集众多的常用页面和布局,减少开发者的重复工作,让你专注逻辑,事半功倍'
},
nav: {
components: '组件',
js: '工具',
template: '模板'
},
common: {
intro: '多平台快速开发的UI框架',
title: 'uView UI',
},
}

16
common/utils.js Normal file
View File

@ -0,0 +1,16 @@
export const Debounce = (fn, wait) => {
let delay = wait|| 500
let timer
return function () {
let args = arguments;
if (timer) {
clearTimeout(timer)
}
let callNow = !timer
timer = setTimeout(() => {
timer = null
}, delay)
if (callNow) fn.apply(this, args)
}
}

6
common/vue-i18n.min.js vendored Normal file

File diff suppressed because one or more lines are too long

722
components/ContentCard.vue Normal file
View File

@ -0,0 +1,722 @@
<template>
<!-- 视频图片 动态卡片 -->
<view class="content-card">
<!-- 用户信息 -->
<view class="user-info">
<image
class="avatar"
:src="cardData.user.avatar"
mode="aspectFill"
></image>
<view class="user-detail">
<text class="username">{{ cardData.user.name }}</text>
<text class="user-meta">{{ cardData.user.meta }}</text>
</view>
<view class="follow-btn" @click="onFollow">
<u-icon name="plus" color="#666" size="14"></u-icon>
<text>关注</text>
</view>
</view>
<!-- 内容文本 -->
<view class="content-text" @click="goContentDetail">
{{ cardData.content }}
</view>
<!-- 媒体内容 - 内部处理交互 -->
<view class="media-content">
<!-- 视频内容 -->
<view v-if="isVideo" class="video-container" @click="handleVideoPlay">
<image
class="video-cover"
:src="cardData.cover"
mode="aspectFill"
></image>
<view class="video-overlay">
<u-icon name="play-right" color="#fff" size="40"></u-icon>
<text v-if="cardData.duration" class="video-duration">{{
formatDuration(cardData.duration)
}}</text>
</view>
</view>
<!-- 图片内容 -->
<view v-else class="image-grid" :class="getImageLayoutClass()">
<image
v-for="(img, index) in cardData.images"
:key="index"
class="grid-image"
:src="img"
mode="aspectFill"
@click="handleImagePreview(index)"
></image>
</view>
</view>
<!-- 互动栏 - 内部处理交互 -->
<view class="interaction-bar">
<view
class="action-item"
v-for="(item, index) in actionButtons"
:key="index"
@click="handleAction(item.action)"
>
<image
:src="item.icon"
mode="aspectFill"
style="width: 40rpx; height: 40rpx"
></image>
<text>{{ cardData.stats[item.stat] }}</text>
</view>
</view>
</view>
</template>
<script>
export default {
name: "ContentCard",
props: {
cardData: {
type: Object,
required: true,
default: () => ({
user: {
avatar: "",
name: "",
meta: "",
},
content: "",
//
type: "image", // 'image' 'video'
images: [], //
cover: "", //
videoUrl: "", //
duration: 0, // ()
stats: {
forward: 0,
comment: 0,
like: 0,
favorite: 0,
},
}),
},
},
data() {
return {
//
isLiked: false,
isFavorited: false,
isForwarded: false,
videoContext: null,
//
actionButtons: [
{
icon: "/static/common/img/homepage/reply.png",
action: "forward",
stat: "forward"
},
{
icon: "/static/common/img/homepage/comment.png",
action: "comment",
stat: "comment"
},
{
icon: "/static/common/img/homepage/like.png",
action: "like",
stat: "like"
},
{
icon: "/static/common/img/homepage/star.png",
action: "favorite",
stat: "favorite"
}
]
};
},
computed: {
isVideo() {
return this.cardData.type === "video";
},
//
likeIcon() {
return this.isLiked ? "heart-fill" : "heart";
},
likeColor() {
return this.isLiked ? "#ff5252" : "#999";
},
favoriteIcon() {
return this.isFavorited ? "star-fill" : "star";
},
favoriteColor() {
return this.isFavorited ? "#ffb700" : "#999";
},
forwardIcon() {
return this.isForwarded ? "arrow-right-fill" : "arrow-right";
},
forwardColor() {
return this.isForwarded ? "#2979ff" : "#999";
},
commentColor() {
return "#999"; //
},
},
methods: {
//
onFollow() {
this.$emit("follow", this.cardData.user);
},
//
goContentDetail() {
console.log("this.cardData", this.cardData);
this.$u.route({
url: "/pages/home/home/components/contentDetail/index",
// params: {
// card,
// },
});
},
//
formatDuration(seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.floor(seconds % 60);
return `${minutes.toString().padStart(2, "0")}:${remainingSeconds
.toString()
.padStart(2, "0")}`;
},
//
handleVideoPlay() {
if (this.cardData.videoUrl) {
//
this.savePlayHistory();
// 使
try {
// 使
if (this.useInternalPlayer) {
this.showVideoPlayer = true;
this.$nextTick(() => {
this.videoContext = uni.createVideoContext("video-player", this);
this.videoContext.requestFullScreen();
this.videoContext.play();
});
} else {
//
uni.navigateTo({
url: `/pages/video/player?videoUrl=${encodeURIComponent(
this.cardData.videoUrl
)}&title=${encodeURIComponent(this.cardData.content)}`,
});
}
//
this.$emit("video-play", {
videoUrl: this.cardData.videoUrl,
title: this.cardData.content,
cover: this.cardData.cover,
cardId: this.cardData.id,
});
//
this.updateVideoStats();
} catch (error) {
console.error("视频播放失败:", error);
uni.showToast({
title: "视频播放失败,请稍后再试",
icon: "none",
});
}
}
},
//
handleImagePreview(index) {
try {
// 使uni-appAPI
uni.previewImage({
current: index,
urls: this.cardData.images,
longPressActions: {
itemList: ["保存图片", "分享图片"],
success: (res) => {
const { tapIndex } = res;
if (tapIndex === 0) {
//
this.saveImage(this.cardData.images[index]);
} else if (tapIndex === 1) {
//
this.shareImage(this.cardData.images[index]);
}
},
},
});
//
this.$emit("image-preview", {
index,
images: this.cardData.images,
cardId: this.cardData.id,
});
} catch (error) {
console.error("图片预览失败:", error);
}
},
//
saveImage(url) {
uni.showLoading({ title: "正在保存..." });
uni.downloadFile({
url,
success: (res) => {
if (res.statusCode === 200) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.showToast({ title: "保存成功" });
},
fail: (err) => {
console.error("保存失败:", err);
uni.showToast({ title: "保存失败", icon: "none" });
},
});
}
},
fail: () => {
uni.showToast({ title: "下载图片失败", icon: "none" });
},
complete: () => {
uni.hideLoading();
},
});
},
//
shareImage(url) {
//
// #ifdef APP-PLUS
plus.share.sendWithSystem({
type: "image",
pictures: [url],
});
// #endif
// #ifdef H5
// H5API
// #endif
// #ifdef MP
// 使API
uni.showToast({ title: "请使用右上角分享", icon: "none" });
// #endif
},
//
getImageLayoutClass() {
const count = this.cardData.images.length;
if (count === 1) return "single-image";
if (count === 2) return "double-image";
if (count === 3) return "triple-image";
if (count === 4) return "four-image";
if (count > 4) return "multi-image";
return "";
},
//
handleForward() {
this.isForwarded = !this.isForwarded;
//
uni.showShareMenu({
withShareTicket: true,
menus: ["shareAppMessage", "shareTimeline"],
});
//
this.$emit("forward", {
cardData: this.cardData,
isForwarded: this.isForwarded,
});
// APP
// #ifdef APP-PLUS
uni.share({
provider: "weixin",
scene: "WXSceneSession",
type: 0,
title: this.cardData.content,
summary: this.cardData.content,
imageUrl: this.isVideo ? this.cardData.cover : this.cardData.images[0],
success: function (res) {
console.log("分享成功:" + JSON.stringify(res));
},
fail: function (err) {
console.log("分享失败:" + JSON.stringify(err));
},
});
// #endif
},
//
handleComment() {
//
this.$emit("comment", {
cardData: this.cardData,
});
//
uni.navigateTo({
url: `/pages/comment/index?id=${this.cardData.id}&type=${this.cardData.type}`,
});
},
//
handleLike() {
//
this.isLiked = !this.isLiked;
//
const newStats = { ...this.cardData.stats };
if (this.isLiked) {
newStats.like += 1;
} else {
newStats.like = Math.max(0, newStats.like - 1);
}
//
this.$emit("like", {
cardData: this.cardData,
isLiked: this.isLiked,
newStats,
});
//
this.updateLikeStatus();
},
//
handleFavorite() {
//
this.isFavorited = !this.isFavorited;
//
const newStats = { ...this.cardData.stats };
if (this.isFavorited) {
newStats.favorite += 1;
} else {
newStats.favorite = Math.max(0, newStats.favorite - 1);
}
//
this.$emit("favorite", {
cardData: this.cardData,
isFavorited: this.isFavorited,
newStats,
});
//
this.updateFavoriteStatus();
},
//
updateLikeStatus() {
// API
// API
const url = this.isLiked ? "/api/like/add" : "/api/like/cancel";
uni.request({
url,
method: "POST",
data: {
contentId: this.cardData.id,
contentType: this.cardData.type,
},
success: (res) => {
console.log("点赞状态更新成功", res);
},
fail: (err) => {
console.error("点赞状态更新失败", err);
//
this.isLiked = !this.isLiked;
},
});
},
//
updateFavoriteStatus() {
// API
// API
const url = this.isFavorited
? "/api/favorite/add"
: "/api/favorite/cancel";
uni.request({
url,
method: "POST",
data: {
contentId: this.cardData.id,
contentType: this.cardData.type,
},
success: (res) => {
console.log("收藏状态更新成功", res);
},
fail: (err) => {
console.error("收藏状态更新失败", err);
//
this.isFavorited = !this.isFavorited;
},
});
},
//
savePlayHistory() {
//
try {
const historyList = uni.getStorageSync("videoPlayHistory") || [];
const now = new Date().getTime();
//
const index = historyList.findIndex(
(item) => item.id === this.cardData.id
);
if (index > -1) {
//
historyList[index].lastPlayTime = now;
historyList[index].playCount += 1;
} else {
//
historyList.push({
id: this.cardData.id,
title: this.cardData.content,
cover: this.cardData.cover,
lastPlayTime: now,
playCount: 1,
});
}
//
uni.setStorageSync("videoPlayHistory", historyList);
} catch (e) {
console.error("保存播放历史失败", e);
}
},
//
updateVideoStats() {
// API
uni.request({
url: "/api/video/view",
method: "POST",
data: {
videoId: this.cardData.id,
},
success: (res) => {
console.log("视频播放统计更新成功", res);
},
fail: (err) => {
console.error("视频播放统计更新失败", err);
},
});
},
//
handleAction(action) {
switch(action) {
case "forward":
this.handleForward();
break;
case "comment":
this.handleComment();
break;
case "like":
this.handleLike();
break;
case "favorite":
this.handleFavorite();
break;
}
}
},
};
</script>
<style scoped lang="scss">
.content-card {
background-color: #fff;
border-radius: 24rpx;
padding: 24rpx;
margin-bottom: 24rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
.user-info {
display: flex;
align-items: center;
margin-bottom: 24rpx;
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 16rpx;
}
.user-detail {
flex: 1;
.username {
font-size: 30rpx;
font-weight: 500;
color: #333;
display: block;
line-height: 1.2;
}
.user-meta {
font-size: 24rpx;
color: #999;
display: block;
line-height: 1.2;
margin-top: 6rpx;
}
}
.follow-btn {
display: flex;
align-items: center;
justify-content: center;
background-color: #f5f5f5;
border-radius: 30rpx;
padding: 8rpx 16rpx;
text {
font-size: 24rpx;
color: #666;
margin-left: 4rpx;
}
}
}
.content-text {
font-size: 28rpx;
color: #333;
line-height: 1.5;
margin-bottom: 24rpx;
}
.media-content {
margin-bottom: 24rpx;
width: 100%;
//
.video-container {
position: relative;
width: 100%;
border-radius: 8rpx;
overflow: hidden;
.video-cover {
width: 100%;
height: 400rpx;
display: block;
}
.video-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.2);
.video-duration {
position: absolute;
right: 16rpx;
bottom: 16rpx;
color: #fff;
font-size: 24rpx;
background-color: rgba(0, 0, 0, 0.5);
padding: 4rpx 8rpx;
border-radius: 4rpx;
}
}
}
//
.image-grid {
display: flex;
flex-wrap: wrap;
.grid-image {
border-radius: 8rpx;
background-color: #f5f5f5;
}
&.single-image {
.grid-image {
width: 100%;
max-height: 400rpx;
}
}
&.double-image {
justify-content: space-between;
.grid-image {
width: 49%;
height: 240rpx;
}
}
&.triple-image {
justify-content: space-between;
.grid-image {
width: 31%;
height: 180rpx;
}
}
&.four-image {
justify-content: space-between;
.grid-image {
width: 49%;
height: 180rpx;
margin-bottom: 10rpx;
}
}
&.multi-image {
justify-content: space-between;
.grid-image {
width: 31%;
height: 180rpx;
margin-bottom: 10rpx;
}
}
}
}
.interaction-bar {
display: flex;
justify-content: space-between;
margin-top: 16rpx;
padding: 0 20rpx;
.action-item {
display: flex;
align-items: center;
text {
font-size: 24rpx;
color: #999;
margin-left: 8rpx;
}
}
}
}
</style>

698
components/Information.vue Normal file
View File

@ -0,0 +1,698 @@
<template>
<view>
<view
class="flex-col Information"
style="position: relative; height: 100%"
@tap="btnShow = false"
>
<view class="flex-col">
<template v-if="list.length <= 0">
<view
v-if="type != 2 && type != 3 && !noShowEmpty"
style="height: 1rem"
></view>
<!-- <u-empty v-if="type != 2 && type != 3" text="暂无数据" mode="list"></u-empty> -->
<no-data v-if="type != 2 && type != 3" text="暂无数据"></no-data>
</template>
<template v-else v-for="(item, index) in list">
<view
class="flex-col list-item"
:class="{
'border-radius': borderRadius,
'border-noPadding': borderNoPadding,
}"
:key="index"
>
<view style="height: 0.1rem" v-if="item.isState"></view>
<text class="shield" v-if="item.isState">
<u-icon size="30" name="error-circle-fill"></u-icon
>该信息已被管理员屏蔽
</text>
<view class="flex-row group_8 view">
<u-avatar
@click="toDetil(item.userId)"
size="0.3rem"
:src="$u.http.config.imgUrl + item.userHead"
class="image_3"
></u-avatar>
<text class="text_8 text_43">{{ item.userName }}</text>
<text class="text_9">{{ item.creationTime }}</text>
<text class="text_11">{{ item.schoolName }}</text>
<u-icon
v-if="isDel"
name="more-dot-fill"
color="#ccc"
size="40"
style="position: absolute; right: 0"
@click="showDelFn(item)"
></u-icon>
</view>
<view class="flex-col group_9" @click="onDetails(item)">
<text class="text_14" v-if="type != 2">{{
item.title.length > 15
? item.title.slice(0, 15) + "..."
: item.title
}}</text>
<text class="text_14" v-else>{{ item.title }}</text>
<template v-if="!item.isForward">
<view v-if="!item.isDelete">
<text class="text_15" v-if="type != 2">
{{
item.content.length > 50
? item.content.slice(0, 50) + "..."
: item.content
}}
</text>
<text class="text_15" v-else>
{{ item.content }}
</text>
<view
class="imgList flex-col"
v-if="item.imageUrl.indexOf('.') > 0"
>
<view class="flex-row">
<image
@click.stop="clickImg(v)"
v-for="(v, i) in item.imageUrl.split(',')"
:key="i"
:src="v ? $u.http.config.imgUrl + v : ''"
class="image_10"
/>
</view>
</view>
<view class="flex-row" v-if="item.sysSignStr">
<text
class="text_16"
v-for="(v, i) in item.sysSignStr.split(',')"
@click.stop="onSign(v)"
:key="i"
>{{ v ? "#" + v : "" }}</text
>
</view>
</view>
<view
v-else
class="flex-row justify-between items-center delete-item"
>
<text class="item-text">哎呀此页面已被发布者删除</text>
<u-icon
class="icon-1"
name="trash"
color="black"
size="50"
@click="onDelCollet(item)"
></u-icon>
</view>
</template>
<template v-else>
<view
style="
background: #f8f8f8;
padding: 0.1rem;
margin-top: 0.1rem;
"
class="flex-col group_9"
>
<text class="text_14" v-if="type != 2">{{
item.forwardModel.forwardTitle.length > 15
? item.forwardModel.forwardTitle.slice(0, 15) + "..."
: item.forwardModel.forwardTitle
}}</text>
<text class="text_14" v-else>{{
item.forwardModel.forwardTitle
}}</text>
<text class="text_15" v-if="type != 2">
{{
item.content.length > 50
? item.content.slice(0, 50) + "..."
: item.content
}}
</text>
<text class="text_15" v-else>
{{ item.content }}
</text>
<view
class="imgList flex-col"
v-if="item.forwardModel.forwardImageUrl.indexOf('.') > 0"
>
<view class="flex-row">
<image
style="width: 32%; height: 0auto"
@click.stop="clickImg(v)"
v-for="(
v, i
) in item.forwardModel.forwardImageUrl.split(',')"
v-if="i < 9"
:key="i"
:src="v ? $u.http.config.imgUrl + v : ''"
class="image_10"
/>
</view>
</view>
<view class="flex-row" v-if="item.sysSignStr">
<text
@click.stop="onSign(v)"
class="text_16"
v-for="(v, i) in item.sysSignStr.split(',')"
:key="i"
>{{ v ? "#" + v : "" }}</text
>
</view>
</view>
</template>
</view>
<view class="flex-row">
<view class="flex-row group_21" v-if="type != 2 && type != 3">
<view
class="flex-row equal-division-item_1"
@click="onForward(item)"
v-if="!item.isForward && type != 0"
>
<image
src="/static/common/img/homepage/reply.png"
class="image_8"
/>
<text class="text_19">{{ item.forwardCount }}</text>
</view>
<view class="flex-row group_10" @click="onDetails(item)">
<image
src="/static/common/img/homepage/comment.png"
class="image_7"
/>
<text class="text_18">{{ item.commentCount }}</text>
</view>
<view class="flex-row group_20">
<!-- <u-icon style="font-size:0.22rem;color:#b4b6bd" v-if="item.isCllect == false"
name="star" @click="onStar(item)"></u-icon> -->
<image
style="width: 42rpx; height: 42rpx"
src="/static/common/img/homepage/star.png"
v-if="item.isCllect == false"
name="star"
@click="onStar(item)"
></image>
<u-icon
style="font-size: 40rpx; color: #ffc300"
v-else
name="star-fill"
@click="onStar(item)"
></u-icon>
<text class="text_17">{{ item.collectCount }}</text>
</view>
<!--
<view
class="flex-row group_20"
v-if="isDel"
@tap="onDelete(item)"
>
<image
src="/static/common/img/homepage/trash.png"
style="width: 42rpx; height: 42rpx"
/>
</view>
-->
</view>
</view>
</view>
</template>
</view>
<template v-if="bottom && list.length > 0">
<view style="height: 0.46rem"></view>
<u-divider
style="bottom: 0.2rem; position: absolute; background: transparent"
color="#6d6d6d"
half-width="200"
border-color="#6d6d6d"
>
{{ text ? text : "已经到底了" }}
</u-divider>
</template>
<u-popup v-model="showDel" mode="bottom" :border-radius="40">
<view class="popup-box">
<view class="popup-btn" @click="delItem">删除</view>
<view class="popup-line"></view>
<view class="popup-btn" @click="showDel = false">取消</view>
</view>
</u-popup>
<u-toast ref="uToast" />
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
</view>
</view>
</template>
<script>
import NoData from "components/NoData.vue";
export default {
name: "information",
components: {
NoData,
},
// listarray typenumber bottom nolink
props: [
"list",
"type",
"bottom",
"text",
"schoolId",
"nolink",
"route",
"flag",
"id",
"isEllipsis",
"isDel",
"borderRadius",
"borderNoPadding",
"noShowEmpty",
],
data() {
return {
isindex: -1,
btnShow: false,
state: false,
currentRow: {},
showDel: false,
delRow: {},
};
},
mounted() {},
onLoad() {
this.state = true;
},
methods: {
showDelFn(item) {
this.delRow = item;
this.showDel = true;
},
delItem() {
this.showDel = false;
this.$emit("onDelete", {
type: this.delRow.type,
id: this.delRow.id,
});
},
//
onDetails(item) {
console.log(JSON.parse(JSON.stringify(item)), "item-JSON-");
this.currentRow = item;
uni.$off("echoList");
uni.$on("echoList", (result) => {
// console.log('echoList----')
//
if (result.type === "star") {
console.log("%c%s", "color:red", "收藏回显");
console.log(result, "result");
this.currentRow.isCllect = result.data.isCllect;
console.log(result.isCllect, "result.isCllect");
if (result.data.isCllect === true) {
this.currentRow.collectCount++;
}
if (result.data.isCllect === false) {
this.currentRow.collectCount && this.currentRow.collectCount--;
}
}
//
if (result.type === "evaluate") {
console.log("%c%s", "color:red", "评价回显");
console.log(result, "result");
this.currentRow.commentCount = result.data.commentCount;
}
});
// return
if (this.nolink) {
return;
}
if (item.isDelete) {
return;
}
item.flag = this.flag;
item.route = this.route;
item.mytype = this.type;
item.myschoolId = this.id;
if (this.type == 3) {
item.mytype = item.type;
}
// return
this.$u.route({
url: "pages/AlumniCircle/ArticleDetails/ArticleDetails",
params: {
data: JSON.stringify(item),
isDel:this.isDel
},
});
},
toDetil(id) {
this.$u.route({
url: "/pages/AlumniCircle/userDetail/userDetail?id=" + id + "&type=4",
});
},
//
onStar(item) {
item.type = this.type;
this.$emit("onStar", item);
},
//
async onForward(item) {
console.log(JSON.parse(JSON.stringify(item)), "item-JSON-");
// return
this.currentRow = item;
uni.$off("echoList");
uni.$on("echoList", (result) => {
console.log("%c%s", "color:red", "echoList----");
//
if (result.type === "forward") {
console.log("%c%s", "color:red", "转发回显");
console.log(result, "result");
this.currentRow.forwardCount++;
}
});
//
const req = {
userId: this.vuex_user.id,
};
const res = await this.$u.apiList.MyPage(req);
console.log(JSON.parse(JSON.stringify(res)), "res");
const edcationList = res.edcationList;
if (!edcationList.length) {
return this.$refs.uToast.show({
title: "认证后可进行转发操作",
type: "none",
});
}
const findRow = edcationList.find((x) => x.isSelected === true);
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "认证后可进行转发操作",
type: "none",
});
}
if (this.schoolId) {
item.schoolId = this.schoolId;
}
item.route = this.route;
if (item.isForward) return;
this.$u.route({
url: "pages/AlumniCircle/forward/forward",
params: {
data: JSON.stringify(item),
},
});
},
//
clickImg(item) {
if (this.route == 3 || this.nolink) {
item = this.$u.http.config.imgUrl + item;
var images = [];
images.push(item);
uni.previewImage({
// => ['']
current: 0,
urls: images,
});
}
this.$emit("clickImg", item);
},
onSign(v) {
this.$emit("onSign", v);
},
//
onDelete(item) {
this.$emit("onDelete", {
type: item.type,
id: item.id,
});
},
//
onDelCollet(item) {
this.$emit("onDelCollet", item.collectId);
},
},
};
</script>
<style lang="scss">
.btns {
background-color: #fff;
box-shadow: 0 0 0.05rem #ccc;
border-radius: 0.05rem;
position: absolute;
bottom: 100%;
white-space: nowrap;
.item {
line-height: 2;
padding: 0 0.1rem;
}
}
::v-deep .u-divider-text {
line-height: 2;
}
.Information {
background-color: rgb(246, 247, 250);
// margin-top: 0.1rem;
.list-item {
padding: 0.18rem 0.2rem;
background-color: rgb(255, 255, 255);
margin-bottom: 0.1rem;
position: relative;
width: 100%;
// width: calc(100% - 50rpx);
// margin: 0.1rem auto 0;
// border-radius: 24rpx 24rpx 24rpx 24rpx;
// border: 2rpx solid #F7F6F9;
overflow: hidden;
.shield {
position: absolute;
top: 0.05rem;
width: 100%;
color: #ff9b00;
left: 0.1rem;
}
.view {
margin-right: 0.051rem;
}
.group_9 {
// margin-right: 0.13rem;
margin-top: 0.1rem;
width: 100%;
.text_14 {
align-self: flex-start;
color: rgb(2, 2, 2);
font-size: 0.16rem;
font-family: Adobe Heiti Std;
line-height: 2;
width: 100%;
word-wrap: break-word;
}
.text_15 {
// margin-top: 0.11rem;
color: rgb(73, 76, 87);
font-size: 0.14rem;
font-family: Adobe Heiti Std;
line-height: 0.24rem;
text-indent: 0.2rem;
word-wrap: break-word;
}
.text_16 {
margin-left: 0.04rem;
margin-top: 0.12rem;
align-self: flex-start;
// color: rgb(44, 109, 255);
color: #298bc3;
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
}
.group_21 {
margin-top: 0.1rem;
justify-content: space-between;
width: 90%;
margin: 0.1rem auto 0;
.group_20 {
justify-content: center;
flex: 1;
// margin: 0.025rem 0;
.image_6 {
flex-shrink: 0;
width: 42rpx;
height: 42rpx;
}
.text_17 {
margin-left: 5rpx;
margin-top: 8rpx;
color: rgb(180, 182, 189);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.11rem;
}
}
.group_10 {
justify-content: center;
flex: 1;
align-self: center;
.image_7 {
flex-shrink: 0;
width: 42rpx;
height: 42rpx;
}
.text_18 {
margin-left: 5rpx;
margin-top: 8rpx;
color: rgb(180, 182, 189);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.11rem;
}
}
.equal-division-item_1 {
flex: 1;
justify-content: center;
align-self: center;
.image_8 {
width: 42rpx;
height: 42rpx;
}
.text_19 {
margin-left: 5rpx;
margin-top: 8rpx;
color: rgb(180, 182, 189);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.11rem;
}
}
}
}
.border-radius {
border-radius: 24rpx;
width: calc(100% - 48rpx);
margin: 0.1rem auto 0;
}
.border-noPadding {
border-radius: 24rpx;
margin: 0.1rem auto 0;
}
.list-item:last-child {
margin-bottom: 0;
}
.imgList {
padding-top: 0.1rem;
.flex-row {
flex-wrap: wrap;
}
image {
width: 33%;
height: 1rem;
margin: 0 0.5% 0.5% 0;
}
image:nth-child(3n) {
margin-right: 0;
}
}
.delete-item {
box-sizing: border-box;
.item-text {
padding-top: 0.05rem;
color: #000000;
}
.icon-1 {
}
}
.group_8 {
height: 0.32rem;
position: relative;
.image_3 {
width: 0.3rem !important;
height: 0.3rem !important;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
}
.text_8 {
color: rgb(2, 2, 2);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
.text_43 {
position: absolute;
left: 0.37rem;
top: 0.02rem;
}
.text_9 {
color: rgb(184, 184, 184);
font-size: 0.12rem;
font-family: PingFang;
line-height: 0.12rem;
position: absolute;
left: 0.37rem;
bottom: 0;
}
.text_11 {
color: rgb(184, 184, 184);
font-size: 0.12rem;
font-family: PingFang;
line-height: 0.12rem;
position: absolute;
left: 0.97rem;
bottom: 0;
}
.text_20 {
position: absolute;
left: 0.36rem;
top: 0.02rem;
}
}
}
.popup-box {
padding: 10rpx 0;
.popup-btn {
font-size: 34rpx;
text-align: center;
padding: 30rpx;
}
.popup-line {
height: 20rpx;
background: #f7f7f8;
}
}
</style>

117
components/NoData copy.vue Normal file
View File

@ -0,0 +1,117 @@
<template>
<view class="empty-container">
<image :src="getImage" class="empty-image" mode="widthFix"></image>
<text class="empty-text">{{ text }}</text>
</view>
</template>
<script>
//
import noDataDefault from "@/static/common/img/noData/no-data.png";
//
import noDataSearch from "@/static/common/img/noData/no-search.png";
//
import noDataMessage from "@/static/common/img/noData/no-message.png";
//
import errorNet from "@/static/common/img/noData/error-net.png";
//
import errorData from "@/static/common/img/noData/error-data.png";
//
import maintenance from "@/static/common/img/noData/maintenance.png";
//
import noAttachmentResume from "@/static/common/img/noData/no-attachment-resume.png";
//
import noCollection from "@/static/common/img/noData/no-collection.png";
//
import noComments from "@/static/common/img/noData/no-comments.png";
//
import noContent from "@/static/common/img/noData/no-content.png";
//
import noFile from "@/static/common/img/noData/no-file.png";
//
import noFriends from "@/static/common/img/noData/no-friends.png";
//
import noInternet from "@/static/common/img/noData/no-internet.png";
//
import noPermissions from "@/static/common/img/noData/no-permissions.png";
//
import noPicture from "@/static/common/img/noData/no-picture.png";
export default {
name: "NoData",
props: {
//
type: {
type: String,
default: "default",
},
// ""
text: {
type: String,
default: "暂无数据",
},
},
computed: {
getImage() {
const imageMap = {
default: noDataDefault,
search: noDataSearch,
message: noDataMessage,
errorNet: errorNet,
errorData: errorData,
maintenance: maintenance,
resume: noAttachmentResume,
collection: noCollection,
comments: noComments,
content: noContent,
file: noFile,
friends: noFriends,
internet: noInternet,
permissions: noPermissions,
picture: noPicture,
};
return imageMap[this.type] || imageMap.default;
},
},
data: {
/*
<no-data type="default" text="暂无数据" />
<no-data type="errorNet" text="网络错误" />
<no-data type="search" text="暂无搜索内容" />
<no-data type="errorData" text="数据加载失败" />
<no-data type="message" text="暂无消息" />
<no-data type="maintenance" text="系统维护中" />
<no-data type="resume" text="暂无简历附件" />
<no-data type="collection" text="暂无收藏" />
<no-data type="comments" text="暂无评论" />
<no-data type="content" text="暂无内容" />
<no-data type="file" text="暂无文件" />
<no-data type="friends" text="暂无好友" />
<no-data type="internet" text="无网络连接" />
<no-data type="permissions" text="暂无权限" />
<no-data type="picture" text="暂无图片" /> */
},
};
</script>
<style scoped>
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20rpx;
text-align: center;
}
.empty-image {
width: 400rpx;
height: 400rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 32rpx;
color: #000;
}
</style>

117
components/NoData.vue Normal file
View File

@ -0,0 +1,117 @@
<template>
<view class="empty-container">
<image :src="getImage" class="empty-image" mode="widthFix"></image>
<!-- <text class="empty-text">{{ text }}</text> -->
</view>
</template>
<script>
//
import noDataDefault from "@/static/common/img/noDataNew/no-data.png";
//
import noDataSearch from "@/static/common/img/noDataNew/no-search.png";
//
import noDataMessage from "@/static/common/img/noDataNew/no-message.png";
//
import errorNet from "@/static/common/img/noDataNew/error-net.png";
//
import errorData from "@/static/common/img/noDataNew/error-data.png";
//
import maintenance from "@/static/common/img/noDataNew/maintenance.png";
//
import noAttachmentResume from "@/static/common/img/noDataNew/no-attachment-resume.png";
//
import noCollection from "@/static/common/img/noDataNew/no-collection.png";
//
import noComments from "@/static/common/img/noDataNew/no-comments.png";
//
import noContent from "@/static/common/img/noDataNew/no-content.png";
//
import noFile from "@/static/common/img/noDataNew/no-file.png";
//
import noFriends from "@/static/common/img/noDataNew/no-friends.png";
//
import noInternet from "@/static/common/img/noDataNew/no-internet.png";
//
import noPermissions from "@/static/common/img/noDataNew/no-permissions.png";
//
import noPicture from "@/static/common/img/noDataNew/no-picture.png";
export default {
name: "NoData",
props: {
//
type: {
type: String,
default: "default",
},
// ""
text: {
type: String,
default: "暂无数据",
},
},
computed: {
getImage() {
const imageMap = {
default: noDataDefault,
search: noDataSearch,
message: noDataMessage,
errorNet: errorNet,
errorData: errorData,
maintenance: maintenance,
resume: noAttachmentResume,
collection: noCollection,
comments: noComments,
content: noContent,
file: noFile,
friends: noFriends,
internet: noInternet,
permissions: noPermissions,
picture: noPicture,
};
return imageMap[this.type] || imageMap.default;
},
},
data: {
/*
<no-data type="default" text="暂无数据" />
<no-data type="errorNet" text="网络错误" />
<no-data type="search" text="暂无搜索内容" />
<no-data type="errorData" text="数据加载失败" />
<no-data type="message" text="暂无消息" />
<no-data type="maintenance" text="系统维护中" />
<no-data type="resume" text="暂无简历附件" />
<no-data type="collection" text="暂无收藏" />
<no-data type="comments" text="暂无评论" />
<no-data type="content" text="暂无内容" />
<no-data type="file" text="暂无文件" />
<no-data type="friends" text="暂无好友" />
<no-data type="internet" text="无网络连接" />
<no-data type="permissions" text="暂无权限" />
<no-data type="picture" text="暂无图片" /> */
},
};
</script>
<style scoped>
.empty-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* padding: 20rpx; */
text-align: center;
}
.empty-image {
width: 400rpx;
height: 300rpx;
margin-bottom: 20rpx;
}
.empty-text {
font-size: 32rpx;
color: #000;
}
</style>

164
components/drag-button.vue Normal file
View File

@ -0,0 +1,164 @@
<template>
<view>
<!-- v-if="current==0&&vuex_user.isAttestationGLY&&vuex_user.isAttestationJZG&&(vuex_user.isAttestationXY||true) || current==1&&(vuex_user.isAttestationXY||true)" -->
<view
v-if="false"
id="_drag_button"
class="drag"
:style="'left: ' + left + 'px; top:' + top + 'px;transform: translateY(-60%);'"
@touchstart="touchstart"
@touchmove.stop.prevent="touchmove"
@touchend.stop="touchend"
@click.stop.prevent="click"
:class="{ transition: isDock && !isMove }"
>
<u-icon name="plus" size="50" color="#ccc"></u-icon>
<!-- <text>{{ text }}</text> -->
</view>
<view
id="_drag_button"
class="drag"
:style="'left: ' + left + 'px; top:' + (top + 0)+ 'px;transform: translateY(60%);'"
@touchstart="touchstart"
@touchmove.stop.prevent="touchmove"
@touchend.stop="touchend"
@click.stop.prevent="reload"
:class="{ transition: isDock && !isMove }"
>
<u-icon name="reload" size="50" color="#ccc"></u-icon>
<!-- <text>{{ text }}</text> -->
</view>
</view>
</template>
<script>
export default {
name: 'drag-button',
props: {
current:{
type: Number,
default: 0
},
isDock: {
type: Boolean,
default: false
},
existTabBar: {
type: Boolean,
default: false
}
},
data() {
return {
top: 0,
left: 0,
width: 0,
height: 0,
offsetWidth: 0,
offsetHeight: 0,
windowWidth: 0,
windowHeight: 0,
isMove: true,
edge: 70,
wrap:10,
text: '公告' //(1-3)
};
},
mounted() {
const sys = uni.getSystemInfoSync();
this.windowWidth = sys.windowWidth;
this.windowHeight = sys.windowHeight;
// #ifdef APP-PLUS
this.existTabBar && (this.windowHeight -= 50);
// #endif
if (sys.windowTop) {
this.windowHeight += sys.windowTop;
}
const query = uni.createSelectorQuery().in(this);
query
.select('#_drag_button')
.boundingClientRect(data => {
this.width = data.width;
this.height = data.height;
this.offsetWidth = data.width / 2;
this.offsetHeight = data.height / 2;
this.left = this.windowWidth - this.width - this.wrap;
this.top = ((this.windowHeight - this.height - this.edge) * 3) / 4;
})
.exec();
},
methods: {
click() {
this.$emit('btnClick');
},
reload(){
this.$emit('reload');
},
touchstart(e) {
this.$emit('btnTouchstart');
},
touchmove(e) {
//
if (e.touches.length !== 1) {
return false;
}
this.isMove = true;
this.left = e.touches[0].clientX - this.offsetWidth ;
let clientY = e.touches[0].clientY - this.offsetHeight -(this.height);
// #ifdef H5
clientY += this.height;
// #endif
let edgeBottom = this.windowHeight - this.height - this.edge;
//
if (clientY < this.edge) {
this.top = this.edge;
} else if (clientY > edgeBottom) {
this.top = edgeBottom;
} else {
this.top = clientY;
}
},
touchend(e) {
if (this.isDock) {
let edgeRigth = this.windowWidth - this.width - this.wrap;
if (this.left < this.windowWidth / 2 - this.offsetWidth) {
this.left = this.wrap;
} else {
this.left = edgeRigth;
}
}
this.isMove = false;
this.$emit('btnTouchend');
}
}
};
</script>
<style lang="scss">
.drag {
display: flex;
justify-content: center;
align-items: center;
// background-color: rgba(0, 0, 0, 0.5);
background-color: #FFFFFF;
box-shadow: 0 0 6upx rgba(0, 0, 0, 0.4);
color: $uni-text-color-inverse;
width: 80upx;
height: 80upx;
border-radius: 50%;
font-size: $uni-font-size-sm;
position: fixed;
z-index: 99;
&.transition {
transition: left 0.3s ease, top 0.3s ease;
}
}
</style>

View File

@ -0,0 +1,277 @@
/**
* covert canvas to image
* and save the image file
*/
var Canvas2Image = function () {
// check if support sth.
var $support = function () {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
return {
canvas: !!ctx,
imageData: !!ctx.getImageData,
dataURL: !!canvas.toDataURL,
btoa: !!window.btoa
};
}();
var downloadMime = 'image/octet-stream';
function scaleCanvas (canvas, width, height) {
var w = canvas.width,
h = canvas.height;
if (width == undefined) {
width = w;
}
if (height == undefined) {
height = h;
}
var retCanvas = document.createElement('canvas');
var retCtx = retCanvas.getContext('2d');
retCanvas.width = width;
retCanvas.height = height;
retCtx.drawImage(canvas, 0, 0, w, h, 0, 0, width, height);
return retCanvas;
}
function getDataURL (canvas, type, width, height) {
canvas = scaleCanvas(canvas, width, height);
return canvas.toDataURL(type);
}
function saveFile (strData,filename) {
var save_link = document.createElement('a');
save_link.href = strData;
save_link.download = filename;
var event = new MouseEvent('click',{"bubbles":false, "cancelable":false});
save_link.dispatchEvent(event);
}
function genImage(strData) {
var img = document.createElement('img');
img.src = strData;
return img;
}
function fixType (type) {
type = type.toLowerCase().replace(/jpg/i, 'jpeg');
var r = type.match(/png|jpeg|bmp|gif/)[0];
return 'image/' + r;
}
function encodeData (data) {
if (!window.btoa) { throw 'btoa undefined' }
var str = '';
if (typeof data == 'string') {
str = data;
} else {
for (var i = 0; i < data.length; i ++) {
str += String.fromCharCode(data[i]);
}
}
return btoa(str);
}
function getImageData (canvas) {
var w = canvas.width,
h = canvas.height;
return canvas.getContext('2d').getImageData(0, 0, w, h);
}
function makeURI (strData, type) {
return 'data:' + type + ';base64,' + strData;
}
/**
* create bitmap image
* 按照规则生成图片响应头和响应体
*/
var genBitmapImage = function (oData) {
//
// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
//
var biWidth = oData.width;
var biHeight = oData.height;
var biSizeImage = biWidth * biHeight * 3;
var bfSize = biSizeImage + 54; // total header size = 54 bytes
//
// typedef struct tagBITMAPFILEHEADER {
// WORD bfType;
// DWORD bfSize;
// WORD bfReserved1;
// WORD bfReserved2;
// DWORD bfOffBits;
// } BITMAPFILEHEADER;
//
var BITMAPFILEHEADER = [
// WORD bfType -- The file type signature; must be "BM"
0x42, 0x4D,
// DWORD bfSize -- The size, in bytes, of the bitmap file
bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
// WORD bfReserved1 -- Reserved; must be zero
0, 0,
// WORD bfReserved2 -- Reserved; must be zero
0, 0,
// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
54, 0, 0, 0
];
//
// typedef struct tagBITMAPINFOHEADER {
// DWORD biSize;
// LONG biWidth;
// LONG biHeight;
// WORD biPlanes;
// WORD biBitCount;
// DWORD biCompression;
// DWORD biSizeImage;
// LONG biXPelsPerMeter;
// LONG biYPelsPerMeter;
// DWORD biClrUsed;
// DWORD biClrImportant;
// } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
//
var BITMAPINFOHEADER = [
// DWORD biSize -- The number of bytes required by the structure
40, 0, 0, 0,
// LONG biWidth -- The width of the bitmap, in pixels
biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
// LONG biHeight -- The height of the bitmap, in pixels
biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
1, 0,
// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
// has a maximum of 2^24 colors (16777216, Truecolor)
24, 0,
// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
0, 0, 0, 0,
// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
// LONG biXPelsPerMeter, unused
0,0,0,0,
// LONG biYPelsPerMeter, unused
0,0,0,0,
// DWORD biClrUsed, the number of color indexes of palette, unused
0,0,0,0,
// DWORD biClrImportant, unused
0,0,0,0
];
var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
var aImgData = oData.data;
var strPixelData = '';
var biWidth4 = biWidth<<2;
var y = biHeight;
var fromCharCode = String.fromCharCode;
do {
var iOffsetY = biWidth4*(y-1);
var strPixelRow = '';
for (var x = 0; x < biWidth; x++) {
var iOffsetX = x<<2;
strPixelRow += fromCharCode(aImgData[iOffsetY+iOffsetX+2]) +
fromCharCode(aImgData[iOffsetY+iOffsetX+1]) +
fromCharCode(aImgData[iOffsetY+iOffsetX]);
}
for (var c = 0; c < iPadding; c++) {
strPixelRow += String.fromCharCode(0);
}
strPixelData += strPixelRow;
} while (--y);
var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
return strEncoded;
};
/**
* [saveAsImage]
* @param {[obj]} canvas [canvasElement]
* @param {[Number]} width [optional] png width
* @param {[Number]} height [optional] png height
* @param {[String]} type [image type]
* @param {[String]} filename [image filename]
* @return {[type]} [description]
*/
var saveAsImage = function (canvas, width, height, type,filename) {
if ($support.canvas && $support.dataURL) {
if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
if (type == undefined) { type = 'png'; }
filename = filename == undefined||filename.length === 0 ?Date.now()+'.'+type: filename+'.'+type
type = fixType(type);
if (/bmp/.test(type)) {
var data = getImageData(scaleCanvas(canvas, width, height));
var strData = genBitmapImage(data);
saveFile(makeURI(strData, downloadMimedownloadMime),filename);
} else {
var strData = getDataURL(canvas, type, width, height);
saveFile(strData.replace(type, downloadMime),filename);
}
}
};
var convertToImage = function (canvas, width, height, type) {
if ($support.canvas && $support.dataURL) {
if (typeof canvas == "string") { canvas = document.getElementById(canvas); }
if (type == undefined) { type = 'png'; }
type = fixType(type);
if (/bmp/.test(type)) {
var data = getImageData(scaleCanvas(canvas, width, height));
var strData = genBitmapImage(data);
return genImage(makeURI(strData, 'image/bmp'));
} else {
var strData = getDataURL(canvas, type, width, height);
return genImage(strData);
}
}
};
return {
saveAsImage: saveAsImage,
saveAsPNG: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, 'png',fileName);
},
saveAsJPEG: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, 'jpeg',fileName);
},
saveAsGIF: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, 'gif',fileName);
},
saveAsBMP: function (canvas, width, height, fileName) {
return saveAsImage(canvas, width, height, 'bmp',fileName);
},
convertToImage: convertToImage,
convertToPNG: function (canvas, width, height) {
return convertToImage(canvas, width, height, 'png');
},
convertToJPEG: function (canvas, width, height) {
return convertToImage(canvas, width, height, 'jpeg');
},
convertToGIF: function (canvas, width, height) {
return convertToImage(canvas, width, height, 'gif');
},
convertToBMP: function (canvas, width, height) {
return convertToImage(canvas, width, height, 'bmp');
}
};
}();
export default Canvas2Image

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,34 @@
import html2canvas from '@/components/dyw-html2image/html2canvas.min.js'
import canvas2Image from '@/components/dyw-html2image/canvas2image.js' // canvas源码不支持import导入在源码的最后添加export default使得可以将canvas2image对象import进来
/**
* html2image: 将canvas2iamge以及html2canvas结合将html转化为image. 方便大家使用也可以自己去下载这两个插件单独使用
* @param {Object} element : html元素如document.body, document.getElementById('elementId')
* @param {Object} html2canvasObject : html2canvas所需要的参数 具体参数可访问html2canvas网站 http://html2canvas.hertzen.com/configuration
* @param {String} saveType :'download''src'两种类型第一种直接下载微信中不可直接下载被拦截第二种返回src,可放入image标签中使用 canvas转image: git地址 https://github.com/hongru/canvas2image
* @param {String} imageName : 导出的图片命名, 只有type为'download'才会生效
* @param {String} type: 图片的类型 png jpeggifbmp四种类型
* **/
var htmlToCavas = function(element, html2canvasObject, saveType='src', type='png', imageName) {
var result = new Promise(function(resolve, reject){
html2canvas(element, html2canvasObject).then(canvas => {
var imageWidth = canvas.width
var imageHeight = canvas.height
console.log(canvas.toDataURL('image/jpeg'))
console.log('测试')
if(saveType=== 'download'){
canvas2Image.saveAsImage(canvas, imageWidth, imageHeight, imageName, type)
resolve()
} else if(saveType === 'src'){
var result = canvas2Image.convertToImage(canvas, imageWidth, imageHeight,type)
console.log(result)
resolve(result)
}
}).catch(err=> {
reject(err)
})
})
return result
}
export default htmlToCavas

View File

@ -0,0 +1,19 @@
# html2canvas
### 使用方法
```
import htmlToCavas from '@/components/html2image/html2image'
htmlToCavas(element, {
useCORS: true,
logging: true,
backgroundColor: '#982121',
scale: 2,
dpi: 350}).then(res=> {
this.imageSrc = res.src
}).catch(err=> {
console.log(err)
})
```

318
components/messageBox.vue Normal file
View File

@ -0,0 +1,318 @@
<template>
<view class="msgbox">
<!-- <view class="quick" :style="[{ background: quick ? '#fff' : 'none' }]">
<view class="justify-between section_7" v-if="quick">
<view class="flex-row">
<view class="flex-col items-center text-wrapper_2">
<text class="text">交换信息</text>
</view>
<view class="flex-col items-end text-wrapper_3">
<text class="text">交换联系方式</text>
</view>
</view>
<image
@click="quick = false"
src="/static/common/img/msgclose.png"
class="image_13"
/>
</view>
<view style="display: flex; justify-content: flex-end" v-else>
<image
style="margin: 0.08rem; width: 0.2rem; height: 0.2rem"
@click="quick = true"
src="/static/common/img/msgopen.png"
class="image_13"
/>
</view>
</view> -->
<view class="flex-row section_1">
<text class="text" v-if="!isCommonWords" @click="CommonWords = !CommonWords;emoji = false;">常用语</text>
<view class="input-container">
<image @click="emoji = !emoji;CommonWords = false;emojicurrent = 0;" src="/static/common/img/homepage/icon-message.png" class="input-icon" />
<u-input class="input" :type="'textarea'" v-model="message" :auto-height="true" @click="shuru"
@blur="inputBlur" @focus="inputFocus" :placeholder='placeholder'/>
</view>
<!-- <u-input class="input" :type="'textarea'" v-model="message" :auto-height="true" @click="shuru"
@blur="inputBlur" @focus="inputFocus" :placeholder='placeholder'/> -->
<!-- <view class="icon" @click="emoji = !emoji;CommonWords = false;emojicurrent = 0;">
<image src="/static/common/img/icon.png" class="image" />
</view> -->
<view class="btn" v-if="message != ''">
<!-- <u-button size="mini" class="sendOut" @click="send">发送</u-button> -->
<image
src="/static/common/img/homepage/icon-send.png"
class="image_send"
@click="send"
/>
</view>
</view>
<!-- 常用语 -->
<view class="CommonWords">
<scroll-view scroll-y="true" style="transition: all 0.3s; height: 0rem" :class="CommonWords ? 'open' : ''">
<text v-for="(v, i) in commonWords" :key="i" @click="choice(v)">{{v}}</text>
</scroll-view>
</view>
<!-- emoji 表情 -->
<swiper class="slider" :current="emojicurrent" :class="emoji ? 'emojishow' : ''">
<swiper-item v-for="(item, key) in emojiData" :key="key" class="slider-emoji"
:class="[key == emojiData.length - 1 ? 'lastbox' : '']">
<text v-for="(emoji, index) in item" :key="index" @click="selemoji(emoji)"
class="slider-emoji-icon">{{ emoji }}</text>
</swiper-item>
</swiper>
</view>
</template>
<script>
import emoji from "../static/common/js/emoji";
export default {
name: "messageBox",
props:['isCommonWords'],
data() {
return {
commonWords: [
'您好,很高兴认识你!',
'您好,有空聊一聊吗?',
'嗨,你好呀!',
'好的,我知道了。',
'我们下次再聊,拜拜。'
],
CommonWords: false,
quick: false,
message: "",
emojiData: [],
emoji: false,
inputShow: false,
emojicurrent: 0,
placeholder:"",
};
},
// props:['placeholder'],
mounted() {
// console.log(this.placeholder)
this.emojiInit();
},
created(){
// console.log(this.placeholder)
},
methods: {
outbox() {
alert("out");
},
emojiInit() {
var number = 60;
var page = Math.ceil(emoji.length / number);
for (let i = 0; i < page; i++) {
this.emojiData[i] = [];
for (let k = 0; k < number; k++) {
emoji[i * number + k] ?
this.emojiData[i].push(emoji[i * number + k]) :
"";
}
}
},
inputFocus() {
this.CommonWords = false;
this.emoji = false;
setTimeout(() => {
this.scrollTop += 1;
}, 100);
// console.log("inputFocus");
},
inputBlur() {
// console.log("inputBlur");
},
shuru() {
setTimeout(() => {
this.scrollTop += 1;
}, 100);
},
choice(txt) {
this.message = txt;
},
close() {
this.CommonWords = false;
this.emoji = false;
},
sendOut() {
this.close();
},
selemoji(m) {
this.message += m;
},
send(){
this.$emit('onsend',this.message)
this.message = ""
this.$emit('onmsgShow',false)
}
},
};
</script>
<style lang="scss">
.msgbox {
position: fixed;
bottom: 0;
width: 100%;
.section_1 {
width: 100%;
display: flex;
// height: 0.52rem;
background-color: #ffffff;
border: solid 0.01rem #eeeeee;
padding: 0.11rem 0.1rem 0.11rem 0.1rem;
}
.text {
font-size: 0.14rem;
line-height: 0.15rem;
color: #505051;
margin: 0 0.1rem;
line-height: 0.36rem;
}
.input {
width: 100%;
min-height: 0.36rem !important;
line-height: 0.36rem;
background-color: #f7f7f7;
border-radius: 0.1rem;
font-size: 0.14rem;
padding-right: 0.1rem !important;
::v-deep .u-input__input {
padding: 0.05rem;
min-height: 0.16rem !important;
transform: translateY(0.03rem);
}
}
.icon {
margin-left: 0.05rem;
padding: 0.03rem 0;
}
.btn {
padding: 0.03rem 0;
.sendOut {
height: 0.3rem;
line-height: 0.3rem;
width: 0.5rem;
margin-left: 0.05rem;
background-color: #2e9bff;
color: #ffffff;
}
.image_send {
width: 0.25rem;
height: 0.25rem;
margin-left: 0.05rem;
transform: translateY(0.03rem);
}
}
.image {
width: 0.26rem;
height: 0.26rem;
}
.CommonWords {
width: 100%;
background-color: #f6f7fa;
text {
transition: all 0.3s;
display: block;
padding: 0.1rem 0 0.1rem 0.2rem;
font-size: 0.14rem;
line-height: 0.2rem;
height: 0.4rem;
overflow: hidden;
color: #505051;
}
text:active {
background: #ccc;
}
}
.open {
height: 3rem !important;
transition: all 0.3s;
}
.input-container{
position: relative;
// width: 90%;
display: flex;
align-items: center;
flex: 1;
.input-icon {
width: 0.2rem;
height: 0.2rem;
position: absolute;
left: 0.1rem;
z-index: 1;
}
.input {
width: 100%;
min-height: 0.36rem !important;
line-height: 0.36rem;
// background-color: #f7f7f7;
border-radius: 0.1rem;
font-size: 0.14rem;
padding-right: 0.1rem !important;
padding-left: 0.35rem !important; /* 为左侧图标留出空间 */
::v-deep .u-input__input {
padding: 0.05rem;
min-height: 0.16rem !important;
transform: translateY(0.03rem);
}
}
}
}
.emojishow {
height: 3rem !important;
}
.slider {
background: #fff;
width: 7.75rem;
height: 0rem;
transition: all 0.3s;
.slider-emoji {
overflow-y: scroll;
width: 100vw !important;
}
&-emoji {
width: 6.75rem;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
&-icon {
font-size: 0.265rem;
display: inline-block;
width: 0.4rem;
text-align: center;
padding: 0.05rem 0;
border-radius: 0.1rem;
// border-bottom: 1px solid #ccc;
}
&-icon:active {
background: #ccc;
}
}
}
</style>

View File

@ -0,0 +1,99 @@
<template>
<view class="nav-wrap">
<view class="nav-title">
<image class="logo" src="https://cdn.uviewui.com/uview/common/logo.png" mode="widthFix"></image>
<view class="nav-info">
<view class="nav-title__text">
{{$t('common.title')}}
</view>
<view class="nav-slogan">
{{$t('common.intro')}}
</view>
</view>
</view>
<view class="nav-desc">
{{desc}}
</view>
<view class="lang" @tap="switchLang">
<u-icon size="46" color="warning" :name="lang"></u-icon>
</view>
</view>
</template>
<script>
export default {
props: {
desc: String,
title: String,
},
computed: {
lang() {
return this.$i18n.locale == 'zh' ? 'zh' : 'en';
}
},
methods: {
switchLang() {
this.$i18n.locale = this.$i18n.locale == 'en' ? 'zh' : 'en';
this.vuex_tabbar[0].text = this.$t('nav.components')
this.vuex_tabbar[1].text = this.$t('nav.js')
this.vuex_tabbar[2].text = this.$t('nav.template')
uni.setNavigationBarTitle({
title: this.$t(this.title)
});
}
}
}
</script>
<style lang="scss" scoped>
.nav-wrap {
padding: 15px;
position: relative;
}
.lang {
position: absolute;
top: 15px;
right: 15px;
}
.nav-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.nav-info {
margin-left: 15px;
}
.nav-title__text {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
color: $u-main-color;
font-size: 25px;
font-weight: bold;
}
.logo {
width: 70px;
/* #ifndef APP-NVUE */
height: auto;
/* #endif */
}
.nav-slogan {
color: $u-tips-color;
font-size: 14px;
}
.nav-desc {
margin-top: 10px;
font-size: 14px;
color: $u-content-color;
}
</style>

24
enums/index.js Normal file
View File

@ -0,0 +1,24 @@
// 返校核验状态枚举
export const AuditStateEnumMap = new Map([
[0, '待审核'],
[1, '通过'],
[2, '未通过'],
])
//
export const PrebookStateEnumMap = new Map([
[0, '待核验'],
[1, '已取消'],
[2, '已驳回'],
[3, '已核验'],
[4, '未返校'],
])
// 彭剑提供的枚举
export const glyTypeEnumMap = new Map([
[0,'校级管理员'],
[1,'教职工管理员'],
[2,'学生管理员'],
[3,'普通人员'],
])

View File

@ -0,0 +1,462 @@
/**
* 微信小程序JavaScriptSDK
*
* @version 1.0
* @date 2017-01-10
* @author jaysonzhou@tencent.com
*/
var ERROR_CONF = {
KEY_ERR: 311,
KEY_ERR_MSG: 'key格式错误',
PARAM_ERR: 310,
PARAM_ERR_MSG: '请求参数信息有误',
SYSTEM_ERR: 600,
SYSTEM_ERR_MSG: '系统错误',
WX_ERR_CODE: 1000,
WX_OK_CODE: 200
};
var BASE_URL = 'https://apis.map.qq.com/ws/';
var URL_SEARCH = BASE_URL + 'place/v1/search';
var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion';
var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/';
var URL_CITY_LIST = BASE_URL + 'district/v1/list';
var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren';
var URL_DISTANCE = BASE_URL + 'distance/v1/';
var Utils = {
/**
* 得到终点query字符串
* @param {Array|String} 检索数据
*/
location2query(data) {
if (typeof data == 'string') {
return data;
}
var query = '';
for (var i = 0; i < data.length; i++) {
var d = data[i];
if (!!query) {
query += ';';
}
if (d.location) {
query = query + d.location.lat + ',' + d.location.lng;
}
if (d.latitude && d.longitude) {
query = query + d.latitude + ',' + d.longitude;
}
}
return query;
},
/**
* 使用微信接口进行定位
*/
getWXLocation(success, fail, complete) {
wx.getLocation({
type: 'gcj02',
success: success,
fail: fail,
complete: complete
});
},
/**
* 获取location参数
*/
getLocationParam(location) {
if (typeof location == 'string') {
var locationArr = location.split(',');
if (locationArr.length === 2) {
location = {
latitude: location.split(',')[0],
longitude: location.split(',')[1]
};
} else {
location = {};
}
}
return location;
},
/**
* 回调函数默认处理
*/
polyfillParam(param) {
param.success = param.success || function () { };
param.fail = param.fail || function () { };
param.complete = param.complete || function () { };
},
/**
* 验证param对应的key值是否为空
*
* @param {Object} param 接口参数
* @param {String} key 对应参数的key
*/
checkParamKeyEmpty(param, key) {
if (!param[key]) {
var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key +'参数格式有误');
param.fail(errconf);
param.complete(errconf);
return true;
}
return false;
},
/**
* 验证参数中是否存在检索词keyword
*
* @param {Object} param 接口参数
*/
checkKeyword(param){
return !this.checkParamKeyEmpty(param, 'keyword');
},
/**
* 验证location值
*
* @param {Object} param 接口参数
*/
checkLocation(param) {
var location = this.getLocationParam(param.location);
if (!location || !location.latitude || !location.longitude) {
var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + ' location参数格式有误')
param.fail(errconf);
param.complete(errconf);
return false;
}
return true;
},
/**
* 构造错误数据结构
* @param {Number} errCode 错误码
* @param {Number} errMsg 错误描述
*/
buildErrorConfig(errCode, errMsg) {
return {
status: errCode,
message: errMsg
};
},
/**
* 构造微信请求参数公共属性处理
*
* @param {Object} param 接口参数
* @param {Object} param 配置项
*/
buildWxRequestConfig(param, options) {
var that = this;
options.header = { "content-type": "application/json" };
options.method = 'GET';
options.success = function (res) {
var data = res.data;
if (data.status === 0) {
param.success(data);
} else {
param.fail(data);
}
};
options.fail = function (res) {
res.statusCode = ERROR_CONF.WX_ERR_CODE;
param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, result.errMsg));
};
options.complete = function (res) {
var statusCode = +res.statusCode;
switch(statusCode) {
case ERROR_CONF.WX_ERR_CODE: {
param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
break;
}
case ERROR_CONF.WX_OK_CODE: {
var data = res.data;
if (data.status === 0) {
param.complete(data);
} else {
param.complete(that.buildErrorConfig(data.status, data.message));
}
break;
}
default:{
param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG));
}
}
}
return options;
},
/**
* 处理用户参数是否传入坐标进行不同的处理
*/
locationProcess(param, locationsuccess, locationfail, locationcomplete) {
var that = this;
locationfail = locationfail || function (res) {
res.statusCode = ERROR_CONF.WX_ERR_CODE;
param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
};
locationcomplete = locationcomplete || function (res) {
if (res.statusCode == ERROR_CONF.WX_ERR_CODE) {
param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg));
}
};
if (!param.location) {
that.getWXLocation(locationsuccess, locationfail, locationcomplete);
} else if (that.checkLocation(param)) {
var location = Utils.getLocationParam(param.location);
locationsuccess(location);
}
}
}
class QQMapWX {
/**
* 构造函数
*
* @param {Object} options 接口参数,key 为必选参数
*/
constructor(options) {
if (!options.key) {
throw Error('key值不能为空');
}
this.key = options.key;
}
/**
* POI周边检索
*
* @param {Object} options 接口参数对象
*
* 参数对象结构可以参考
* @see http://lbs.qq.com/webservice_v1/guide-search.html
*/
search(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
if (!Utils.checkKeyword(options)) {
return;
}
var requestParam = {
keyword: options.keyword,
orderby: options.orderby || '_distance',
page_size: options.page_size || 10,
page_index: options.page_index || 1,
output: 'json',
key: that.key
};
if (options.address_format) {
requestParam.address_format = options.address_format;
}
if (options.filter) {
requestParam.filter = options.filter;
}
var distance = options.distance || "1000";
var auto_extend = options.auto_extend || 1;
var locationsuccess = function (result) {
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend +")";
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_SEARCH,
data: requestParam
}));
}
Utils.locationProcess(options, locationsuccess);
}
/**
* sug模糊检索
*
* @param {Object} options 接口参数对象
*
* 参数对象结构可以参考
* http://lbs.qq.com/webservice_v1/guide-suggestion.html
*/
getSuggestion(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
if (!Utils.checkKeyword(options)) {
return;
}
var requestParam = {
keyword: options.keyword,
region: options.region || '全国',
region_fix: options.region_fix || 0,
policy: options.policy || 0,
output: 'json',
key: that.key
};
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_SUGGESTION,
data: requestParam
}));
}
/**
* 逆地址解析
*
* @param {Object} options 接口参数对象
*
* 请求参数结构可以参考
* http://lbs.qq.com/webservice_v1/guide-gcoder.html
*/
reverseGeocoder(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
var requestParam = {
coord_type: options.coord_type || 5,
get_poi: options.get_poi || 0,
output: 'json',
key: that.key
};
if (options.poi_options) {
requestParam.poi_options = options.poi_options
}
var locationsuccess = function (result) {
requestParam.location = result.latitude + ',' + result.longitude;
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_GET_GEOCODER,
data: requestParam
}));
};
Utils.locationProcess(options, locationsuccess);
}
/**
* 地址解析
*
* @param {Object} options 接口参数对象
*
* 请求参数结构可以参考
* http://lbs.qq.com/webservice_v1/guide-geocoder.html
*/
geocoder(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
if (Utils.checkParamKeyEmpty(options, 'address')) {
return;
}
var requestParam = {
address: options.address,
output: 'json',
key: that.key
};
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_GET_GEOCODER,
data: requestParam
}));
}
/**
* 获取城市列表
*
* @param {Object} options 接口参数对象
*
* 请求参数结构可以参考
* http://lbs.qq.com/webservice_v1/guide-region.html
*/
getCityList(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
var requestParam = {
output: 'json',
key: that.key
};
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_CITY_LIST,
data: requestParam
}));
}
/**
* 获取对应城市ID的区县列表
*
* @param {Object} options 接口参数对象
*
* 请求参数结构可以参考
* http://lbs.qq.com/webservice_v1/guide-region.html
*/
getDistrictByCityId(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
if (Utils.checkParamKeyEmpty(options, 'id')) {
return;
}
var requestParam = {
id: options.id || '',
output: 'json',
key: that.key
};
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_AREA_LIST,
data: requestParam
}));
}
/**
* 用于单起点到多终点的路线距离(非直线距离)计算
* 支持两种距离计算方式步行和驾车
* 起点到终点最大限制直线距离10公里
*
* @param {Object} options 接口参数对象
*
* 请求参数结构可以参考
* http://lbs.qq.com/webservice_v1/guide-distance.html
*/
calculateDistance(options) {
var that = this;
options = options || {};
Utils.polyfillParam(options);
if (Utils.checkParamKeyEmpty(options, 'to')) {
return;
}
var requestParam = {
mode: options.mode || 'walking',
to: Utils.location2query(options.to),
output: 'json',
key: that.key
};
var locationsuccess = function (result) {
requestParam.from = result.latitude + ',' + result.longitude;
wx.request(Utils.buildWxRequestConfig(options, {
url: URL_DISTANCE,
data: requestParam
}));
}
if (options.from) {
options.location = options.from;
}
Utils.locationProcess(options, locationsuccess);
}
}
module.exports = QQMapWX;

File diff suppressed because one or more lines are too long

106
main.js Normal file
View File

@ -0,0 +1,106 @@
import Vue from 'vue';
import App from './App';
import "./static/common/css/font.css"
import common from './static/common/js/common'
import jweixin from 'jweixin-module'
import {
HubConnectionBuilder,
LogLevel,
} from "./uni_modules/Lyuan-SignalR/js_sdk/signalr";
Vue.config.productionTip = false;
App.mpType = 'app';
// 提示
var tips = function(title, type, time) {
this.$refs.uTips.show({
title: title ? title : "",
type: type ? type : "success",
duration: time ? time + "" : "1000",
});
}
// 导入公用js
Vue.prototype.$tips = tips
Vue.prototype.common = common
// 导入微信sdk
Vue.prototype.jweixin = jweixin
// 引入全局uView
import uView from 'uview-ui';
Vue.use(uView);
// 此处为演示vuex使用非uView的功能部分
import store from '@/store';
// 引入uView提供的对vuex的简写法文件
let vuexStore = require('@/store/$u.mixin.js');
Vue.mixin(vuexStore);
// 引入uView对小程序分享的mixin封装
let mpShare = require('uview-ui/libs/mixin/mpShare.js');
Vue.mixin(mpShare);
// 引入 jsonp
import {VueJsonp} from 'vue-jsonp' //中间有忘记大括号出现install undefind问题
Vue.use(VueJsonp)
// i18n部分的配置
// 引入语言包,注意路径
import Chinese from '@/common/locales/zh.js';
import English from '@/common/locales/en.js';
// VueI18n
import VueI18n from '@/common/vue-i18n.min.js';
// VueI18n
Vue.use(VueI18n);
const i18n = new VueI18n({
// 默认语言
locale: 'zh',
// 引入语言文件
messages: {
'zh': Chinese,
'en': English,
}
});
// 由于微信小程序的运行机制问题需声明如下一行H5和APP非必填
Vue.prototype._i18n = i18n;
const app = new Vue({
i18n,
store,
...App
});
// http拦截器将此部分放在new Vue()和app.$mount()之间才能App.vue中正常使用
import httpInterceptor from '@/common/http.interceptor.js';
Vue.use(httpInterceptor, app);
// http接口API抽离免于写url或者一些固定的参数
import httpApi from '@/common/http.api.js';
Vue.use(httpApi, app);
import httpApiList from '@/common/http.apiList.js';
Vue.use(httpApiList, app);
var connection = new HubConnectionBuilder()
// .withUrl("https://xy.apps.service.zheke.com/ChatHub",)
.withUrl("http://sl.vrgon.com:8003/ChatHub",)
.configureLogging(LogLevel.Error)
.build();
Vue.prototype.$connection = connection
app.$mount();

176
manifest.json Normal file
View File

@ -0,0 +1,176 @@
{
"name" : "Dl Chat",
"appid" : "__UNI__D70D15E",
"description" : "",
"versionName" : "1.8.4",
"versionCode" : "100",
"transformPx" : false,
"sassImplementationName" : "node-sass",
"app-plus" : {
"optimization" : {
"subPackages" : true
},
"safearea" : {
"bottom" : {
"offset" : "none"
}
},
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
"usingComponents" : true,
"nvueCompiler" : "uni-app",
"compilerVersion" : 3,
"modules" : {},
"distribute" : {
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
],
"abiFilters" : [ "armeabi-v7a", "arm64-v8a" ]
},
"ios" : {},
"sdkConfigs" : {
"ad" : {}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
"quickapp" : {},
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : true,
"es6" : false,
"minified" : true,
"postcss" : true
},
"optimization" : {
"subPackages" : true
},
"usingComponents" : true,
"permission" : {},
"secureNetwork" : {
"enable" : false
}
},
"mp-alipay" : {
"usingComponents" : true,
"component2" : true
},
"mp-qq" : {
"optimization" : {
"subPackages" : true
},
"appid" : "15646153"
},
"mp-baidu" : {
"usingComponents" : true,
"appid" : ""
},
"mp-toutiao" : {
"usingComponents" : true,
"appid" : ""
},
"h5" : {
"devServer" : {
"port" : 8080,
"disableHostCheck" : true,
// "proxy" : {
// "/api" : {
// "target" : "https://apis.map.qq.com",
// "changeOrigin" : true,
// "secure" : false,
// "pathRewrite" : {
// "^/api" : ""
// }
// },
// "/dpa" : {
// "target" : "http://pv.sohu.com",
// "changeOrigin" : true,
// "secure" : false,
// "pathRewrite" : {
// "^/dpa" : ""
// }
// }
// },
"https" : false
},
"template" : "template.h5.html",
"router" : {
"mode" : "hash",
"base" : "./"
},
"optimization" : {
"treeShaking" : {
"enable" : true
}
},
"title" : "笑柚",
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : "2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS"
},
"tencent" : {
"key" : "2OLBZ-OOSRQ-RYZ5A-GMCM2-DJ43O-3QFLS"
}
}
}
}
}

77
node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,77 @@
{
"name": "uView",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/js-md5": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
},
"node_modules/jweixin-module": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/vue-i18n": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg=="
},
"node_modules/vue-jsonp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/vue-jsonp/-/vue-jsonp-2.0.0.tgz",
"integrity": "sha512-Mzd9GNeuKP5hHFDWZNMWOsCuMILSkA6jo2l4A02wheFz3qqBzH7aSEFTey1BRCZCLizlaf1EqJ5YUtF392KspA=="
}
}
}

30
node_modules/jweixin-module/README.md generated vendored Normal file
View File

@ -0,0 +1,30 @@
# jweixin-module
微信JS-SDK
## 安装
### NPM
```shell
npm install jweixin-module --save
```
### UMD
```http
https://unpkg.com/jweixin-module/out/index.js
```
## 使用
```js
var jweixin = require('jweixin-module')
jweixin.ready(function(){
// TODO
});
```
## 完整API
>[微信JS-SDK说明文档](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115)

1
node_modules/jweixin-module/lib/index.js generated vendored Normal file

File diff suppressed because one or more lines are too long

54
node_modules/jweixin-module/package.json generated vendored Normal file
View File

@ -0,0 +1,54 @@
{
"_from": "jweixin-module",
"_id": "jweixin-module@1.6.0",
"_inBundle": false,
"_integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w==",
"_location": "/jweixin-module",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "jweixin-module",
"name": "jweixin-module",
"escapedName": "jweixin-module",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"_shasum": "4a7ea614083e3c9c3f49e2fdc2bb882cfa58dfcd",
"_spec": "jweixin-module",
"_where": "C:\\Users\\Administrator\\Documents\\HBuilderProjects\\笑柚",
"author": {
"name": "Shengqiang Guo"
},
"bugs": {
"url": "https://github.com/zhetengbiji/jweixin-module/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "微信JS-SDK",
"devDependencies": {},
"homepage": "https://github.com/zhetengbiji/jweixin-module#readme",
"keywords": [
"wxjssdk",
"weixin",
"jweixin",
"wechat",
"jssdk",
"wx"
],
"license": "ISC",
"main": "lib/index.js",
"name": "jweixin-module",
"repository": {
"type": "git",
"url": "git+https://github.com/zhetengbiji/jweixin-module.git"
},
"scripts": {},
"version": "1.6.0"
}

1631
node_modules/vue-i18n/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

20
node_modules/vue-i18n/LICENSE generated vendored Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2016 kazuya kawaguchi
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

73
node_modules/vue-i18n/README.md generated vendored Normal file
View File

@ -0,0 +1,73 @@
<p align="center"><img width="128px" height="112px" src="./assets/vue-i18n-logo.png" alt="Vue I18n logo"></p>
<h1 align="center">vue-i18n</h1>
<p align="center">
<a href="https://circleci.com/gh/kazupon/vue-i18n/tree/dev"><img src="https://circleci.com/gh/kazupon/vue-i18n/tree/dev.svg?style=shield" alt="Build Status"></a>
<a href="https://codecov.io/gh/kazupon/vue-i18n"><img src="https://codecov.io/gh/kazupon/vue-i18n/branch/dev/graph/badge.svg" alt="Coverage Status"></a>
<a href="http://badge.fury.io/js/vue-i18n"><img src="https://badge.fury.io/js/vue-i18n.svg" alt="NPM version"></a>
<a href="https://discord.gg/4yCnk2m"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="vue-i18n channel on Discord"></a>
<a href="https://devtoken.rocks/package/vue-i18n"><img src="https://badge.devtoken.rocks/vue-i18n" alt="vue-i18n Dev Token"></a>
</p>
<p align="center">Internationalization plugin for Vue.js</p>
<br/>
<h3 align="center">Silver Sponsors</h3>
<p align="center">
<a href="https://www.codeandweb.com/babeledit?utm_campaign=vue-i18n-2019-01" target="_blank">
<img src="https://raw.githubusercontent.com/kazupon/vue-i18n/dev/vuepress/.vuepress/public/patrons/babeledit.png">
</a>
</p>
<h3 align="center">Bronze Sponsors</h3>
<p align="center">
<a href="https://zenarchitects.co.jp/" target="_blank">
<img src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/zenarchitects.png">
</a>
</p>
<br/>
<p align="center">
<a href="https://www.patreon.com/kazupon" target="_blank">
<img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Become a Patreon">
</a>
</p>
<br/>
## :loudspeaker: Notice
vue-i18n will soon be transferred to [intlify organization](https://github.com/intlify). After that, it will be developed and maintained on intlify.
The `vue-i18n` that has been released on npm will be released as `@intlify/vue-i18n` in near future.
`@intlify/vue-i18n` repo is [here](https://github.com/intlify/vue-i18n-next)
Intlify is a new i18n project kickoff by @kazupon. 😉
## :book: Documentation
See [here](http://kazupon.github.io/vue-i18n/)
## :scroll: Changelog
Detailed changes for each release are documented in the [CHANGELOG.md](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md).
## :exclamation: Issues
Please make sure to read the [Issue Reporting Checklist](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
## :muscle: Contribution
Please make sure to read the [Contributing Guide](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md) before making a pull request.
## :copyright: License
[MIT](http://opensource.org/licenses/MIT)

155
node_modules/vue-i18n/decls/i18n.js generated vendored Normal file
View File

@ -0,0 +1,155 @@
declare var Intl: any;
declare type Path = string;
declare type Locale = string;
declare type FallbackLocale = string | string[] | false | { [locale: string]: string[] };
declare type LocaleMessage = string | LocaleMessageObject | LocaleMessageArray;
declare type LocaleMessageObject = { [key: Path]: LocaleMessage };
declare type LocaleMessageArray = Array<LocaleMessage>;
declare type LocaleMessages = { [key: Locale]: LocaleMessageObject };
// This options is the same as Intl.DateTimeFormat constructor options:
// http://www.ecma-international.org/ecma-402/2.0/#sec-intl-datetimeformat-constructor
declare type DateTimeFormatOptions = {
year?: 'numeric' | '2-digit',
month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',
day?: 'numeric' | '2-digit',
hour?: 'numeric' | '2-digit',
minute?: 'numeric' | '2-digit',
second?: 'numeric' | '2-digit',
weekday?: 'narrow' | 'short' | 'long',
hour12?: boolean,
era?: 'narrow' | 'short' | 'long',
timeZone?: string, // IANA time zone
timeZoneName?: 'short' | 'long',
localeMatcher?: 'lookup' | 'best fit',
formatMatcher?: 'basic' | 'best fit'
};
declare type DateTimeFormat = { [key: string]: DateTimeFormatOptions };
declare type DateTimeFormats = { [key: Locale]: DateTimeFormat };
// This options is the same as Intl.NumberFormat constructor options:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
declare type NumberFormatOptions = {
style?: 'decimal' | 'currency' | 'percent',
currency?: string, // ISO 4217 currency codes
currencyDisplay?: 'symbol' | 'code' | 'name',
useGrouping?: boolean,
minimumIntegerDigits?: number,
minimumFractionDigits?: number,
maximumFractionDigits?: number,
minimumSignificantDigits?: number,
maximumSignificantDigits?: number,
localeMatcher?: 'lookup' | 'best fit',
formatMatcher?: 'basic' | 'best fit'
};
declare type NumberFormat = { [key: string]: NumberFormatOptions };
declare type NumberFormats = { [key: Locale]: NumberFormat };
declare type Modifiers = { [key: string]: (str: string) => string };
declare type TranslateResult = string | LocaleMessages;
declare type DateTimeFormatResult = string;
declare type NumberFormatResult = string;
declare type MissingHandler = (locale: Locale, key: Path, vm?: any) => string | void;
declare type PostTranslationHandler = (str: string, key?: string) => string;
declare type GetChoiceIndex = (choice: number, choicesLength: number) => number
declare type ComponentInstanceCreatedListener = (newI18n: I18n, rootI18n: I18n) => void;
declare type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
declare type FormattedNumberPart = {
type: FormattedNumberPartType,
value: string,
};
// This array is the same as Intl.NumberFormat.formatToParts() return value:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/formatToParts#Return_value
declare type NumberFormatToPartsResult = Array<FormattedNumberPart>;
declare type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
declare type I18nOptions = {
locale?: Locale,
fallbackLocale?: FallbackLocale,
messages?: LocaleMessages,
dateTimeFormats?: DateTimeFormats,
numberFormats?: NumberFormats,
formatter?: Formatter,
missing?: MissingHandler,
modifiers?: Modifiers,
root?: I18n, // for internal
fallbackRoot?: boolean,
formatFallbackMessages?: boolean,
sync?: boolean,
silentTranslationWarn?: boolean | RegExp,
silentFallbackWarn?: boolean | RegExp,
pluralizationRules?: PluralizationRules,
preserveDirectiveContent?: boolean,
warnHtmlInMessage?: WarnHtmlInMessageLevel,
sharedMessages?: LocaleMessage,
postTranslation?: PostTranslationHandler,
componentInstanceCreatedListener?: ComponentInstanceCreatedListener,
};
declare type IntlAvailability = {
dateTimeFormat: boolean,
numberFormat: boolean
};
declare type PluralizationRules = {
[lang: string]: GetChoiceIndex,
}
declare interface I18n {
static install: () => void, // for Vue plugin interface
static version: string,
static availabilities: IntlAvailability,
get vm (): any, // for internal
get locale (): Locale,
set locale (locale: Locale): void,
get fallbackLocale (): FallbackLocale,
set fallbackLocale (locale: FallbackLocale): void,
get messages (): LocaleMessages,
get dateTimeFormats (): DateTimeFormats,
get numberFormats (): NumberFormats,
get availableLocales (): Locale[],
get missing (): ?MissingHandler,
set missing (handler: MissingHandler): void,
get formatter (): Formatter,
set formatter (formatter: Formatter): void,
get formatFallbackMessages (): boolean,
set formatFallbackMessages (fallback: boolean): void,
get silentTranslationWarn (): boolean | RegExp,
set silentTranslationWarn (silent: boolean | RegExp): void,
get silentFallbackWarn (): boolean | RegExp,
set silentFallbackWarn (slient: boolean | RegExp): void,
get pluralizationRules (): PluralizationRules,
set pluralizationRules (rules: PluralizationRules): void,
get preserveDirectiveContent (): boolean,
set preserveDirectiveContent (preserve: boolean): void,
get warnHtmlInMessage (): WarnHtmlInMessageLevel,
set warnHtmlInMessage (level: WarnHtmlInMessageLevel): void,
get postTranslation (): ?PostTranslationHandler,
set postTranslation (handler: PostTranslationHandler): void,
getLocaleMessage (locale: Locale): LocaleMessageObject,
setLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
mergeLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
t (key: Path, ...values: any): TranslateResult,
i (key: Path, locale: Locale, values: Object): TranslateResult,
tc (key: Path, choice?: number, ...values: any): TranslateResult,
te (key: Path, locale?: Locale): boolean,
getDateTimeFormat (locale: Locale): DateTimeFormat,
setDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
mergeDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
d (value: number | Date, ...args: any): DateTimeFormatResult,
getNumberFormat (locale: Locale): NumberFormat,
setNumberFormat (locale: Locale, format: NumberFormat): void,
mergeNumberFormat (locale: Locale, format: NumberFormat): void,
n (value: number, ...args: any): NumberFormatResult,
getChoiceIndex: GetChoiceIndex,
pluralizationRules: PluralizationRules,
preserveDirectiveContent: boolean
};
declare interface Formatter {
interpolate (message: string, values: any, path: string): (Array<any> | null)
};

30
node_modules/vue-i18n/decls/module.js generated vendored Normal file
View File

@ -0,0 +1,30 @@
declare type $npm$Vue$Dictionaly<T> = { [key: string]: T }
declare type Util = {
extend: (to: Object, from: ?Object) => Object,
hasOwn: (obj: Object, key: string) => boolean,
isPlainObject: (obj: any) => boolean,
isObject: (obj: mixed) => boolean,
}
declare type Config = {
optionMergeStrategies: $npm$Vue$Dictionaly<Function>,
silent: boolean,
productionTip: boolean,
performance: boolean,
devtools: boolean,
errorHandler: ?(err: Error, vm: Vue, info: string) => void,
ignoredElements: Array<string>,
keyCodes: $npm$Vue$Dictionaly<number>,
isReservedTag: (x?: string) => boolean,
parsePlatformTagName: (x: string) => string,
isUnknownElement: (x?: string) => boolean,
getTagNamespace: (x?: string) => string | void,
mustUseProp: (tag: string, type: ?string, name: string) => boolean,
}
declare interface Vue {
static config: Config,
static util: Util,
static version: string,
}

2132
node_modules/vue-i18n/dist/vue-i18n.common.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

2085
node_modules/vue-i18n/dist/vue-i18n.esm.browser.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

2130
node_modules/vue-i18n/dist/vue-i18n.esm.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

2138
node_modules/vue-i18n/dist/vue-i18n.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

6
node_modules/vue-i18n/dist/vue-i18n.min.js generated vendored Normal file

File diff suppressed because one or more lines are too long

176
node_modules/vue-i18n/package.json generated vendored Normal file
View File

@ -0,0 +1,176 @@
{
"_args": [
[
"vue-i18n@8.20.0",
"C:\\Users\\Administrator\\Documents\\HBuilderProjects\\uView示例"
]
],
"_from": "vue-i18n@8.20.0",
"_id": "vue-i18n@8.20.0",
"_inBundle": false,
"_integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg==",
"_location": "/vue-i18n",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "vue-i18n@8.20.0",
"name": "vue-i18n",
"escapedName": "vue-i18n",
"rawSpec": "8.20.0",
"saveSpec": null,
"fetchSpec": "8.20.0"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"_spec": "8.20.0",
"_where": "C:\\Users\\Administrator\\Documents\\HBuilderProjects\\uView示例",
"author": {
"name": "kazuya kawaguchi",
"email": "kawakazu80@gmail.com"
},
"bugs": {
"url": "https://github.com/kazupon/vue-i18n/issues"
},
"changelog": {
"labels": {
"Type: Feature": ":star: New Features",
"Type: Bug": ":bug: Bug Fixes",
"Type: Security": ":lock: Security Fixes",
"Type: Performance": ":chart_with_upwards_trend: Performance Fixes",
"Type: Improvement": ":zap: Improved Features",
"Type: Breaking": ":boom: Breaking Change",
"Type: Deprecated": ":warning: Deprecated Features",
"Type: I18n": ":globe_with_meridians: Internationalization",
"Type: A11y": ":wheelchair: Accessibility",
"Type: Documentation": ":pencil: Documentation"
}
},
"description": "Internationalization plugin for Vue.js",
"devDependencies": {
"@babel/core": "^7.1.0",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-syntax-flow": "^7.0.0",
"@babel/plugin-transform-flow-strip-types": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^3.0.0",
"@typescript-eslint/parser": "^3.0.0",
"@vue/babel-preset-app": "^4.4.1",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babel-plugin-istanbul": "^6.0.0",
"babel-preset-power-assert": "^3.0.0",
"buble": "^0.19.3",
"chromedriver": "^83.0.0",
"core-js": "^3.6.5",
"cross-env": "^7.0.2",
"cross-spawn": "^7.0.3",
"eslint": "^6.8.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-flowtype": "^4.7.0",
"eslint-plugin-ie11": "^1.0.0",
"eslint-plugin-no-autofix": "^1.0.1",
"eslint-plugin-vue": "^6.2.2",
"eslint-plugin-vue-libs": "^4.0.0",
"flow-bin": "^0.38.0",
"http-server": "^0.12.3",
"intl": "^1.2.5",
"karma": "^5.0.9",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage": "^2.0.2",
"karma-firefox-launcher": "^1.1.0",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-safari-launcher": "^1.0.0",
"karma-sauce-launcher": "^4.1.5",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.2",
"lerna-changelog": "^1.0.0",
"lerna-changelog-label-schema": "^3.0.0",
"mocha": "^7.2.0",
"mocha-loader": "^5.0.0",
"nightwatch": "^1.3.5",
"nightwatch-helpers": "^1.2.0",
"power-assert": "^1.6.0",
"rollup": "^0.66.0",
"rollup-plugin-buble": "^0.19.2",
"rollup-plugin-commonjs": "^9.1.8",
"rollup-plugin-flow-no-whitespace": "^1.0.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-replace": "^2.0.0",
"selenium-server": "^3.141.59",
"shipjs": "^0.17.0",
"sinon": "^9.0.2",
"terser": "^3.17.0",
"typescript": "^3.9.3",
"vue": "^2.5.17",
"vue-github-button": "^1.1.2",
"vue-template-compiler": "^2.5.17",
"vuepress": "^1.5.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.1.1",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.11.0"
},
"files": [
"dist/vue-i18n.js",
"dist/vue-i18n.min.js",
"dist/vue-i18n.common.js",
"dist/vue-i18n.esm.js",
"dist/vue-i18n.esm.browser.js",
"dist/vue-i18n.esm.browser.min.js",
"src/**/*.js",
"types/*.d.ts",
"decls",
"vetur/tags.json",
"vetur/attributes.json"
],
"homepage": "https://github.com/kazupon/vue-i18n#readme",
"keywords": [
"i18n",
"internationalization",
"plugin",
"vue",
"vue.js"
],
"license": "MIT",
"main": "dist/vue-i18n.common.js",
"module": "dist/vue-i18n.esm.js",
"name": "vue-i18n",
"repository": {
"type": "git",
"url": "git+https://github.com/kazupon/vue-i18n.git"
},
"scripts": {
"build": "node config/build.js",
"clean": "rm -rf coverage && rm -rf dist/*.js* && rm ./*.log",
"coverage": "cat ./coverage/lcov.info",
"dev": "cross-env BABEL_ENV=test webpack-dev-server --inline --hot --open --content-base ./test/unit/ --config config/webpack.dev.conf.js",
"docs:build": "cross-env NODE_ENV=production node config/version.js && cross-env NODE_ENV=production vuepress build vuepress -d docs",
"docs:clean": "rm -rf docs/**",
"docs:dev": "vuepress dev vuepress",
"flow": "flow check",
"lint": "eslint --fix src test types/**/*.ts",
"release:prepare": "shipjs prepare",
"release:trigger": "shipjs trigger",
"sauce": "npm run sauce:coolkids && npm run sauce:ie && npm run sauce:mobile",
"sauce:coolkids": "karma start config/karma.sauce.conf.js -- 0",
"sauce:ie": "karma start config/karma.sauce.conf.js -- 1",
"sauce:mobile": "karma start config/karma.sauce.conf.js -- 2",
"test": "npm run lint && npm run flow && npm run test:types && npm run test:cover && npm run test:e2e",
"test:cover": "cross-env BABEL_ENV=test karma start config/karma.cover.conf.js",
"test:e2e": "npm run build && node test/e2e/runner.js",
"test:types": "tsc -p types",
"test:unit": "cross-env BABEL_ENV=test karma start config/karma.unit.conf.js",
"test:unit:ci": "cross-env BABEL_ENV=test karma start config/karma.unit.ci.conf.js"
},
"sideEffects": false,
"types": "types/index.d.ts",
"unpkg": "dist/vue-i18n.js",
"version": "8.20.0",
"vetur": {
"tags": "vetur/tags.json",
"attributes": "vetur/attributes.json"
}
}

101
node_modules/vue-i18n/src/components/interpolation.js generated vendored Normal file
View File

@ -0,0 +1,101 @@
/* @flow */
import { warn } from '../util'
export default {
name: 'i18n',
functional: true,
props: {
tag: {
type: [String, Boolean, Object],
default: 'span'
},
path: {
type: String,
required: true
},
locale: {
type: String
},
places: {
type: [Array, Object]
}
},
render (h: Function, { data, parent, props, slots }: Object) {
const { $i18n } = parent
if (!$i18n) {
if (process.env.NODE_ENV !== 'production') {
warn('Cannot find VueI18n instance!')
}
return
}
const { path, locale, places } = props
const params = slots()
const children = $i18n.i(
path,
locale,
onlyHasDefaultPlace(params) || places
? useLegacyPlaces(params.default, places)
: params
)
const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
return tag ? h(tag, data, children) : children
}
}
function onlyHasDefaultPlace (params) {
let prop
for (prop in params) {
if (prop !== 'default') { return false }
}
return Boolean(prop)
}
function useLegacyPlaces (children, places) {
const params = places ? createParamsFromPlaces(places) : {}
if (!children) { return params }
// Filter empty text nodes
children = children.filter(child => {
return child.tag || child.text.trim() !== ''
})
const everyPlace = children.every(vnodeHasPlaceAttribute)
if (process.env.NODE_ENV !== 'production' && everyPlace) {
warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.')
}
return children.reduce(
everyPlace ? assignChildPlace : assignChildIndex,
params
)
}
function createParamsFromPlaces (places) {
if (process.env.NODE_ENV !== 'production') {
warn('`places` prop is deprecated in next major version. Please switch to Vue slots.')
}
return Array.isArray(places)
? places.reduce(assignChildIndex, {})
: Object.assign({}, places)
}
function assignChildPlace (params, child) {
if (child.data && child.data.attrs && child.data.attrs.place) {
params[child.data.attrs.place] = child
}
return params
}
function assignChildIndex (params, child, index) {
params[index] = child
return params
}
function vnodeHasPlaceAttribute (vnode) {
return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
}

70
node_modules/vue-i18n/src/components/number.js generated vendored Normal file
View File

@ -0,0 +1,70 @@
/* @flow */
import { warn, isString, isObject, includes, numberFormatKeys } from '../util'
export default {
name: 'i18n-n',
functional: true,
props: {
tag: {
type: [String, Boolean, Object],
default: 'span'
},
value: {
type: Number,
required: true
},
format: {
type: [String, Object]
},
locale: {
type: String
}
},
render (h: Function, { props, parent, data }: Object) {
const i18n = parent.$i18n
if (!i18n) {
if (process.env.NODE_ENV !== 'production') {
warn('Cannot find VueI18n instance!')
}
return null
}
let key: ?string = null
let options: ?NumberFormatOptions = null
if (isString(props.format)) {
key = props.format
} else if (isObject(props.format)) {
if (props.format.key) {
key = props.format.key
}
// Filter out number format options only
options = Object.keys(props.format).reduce((acc, prop) => {
if (includes(numberFormatKeys, prop)) {
return Object.assign({}, acc, { [prop]: props.format[prop] })
}
return acc
}, null)
}
const locale: Locale = props.locale || i18n.locale
const parts: NumberFormatToPartsResult = i18n._ntp(props.value, locale, key, options)
const values = parts.map((part, index) => {
const slot: ?Function = data.scopedSlots && data.scopedSlots[part.type]
return slot ? slot({ [part.type]: part.value, index, parts }) : part.value
})
const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
return tag
? h(tag, {
attrs: data.attrs,
'class': data['class'],
staticClass: data.staticClass
}, values)
: values
}
}

112
node_modules/vue-i18n/src/directive.js generated vendored Normal file
View File

@ -0,0 +1,112 @@
/* @flow */
import { warn, isString, isPlainObject, looseEqual } from './util'
export function bind (el: any, binding: Object, vnode: any): void {
if (!assert(el, vnode)) { return }
t(el, binding, vnode)
}
export function update (el: any, binding: Object, vnode: any, oldVNode: any): void {
if (!assert(el, vnode)) { return }
const i18n: any = vnode.context.$i18n
if (localeEqual(el, vnode) &&
(looseEqual(binding.value, binding.oldValue) &&
looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
t(el, binding, vnode)
}
export function unbind (el: any, binding: Object, vnode: any, oldVNode: any): void {
const vm: any = vnode.context
if (!vm) {
warn('Vue instance does not exists in VNode context')
return
}
const i18n: any = vnode.context.$i18n || {}
if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
el.textContent = ''
}
el._vt = undefined
delete el['_vt']
el._locale = undefined
delete el['_locale']
el._localeMessage = undefined
delete el['_localeMessage']
}
function assert (el: any, vnode: any): boolean {
const vm: any = vnode.context
if (!vm) {
warn('Vue instance does not exists in VNode context')
return false
}
if (!vm.$i18n) {
warn('VueI18n instance does not exists in Vue instance')
return false
}
return true
}
function localeEqual (el: any, vnode: any): boolean {
const vm: any = vnode.context
return el._locale === vm.$i18n.locale
}
function t (el: any, binding: Object, vnode: any): void {
const value: any = binding.value
const { path, locale, args, choice } = parseValue(value)
if (!path && !locale && !args) {
warn('value type not supported')
return
}
if (!path) {
warn('`path` is required in v-t directive')
return
}
const vm: any = vnode.context
if (choice != null) {
el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args))
} else {
el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args))
}
el._locale = vm.$i18n.locale
el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale)
}
function parseValue (value: any): Object {
let path: ?string
let locale: ?Locale
let args: any
let choice: ?number
if (isString(value)) {
path = value
} else if (isPlainObject(value)) {
path = value.path
locale = value.locale
args = value.args
choice = value.choice
}
return { path, locale, args, choice }
}
function makeParams (locale: Locale, args: any): Array<any> {
const params: Array<any> = []
locale && params.push(locale)
if (args && (Array.isArray(args) || isPlainObject(args))) {
params.push(args)
}
return params
}

33
node_modules/vue-i18n/src/extend.js generated vendored Normal file
View File

@ -0,0 +1,33 @@
/* @flow */
export default function extend (Vue: any): void {
if (!Vue.prototype.hasOwnProperty('$i18n')) {
// $FlowFixMe
Object.defineProperty(Vue.prototype, '$i18n', {
get () { return this._i18n }
})
}
Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
const i18n = this.$i18n
return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
}
Vue.prototype.$tc = function (key: Path, choice?: number, ...values: any): TranslateResult {
const i18n = this.$i18n
return i18n._tc(key, i18n.locale, i18n._getMessages(), this, choice, ...values)
}
Vue.prototype.$te = function (key: Path, locale?: Locale): boolean {
const i18n = this.$i18n
return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
}
Vue.prototype.$d = function (value: number | Date, ...args: any): DateTimeFormatResult {
return this.$i18n.d(value, ...args)
}
Vue.prototype.$n = function (value: number, ...args: any): NumberFormatResult {
return this.$i18n.n(value, ...args)
}
}

114
node_modules/vue-i18n/src/format.js generated vendored Normal file
View File

@ -0,0 +1,114 @@
/* @flow */
import { warn, isObject } from './util'
export default class BaseFormatter {
_caches: { [key: string]: Array<Token> }
constructor () {
this._caches = Object.create(null)
}
interpolate (message: string, values: any): Array<any> {
if (!values) {
return [message]
}
let tokens: Array<Token> = this._caches[message]
if (!tokens) {
tokens = parse(message)
this._caches[message] = tokens
}
return compile(tokens, values)
}
}
type Token = {
type: 'text' | 'named' | 'list' | 'unknown',
value: string
}
const RE_TOKEN_LIST_VALUE: RegExp = /^(?:\d)+/
const RE_TOKEN_NAMED_VALUE: RegExp = /^(?:\w)+/
export function parse (format: string): Array<Token> {
const tokens: Array<Token> = []
let position: number = 0
let text: string = ''
while (position < format.length) {
let char: string = format[position++]
if (char === '{') {
if (text) {
tokens.push({ type: 'text', value: text })
}
text = ''
let sub: string = ''
char = format[position++]
while (char !== undefined && char !== '}') {
sub += char
char = format[position++]
}
const isClosed = char === '}'
const type = RE_TOKEN_LIST_VALUE.test(sub)
? 'list'
: isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
? 'named'
: 'unknown'
tokens.push({ value: sub, type })
} else if (char === '%') {
// when found rails i18n syntax, skip text capture
if (format[(position)] !== '{') {
text += char
}
} else {
text += char
}
}
text && tokens.push({ type: 'text', value: text })
return tokens
}
export function compile (tokens: Array<Token>, values: Object | Array<any>): Array<any> {
const compiled: Array<any> = []
let index: number = 0
const mode: string = Array.isArray(values)
? 'list'
: isObject(values)
? 'named'
: 'unknown'
if (mode === 'unknown') { return compiled }
while (index < tokens.length) {
const token: Token = tokens[index]
switch (token.type) {
case 'text':
compiled.push(token.value)
break
case 'list':
compiled.push(values[parseInt(token.value, 10)])
break
case 'named':
if (mode === 'named') {
compiled.push((values: any)[token.value])
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
}
}
break
case 'unknown':
if (process.env.NODE_ENV !== 'production') {
warn(`Detect 'unknown' type of token!`)
}
break
}
index++
}
return compiled
}

1049
node_modules/vue-i18n/src/index.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

40
node_modules/vue-i18n/src/install.js generated vendored Normal file
View File

@ -0,0 +1,40 @@
import { warn } from './util'
import extend from './extend'
import mixin from './mixin'
import interpolationComponent from './components/interpolation'
import numberComponent from './components/number'
import { bind, update, unbind } from './directive'
export let Vue
export function install (_Vue) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
warn('already installed.')
return
}
install.installed = true
Vue = _Vue
const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && version < 2) {
warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
return
}
extend(Vue)
Vue.mixin(mixin)
Vue.directive('t', { bind, update, unbind })
Vue.component(interpolationComponent.name, interpolationComponent)
Vue.component(numberComponent.name, numberComponent)
// use simple mergeStrategies to prevent i18n instance lose '__proto__'
const strats = Vue.config.optionMergeStrategies
strats.i18n = function (parentVal, childVal) {
return childVal === undefined
? parentVal
: childVal
}
}

139
node_modules/vue-i18n/src/mixin.js generated vendored Normal file
View File

@ -0,0 +1,139 @@
/* @flow */
import VueI18n from './index'
import { isPlainObject, warn, error, merge } from './util'
export default {
beforeCreate (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)
if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
Object.keys(localeMessages).forEach((locale: Locale) => {
options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
})
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
error(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
this._i18n = options.i18n
this._i18nWatcher = this._i18n.watchI18nData()
} else if (isPlainObject(options.i18n)) {
const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
? this.$root.$i18n
: null
// component local i18n
if (rootI18n) {
options.i18n.root = this.$root
options.i18n.formatter = rootI18n.formatter
options.i18n.fallbackLocale = rootI18n.fallbackLocale
options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
options.i18n.pluralizationRules = rootI18n.pluralizationRules
options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
}
// init locale messages via custom blocks
if (options.__i18n) {
try {
let localeMessages = {}
options.__i18n.forEach(resource => {
localeMessages = merge(localeMessages, JSON.parse(resource))
})
options.i18n.messages = localeMessages
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot parse locale messages via custom blocks.`, e)
}
}
}
const { sharedMessages } = options.i18n
if (sharedMessages && isPlainObject(sharedMessages)) {
options.i18n.messages = merge(options.i18n.messages, sharedMessages)
}
this._i18n = new VueI18n(options.i18n)
this._i18nWatcher = this._i18n.watchI18nData()
if (options.i18n.sync === undefined || !!options.i18n.sync) {
this._localeWatcher = this.$i18n.watchLocale()
}
if (rootI18n) {
rootI18n.onComponentInstanceCreated(this._i18n)
}
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
// root i18n
this._i18n = this.$root.$i18n
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
// parent i18n
this._i18n = options.parent.$i18n
}
},
beforeMount (): void {
const options: any = this.$options
options.i18n = options.i18n || (options.__i18n ? {} : null)
if (options.i18n) {
if (options.i18n instanceof VueI18n) {
// init locale messages via custom blocks
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (isPlainObject(options.i18n)) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else {
if (process.env.NODE_ENV !== 'production') {
warn(`Cannot be interpreted 'i18n' option.`)
}
}
} else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
} else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
this._i18n.subscribeDataChanging(this)
this._subscribing = true
}
},
beforeDestroy (): void {
if (!this._i18n) { return }
const self = this
this.$nextTick(() => {
if (self._subscribing) {
self._i18n.unsubscribeDataChanging(self)
delete self._subscribing
}
if (self._i18nWatcher) {
self._i18nWatcher()
self._i18n.destroyVM()
delete self._i18nWatcher
}
if (self._localeWatcher) {
self._localeWatcher()
delete self._localeWatcher
}
})
}
}

302
node_modules/vue-i18n/src/path.js generated vendored Normal file
View File

@ -0,0 +1,302 @@
/* @flow */
import { isObject } from './util'
/**
* Path parser
* - Inspired:
* Vue.js Path parser
*/
// actions
const APPEND = 0
const PUSH = 1
const INC_SUB_PATH_DEPTH = 2
const PUSH_SUB_PATH = 3
// states
const BEFORE_PATH = 0
const IN_PATH = 1
const BEFORE_IDENT = 2
const IN_IDENT = 3
const IN_SUB_PATH = 4
const IN_SINGLE_QUOTE = 5
const IN_DOUBLE_QUOTE = 6
const AFTER_PATH = 7
const ERROR = 8
const pathStateMachine: any = []
pathStateMachine[BEFORE_PATH] = {
'ws': [BEFORE_PATH],
'ident': [IN_IDENT, APPEND],
'[': [IN_SUB_PATH],
'eof': [AFTER_PATH]
}
pathStateMachine[IN_PATH] = {
'ws': [IN_PATH],
'.': [BEFORE_IDENT],
'[': [IN_SUB_PATH],
'eof': [AFTER_PATH]
}
pathStateMachine[BEFORE_IDENT] = {
'ws': [BEFORE_IDENT],
'ident': [IN_IDENT, APPEND],
'0': [IN_IDENT, APPEND],
'number': [IN_IDENT, APPEND]
}
pathStateMachine[IN_IDENT] = {
'ident': [IN_IDENT, APPEND],
'0': [IN_IDENT, APPEND],
'number': [IN_IDENT, APPEND],
'ws': [IN_PATH, PUSH],
'.': [BEFORE_IDENT, PUSH],
'[': [IN_SUB_PATH, PUSH],
'eof': [AFTER_PATH, PUSH]
}
pathStateMachine[IN_SUB_PATH] = {
"'": [IN_SINGLE_QUOTE, APPEND],
'"': [IN_DOUBLE_QUOTE, APPEND],
'[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
']': [IN_PATH, PUSH_SUB_PATH],
'eof': ERROR,
'else': [IN_SUB_PATH, APPEND]
}
pathStateMachine[IN_SINGLE_QUOTE] = {
"'": [IN_SUB_PATH, APPEND],
'eof': ERROR,
'else': [IN_SINGLE_QUOTE, APPEND]
}
pathStateMachine[IN_DOUBLE_QUOTE] = {
'"': [IN_SUB_PATH, APPEND],
'eof': ERROR,
'else': [IN_DOUBLE_QUOTE, APPEND]
}
/**
* Check if an expression is a literal value.
*/
const literalValueRE: RegExp = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/
function isLiteral (exp: string): boolean {
return literalValueRE.test(exp)
}
/**
* Strip quotes from a string
*/
function stripQuotes (str: string): string | boolean {
const a: number = str.charCodeAt(0)
const b: number = str.charCodeAt(str.length - 1)
return a === b && (a === 0x22 || a === 0x27)
? str.slice(1, -1)
: str
}
/**
* Determine the type of a character in a keypath.
*/
function getPathCharType (ch: ?string): string {
if (ch === undefined || ch === null) { return 'eof' }
const code: number = ch.charCodeAt(0)
switch (code) {
case 0x5B: // [
case 0x5D: // ]
case 0x2E: // .
case 0x22: // "
case 0x27: // '
return ch
case 0x5F: // _
case 0x24: // $
case 0x2D: // -
return 'ident'
case 0x09: // Tab
case 0x0A: // Newline
case 0x0D: // Return
case 0xA0: // No-break space
case 0xFEFF: // Byte Order Mark
case 0x2028: // Line Separator
case 0x2029: // Paragraph Separator
return 'ws'
}
return 'ident'
}
/**
* Format a subPath, return its plain form if it is
* a literal string or number. Otherwise prepend the
* dynamic indicator (*).
*/
function formatSubPath (path: string): boolean | string {
const trimmed: string = path.trim()
// invalid leading 0
if (path.charAt(0) === '0' && isNaN(path)) { return false }
return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
}
/**
* Parse a string path into an array of segments
*/
function parse (path: Path): ?Array<string> {
const keys: Array<string> = []
let index: number = -1
let mode: number = BEFORE_PATH
let subPathDepth: number = 0
let c: ?string
let key: any
let newChar: any
let type: string
let transition: number
let action: Function
let typeMap: any
const actions: Array<Function> = []
actions[PUSH] = function () {
if (key !== undefined) {
keys.push(key)
key = undefined
}
}
actions[APPEND] = function () {
if (key === undefined) {
key = newChar
} else {
key += newChar
}
}
actions[INC_SUB_PATH_DEPTH] = function () {
actions[APPEND]()
subPathDepth++
}
actions[PUSH_SUB_PATH] = function () {
if (subPathDepth > 0) {
subPathDepth--
mode = IN_SUB_PATH
actions[APPEND]()
} else {
subPathDepth = 0
if (key === undefined) { return false }
key = formatSubPath(key)
if (key === false) {
return false
} else {
actions[PUSH]()
}
}
}
function maybeUnescapeQuote (): ?boolean {
const nextChar: string = path[index + 1]
if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
(mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
index++
newChar = '\\' + nextChar
actions[APPEND]()
return true
}
}
while (mode !== null) {
index++
c = path[index]
if (c === '\\' && maybeUnescapeQuote()) {
continue
}
type = getPathCharType(c)
typeMap = pathStateMachine[mode]
transition = typeMap[type] || typeMap['else'] || ERROR
if (transition === ERROR) {
return // parse error
}
mode = transition[0]
action = actions[transition[1]]
if (action) {
newChar = transition[2]
newChar = newChar === undefined
? c
: newChar
if (action() === false) {
return
}
}
if (mode === AFTER_PATH) {
return keys
}
}
}
export type PathValue = PathValueObject | PathValueArray | string | number | boolean | null
export type PathValueObject = { [key: string]: PathValue }
export type PathValueArray = Array<PathValue>
export default class I18nPath {
_cache: Object
constructor () {
this._cache = Object.create(null)
}
/**
* External parse that check for a cache hit first
*/
parsePath (path: Path): Array<string> {
let hit: ?Array<string> = this._cache[path]
if (!hit) {
hit = parse(path)
if (hit) {
this._cache[path] = hit
}
}
return hit || []
}
/**
* Get path value from path string
*/
getPathValue (obj: mixed, path: Path): PathValue {
if (!isObject(obj)) { return null }
const paths: Array<string> = this.parsePath(path)
if (paths.length === 0) {
return null
} else {
const length: number = paths.length
let last: any = obj
let i: number = 0
while (i < length) {
const value: any = last[paths[i]]
if (value === undefined) {
return null
}
last = value
i++
}
return last
}
}
}

165
node_modules/vue-i18n/src/util.js generated vendored Normal file
View File

@ -0,0 +1,165 @@
/* @flow */
/**
* constants
*/
export const numberFormatKeys = [
'style',
'currency',
'currencyDisplay',
'useGrouping',
'minimumIntegerDigits',
'minimumFractionDigits',
'maximumFractionDigits',
'minimumSignificantDigits',
'maximumSignificantDigits',
'localeMatcher',
'formatMatcher',
'unit'
]
/**
* utilities
*/
export function warn (msg: string, err: ?Error): void {
if (typeof console !== 'undefined') {
console.warn('[vue-i18n] ' + msg)
/* istanbul ignore if */
if (err) {
console.warn(err.stack)
}
}
}
export function error (msg: string, err: ?Error): void {
if (typeof console !== 'undefined') {
console.error('[vue-i18n] ' + msg)
/* istanbul ignore if */
if (err) {
console.error(err.stack)
}
}
}
export const isArray = Array.isArray
export function isObject (obj: mixed): boolean %checks {
return obj !== null && typeof obj === 'object'
}
export function isBoolean (val: mixed): boolean %checks {
return typeof val === 'boolean'
}
export function isString (val: mixed): boolean %checks {
return typeof val === 'string'
}
const toString: Function = Object.prototype.toString
const OBJECT_STRING: string = '[object Object]'
export function isPlainObject (obj: any): boolean {
return toString.call(obj) === OBJECT_STRING
}
export function isNull (val: mixed): boolean {
return val === null || val === undefined
}
export function parseArgs (...args: Array<mixed>): Object {
let locale: ?string = null
let params: mixed = null
if (args.length === 1) {
if (isObject(args[0]) || Array.isArray(args[0])) {
params = args[0]
} else if (typeof args[0] === 'string') {
locale = args[0]
}
} else if (args.length === 2) {
if (typeof args[0] === 'string') {
locale = args[0]
}
/* istanbul ignore if */
if (isObject(args[1]) || Array.isArray(args[1])) {
params = args[1]
}
}
return { locale, params }
}
export function looseClone (obj: Object): Object {
return JSON.parse(JSON.stringify(obj))
}
export function remove (arr: Array<any>, item: any): Array<any> | void {
if (arr.length) {
const index = arr.indexOf(item)
if (index > -1) {
return arr.splice(index, 1)
}
}
}
export function includes (arr: Array<any>, item: any): boolean {
return !!~arr.indexOf(item)
}
const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn (obj: Object | Array<*>, key: string): boolean {
return hasOwnProperty.call(obj, key)
}
export function merge (target: Object): Object {
const output = Object(target)
for (let i = 1; i < arguments.length; i++) {
const source = arguments[i]
if (source !== undefined && source !== null) {
let key
for (key in source) {
if (hasOwn(source, key)) {
if (isObject(source[key])) {
output[key] = merge(output[key], source[key])
} else {
output[key] = source[key]
}
}
}
}
}
return output
}
export function looseEqual (a: any, b: any): boolean {
if (a === b) { return true }
const isObjectA: boolean = isObject(a)
const isObjectB: boolean = isObject(b)
if (isObjectA && isObjectB) {
try {
const isArrayA: boolean = Array.isArray(a)
const isArrayB: boolean = Array.isArray(b)
if (isArrayA && isArrayB) {
return a.length === b.length && a.every((e: any, i: number): boolean => {
return looseEqual(e, b[i])
})
} else if (!isArrayA && !isArrayB) {
const keysA: Array<string> = Object.keys(a)
const keysB: Array<string> = Object.keys(b)
return keysA.length === keysB.length && keysA.every((key: string): boolean => {
return looseEqual(a[key], b[key])
})
} else {
/* istanbul ignore next */
return false
}
} catch (e) {
/* istanbul ignore next */
return false
}
} else if (!isObjectA && !isObjectB) {
return String(a) === String(b)
} else {
return false
}
}

269
node_modules/vue-i18n/types/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,269 @@
import Vue, { PluginFunction } from 'vue';
declare namespace VueI18n {
type Path = string;
type Locale = string;
type FallbackLocale = string | string[] | false | { [locale: string]: string[] }
type Values = any[] | { [key: string]: any };
type Choice = number;
type LocaleMessage = string | LocaleMessageObject | LocaleMessageArray;
interface LocaleMessageObject { [key: string]: LocaleMessage; }
interface LocaleMessageArray { [index: number]: LocaleMessage; }
interface LocaleMessages { [key: string]: LocaleMessageObject; }
type TranslateResult = string | LocaleMessages;
type LocaleMatcher = 'lookup' | 'best-fit';
type FormatMatcher = 'basic' | 'best-fit';
type DateTimeHumanReadable = 'long' | 'short' | 'narrow';
type DateTimeDigital = 'numeric' | '2-digit';
interface SpecificDateTimeFormatOptions extends Intl.DateTimeFormatOptions {
year?: DateTimeDigital;
month?: DateTimeDigital | DateTimeHumanReadable;
day?: DateTimeDigital;
hour?: DateTimeDigital;
minute?: DateTimeDigital;
second?: DateTimeDigital;
weekday?: DateTimeHumanReadable;
era?: DateTimeHumanReadable;
timeZoneName?: 'long' | 'short';
localeMatcher?: LocaleMatcher;
formatMatcher?: FormatMatcher;
}
type DateTimeFormatOptions = Intl.DateTimeFormatOptions | SpecificDateTimeFormatOptions;
interface DateTimeFormat { [key: string]: DateTimeFormatOptions; }
interface DateTimeFormats { [locale: string]: DateTimeFormat; }
type DateTimeFormatResult = string;
type CurrencyDisplay = 'symbol' | 'code' | 'name';
interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions {
style?: 'decimal' | 'percent';
currency?: string;
currencyDisplay?: CurrencyDisplay;
localeMatcher?: LocaleMatcher;
formatMatcher?: FormatMatcher;
}
interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions {
style: 'currency';
currency: string; // Obligatory if style is 'currency'
currencyDisplay?: CurrencyDisplay;
localeMatcher?: LocaleMatcher;
formatMatcher?: FormatMatcher;
}
type NumberFormatOptions = Intl.NumberFormatOptions | SpecificNumberFormatOptions | CurrencyNumberFormatOptions;
interface NumberFormat { [key: string]: NumberFormatOptions; }
interface NumberFormats { [locale: string]: NumberFormat; }
type NumberFormatResult = string;
type PluralizationRulesMap = {
/**
* @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
* @param choicesLength {number} an overall amount of available choices
* @returns a final choice index
*/
[lang: string]: (choice: number, choicesLength: number) => number;
};
type Modifiers = { [key: string]: (str : string) => string };
type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
interface FormattedNumberPart {
type: FormattedNumberPartType;
value: string;
}
interface NumberFormatToPartsResult { [index: number]: FormattedNumberPart; }
interface Formatter {
interpolate(message: string, values: Values | undefined, path: string): (any[] | null);
}
type MissingHandler = (locale: Locale, key: Path, vm: Vue | null, values: any) => string | void;
type PostTranslationHandler = (str: string, key?: string) => string;
type ComponentInstanceCreatedListener = (newVm: VueI18n & IVueI18n, rootVm: VueI18n & IVueI18n) => void;
interface IntlAvailability {
dateTimeFormat: boolean;
numberFormat: boolean;
}
// tslint:disable-next-line:interface-name
interface I18nOptions {
locale?: Locale;
fallbackLocale?: FallbackLocale;
messages?: LocaleMessages;
dateTimeFormats?: DateTimeFormats;
numberFormats?: NumberFormats;
formatter?: Formatter;
modifiers?: Modifiers,
missing?: MissingHandler;
fallbackRoot?: boolean;
formatFallbackMessages?: boolean;
sync?: boolean;
silentTranslationWarn?: boolean | RegExp;
silentFallbackWarn?: boolean | RegExp;
preserveDirectiveContent?: boolean;
pluralizationRules?: PluralizationRulesMap;
warnHtmlInMessage?: WarnHtmlInMessageLevel;
sharedMessages?: LocaleMessages;
postTranslation?: PostTranslationHandler;
componentInstanceCreatedListener?: ComponentInstanceCreatedListener;
}
}
export type Path = VueI18n.Path;
export type Locale = VueI18n.Locale;
export type FallbackLocale = VueI18n.FallbackLocale;
export type Values = VueI18n.Values;
export type Choice = VueI18n.Choice;
export type LocaleMessage = VueI18n.LocaleMessage;
export type LocaleMessageObject = VueI18n.LocaleMessageObject;
export type LocaleMessageArray = VueI18n.LocaleMessageArray;
export type LocaleMessages = VueI18n.LocaleMessages;
export type TranslateResult = VueI18n.TranslateResult;
export type DateTimeFormatOptions = VueI18n.DateTimeFormatOptions;
export type DateTimeFormat = VueI18n.DateTimeFormat;
export type DateTimeFormats = VueI18n.DateTimeFormats;
export type DateTimeFormatResult = VueI18n.DateTimeFormatResult;
export type NumberFormatOptions = VueI18n.NumberFormatOptions;
export type NumberFormat = VueI18n.NumberFormat;
export type NumberFormats = VueI18n.NumberFormats;
export type NumberFormatResult = VueI18n.NumberFormatResult;
export type NumberFormatToPartsResult = VueI18n.NumberFormatToPartsResult;
export type WarnHtmlInMessageLevel = VueI18n.WarnHtmlInMessageLevel;
export type Formatter = VueI18n.Formatter;
export type MissingHandler = VueI18n.MissingHandler;
export type PostTranslationHandler = VueI18n.PostTranslationHandler;
export type IntlAvailability = VueI18n.IntlAvailability;
export type I18nOptions = VueI18n.I18nOptions;
export declare interface IVueI18n {
readonly messages: VueI18n.LocaleMessages;
readonly dateTimeFormats: VueI18n.DateTimeFormats;
readonly numberFormats: VueI18n.NumberFormats;
locale: VueI18n.Locale;
fallbackLocale: VueI18n.FallbackLocale;
missing: VueI18n.MissingHandler;
formatter: VueI18n.Formatter;
formatFallbackMessages: boolean;
silentTranslationWarn: boolean | RegExp;
silentFallbackWarn: boolean | RegExp;
preserveDirectiveContent: boolean;
pluralizationRules: VueI18n.PluralizationRulesMap;
warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
postTranslation: VueI18n.PostTranslationHandler;
t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
tc(
key: VueI18n.Path,
choice: VueI18n.Choice,
locale: VueI18n.Locale,
values?: VueI18n.Values,
): string;
te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
d(
value: number | Date,
key?: VueI18n.Path,
locale?: VueI18n.Locale,
): VueI18n.DateTimeFormatResult;
d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
getChoiceIndex: (choice: number, choicesLength: number) => number;
}
declare class VueI18n {
constructor(options?: VueI18n.I18nOptions)
readonly messages: VueI18n.LocaleMessages;
readonly dateTimeFormats: VueI18n.DateTimeFormats;
readonly numberFormats: VueI18n.NumberFormats;
readonly availableLocales: VueI18n.Locale[];
locale: VueI18n.Locale;
fallbackLocale: VueI18n.FallbackLocale;
missing: VueI18n.MissingHandler;
formatter: VueI18n.Formatter;
formatFallbackMessages: boolean;
silentTranslationWarn: boolean | RegExp;
silentFallbackWarn: boolean | RegExp;
preserveDirectiveContent: boolean;
pluralizationRules: VueI18n.PluralizationRulesMap;
warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
postTranslation: VueI18n.PostTranslationHandler;
t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
tc(key: VueI18n.Path, choice: VueI18n.Choice, locale: VueI18n.Locale, values?: VueI18n.Values): string;
te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
d(value: number | Date, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.DateTimeFormatResult;
d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
/**
* @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
* @param choicesLength {number} an overall amount of available choices
* @returns a final choice index
*/
getChoiceIndex: (choice: number, choicesLength: number) => number;
static install: PluginFunction<never>;
static version: string;
static availabilities: VueI18n.IntlAvailability;
}
declare module 'vue/types/vue' {
interface Vue {
readonly $i18n: VueI18n & IVueI18n;
$t: typeof VueI18n.prototype.t;
$tc: typeof VueI18n.prototype.tc;
$te: typeof VueI18n.prototype.te;
$d: typeof VueI18n.prototype.d;
$n: typeof VueI18n.prototype.n;
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
i18n?: {
messages?: VueI18n.LocaleMessages;
dateTimeFormats?: VueI18n.DateTimeFormats;
numberFormats?: VueI18n.NumberFormats;
sharedMessages?: VueI18n.LocaleMessages;
};
}
}
export default VueI18n;

34
node_modules/vue-i18n/vetur/attributes.json generated vendored Normal file
View File

@ -0,0 +1,34 @@
{
"i18n/path" : {
"description": "[required]\nKeypath of the locale message",
"type": "string"
},
"i18n/locale" : {
"description": "[optional]\nLocale to be used in this translation",
"type": "string"
},
"i18n/tag" : {
"description": "[optional]\nWhich tag to render, default is \"span\"",
"type": "string"
},
"i18n/places": {
"description": "[optional after v8.14]\nWill be removed in the next major version, use the slot syntax instead\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#slots-syntax-usage",
"type": "array|object"
},
"i18n-n/value" : {
"description": "[required]\nNumber to be used in formatting",
"type": "number"
},
"i18n-n/format": {
"description": "[optional]\nNumber format name or object with explicit format options",
"type": "string|object"
},
"i18n-n/locale" : {
"description": "[optional]\nLocale to be used in this translation",
"type": "string"
},
"i18n-n/tag" : {
"description": "[optional]\nWhich tag to render, default is `span`",
"type": "string"
}
}

20
node_modules/vue-i18n/vetur/tags.json generated vendored Normal file
View File

@ -0,0 +1,20 @@
{
"i18n": {
"attributes": [
"path",
"locale",
"tag",
"places"
],
"description": "This is a functional component that can be used when HTML interpolation is needed.\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#basic-usage"
},
"i18n-n": {
"attributes": [
"value",
"format",
"locale",
"tag"
],
"description": "This functional component provides a way to use HTML interpolation in pair with number formatting.\n\nhttp://kazupon.github.io/vue-i18n/guide/number.html#custom-formatting"
}
}

21
node_modules/vue-jsonp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 LancerComet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

153
node_modules/vue-jsonp/README.md generated vendored Normal file
View File

@ -0,0 +1,153 @@
# Vue-jsonp
[![VueJsonp](https://github.com/LancerComet/vue-jsonp/workflows/Test/badge.svg)](https://github.com/LancerComet/vue-jsonp/actions)
A tiny library for handling JSONP request.
## Quick Start
As Vue plugin:
```ts
import { VueJsonp } from 'vue-jsonp'
// Vue Plugin.
Vue.use(VueJsonp)
// Now you can use this.$jsonp in Vue components.
const vm = new Vue()
vm.$jsonp('/some-jsonp-url', {
myCustomUrlParam: 'veryNice'
})
```
Use function directly:
```ts
import { jsonp } from 'vue-jsonp'
jsonp('/some-jsonp-url', {
myCustomUrlParam: 'veryNice'
})
```
## Send data and set query & function name
### Send data
```ts
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&callback=jsonp_{RANDOM_STR}".
jsonp('/some-jsonp-url', {
name: 'LancerComet',
age: 100
})
```
### Custom query & function name
The url uniform is `/url?{callbackQuery}={callbackName}&...`, the default is `/url?callback=jsonp_{RANDOM_STRING}&...`.
And you can change it like this:
```ts
// The request url will be "/some-jsonp-url?name=LancerComet&age=100&cb=jsonp_func".
jsonp('/some-jsonp-url', {
callbackQuery: 'cb',
callbackName: 'jsonp_func',
name: 'LancerComet',
age: 100
})
```
## Module exports
- `VueJsonp: PluginObject<never>`
- `jsonp<T>: (url: string, param?: IJsonpParam, timeout?: number) => Promise<T>`
## API
### IJsonpParam
IJsonpParam is the type of param for jsonp function.
```ts
/**
* JSONP parameter declaration.
*/
interface IJsonpParam {
/**
* Callback query name.
* This param is used to define the query name of the callback function.
*
* @example
* // The request url will be "/some-url?myCallback=jsonp_func&myCustomUrlParam=veryNice"
* jsonp('/some-url', {
* callbackQuery: 'myCallback',
* callbackName: 'jsonp_func',
* myCustomUrlParam: 'veryNice'
* })
*
* @default callback
*/
callbackQuery?: string
/**
* Callback function name.
* This param is used to define the jsonp function name.
*
* @example
* // The request url will be "/some-url?myCallback=jsonp_func&myCustomUrlParam=veryNice"
* jsonp('/some-url', {
* callbackQuery: 'myCallback',
* callbackName: 'jsonp_func',
* myCustomUrlParam: 'veryNice'
* })
*
* @default jsonp_ + randomStr()
*/
callbackName?: string
/**
* Custom data.
*/
[key: string]: any
}
```
## Example
```ts
import Vue from 'vue'
import { VueJsonp } from 'vue-jsonp'
Vue.use(VueJsonp)
const vm = new Vue()
const { code, data, message } = await vm.$jsonp<{
code: number,
message: string,
data: {
id: number,
nickname: string
}
}>('/my-awesome-url', {
name: 'MyName', age: 20
})
assert(code === 0)
assert(message === 'ok')
assert(data.id === 1)
assert(data.nickname === 'John Smith')
```
```ts
import { jsonp } from 'vue-jsonp'
const result = await jsonp<string>('/my-awesome-url')
assert(result === 'such a jsonp')
```
## License
MIT

73
node_modules/vue-jsonp/dist/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,73 @@
/**
* Vue Jsonp.
* # Carry Your World #
*
* @author: LancerComet
* @license: MIT
*/
import { PluginObject } from 'vue/types/plugin';
declare module 'vue/types/vue' {
interface Vue {
$jsonp: typeof jsonp;
}
}
/**
* Vue JSONP.
*/
declare const VueJsonp: PluginObject<never>;
/**
* JSONP function.
*
* @param { string } url Target URL address.
* @param { IJsonpParam } param Querying params object.
* @param { number } timeout Timeout setting (ms).
*
* @example
* jsonp('/url', {
* callbackQuery: ''
* callbackName: '',
* name: 'LancerComet',
* age: 26
* }, 1000)
*/
declare function jsonp<T = any>(url: string, param?: IJsonpParam, timeout?: number): Promise<T>;
export { VueJsonp, jsonp };
/**
* JSONP parameter declaration.
*/
interface IJsonpParam {
/**
* Callback query name.
* This param is used to define the query name of the callback function.
*
* @example
* // The request url will be "/some-url?myCallback=jsonp_func&myCustomUrlParam=veryNice"
* jsonp('/some-url', {
* callbackQuery: 'myCallback',
* callbackName: 'jsonp_func',
* myCustomUrlParam: 'veryNice'
* })
*
* @default callback
*/
callbackQuery?: string;
/**
* Callback function name.
* This param is used to define the jsonp function name.
*
* @example
* // The request url will be "/some-url?myCallback=jsonp_func&myCustomUrlParam=veryNice"
* jsonp('/some-url', {
* callbackQuery: 'myCallback',
* callbackName: 'jsonp_func',
* myCustomUrlParam: 'veryNice'
* })
*
* @default jsonp_ + randomStr()
*/
callbackName?: string;
/**
* Custom data.
*/
[key: string]: any;
}

8
node_modules/vue-jsonp/dist/index.esm.js generated vendored Normal file
View File

@ -0,0 +1,8 @@
function e(t,n){t=t.replace(/=/g,"");var o=[];switch(n.constructor){case String:case Number:case Boolean:o.push(encodeURIComponent(t)+"="+encodeURIComponent(n));break;case Array:n.forEach((function(n){o=o.concat(e(t+"[]=",n))}));break;case Object:Object.keys(n).forEach((function(r){var a=n[r];o=o.concat(e(t+"["+r+"]",a))}))}return o}function t(e){var n=[];return e.forEach((function(e){"string"==typeof e?n.push(e):n=n.concat(t(e))})),n}
/**
* Vue Jsonp.
* # Carry Your World #
*
* @author: LancerComet
* @license: MIT
*/var n={install:function(e){e.prototype.$jsonp=o}};function o(n,o,r){if(void 0===o&&(o={}),"string"!=typeof n)throw new Error('[Vue-jsonp] Type of param "url" is not string.');if("object"!=typeof o||!o)throw new Error("[Vue-jsonp] Invalid params, should be an object.");return r="number"==typeof r?r:5e3,new Promise((function(a,c){var u="string"==typeof o.callbackQuery?o.callbackQuery:"callback",i="string"==typeof o.callbackName?o.callbackName:"jsonp_"+(Math.floor(1e5*Math.random())*Date.now()).toString(16);o[u]=i,delete o.callbackQuery,delete o.callbackName;var s=[];Object.keys(o).forEach((function(t){s=s.concat(e(t,o[t]))}));var l=t(s).join("&"),f=function(){p(),clearTimeout(m),c({status:400,statusText:"Bad Request"})},p=function(){b.removeEventListener("error",f)},d=function(){document.body.removeChild(b),delete window[i]},m=null;r>-1&&(m=setTimeout((function(){p(),d(),c({statusText:"Request Timeout",status:408})}),r)),window[i]=function(e){clearTimeout(m),p(),d(),a(e)};var b=document.createElement("script");b.addEventListener("error",f),b.src=n+(/\?/.test(n)?"&":"?")+l,document.body.appendChild(b)}))}export{n as VueJsonp,o as jsonp};

8
node_modules/vue-jsonp/dist/index.js generated vendored Normal file
View File

@ -0,0 +1,8 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).VueJsonp={})}(this,(function(e){"use strict";function t(e,o){e=e.replace(/=/g,"");var n=[];switch(o.constructor){case String:case Number:case Boolean:n.push(encodeURIComponent(e)+"="+encodeURIComponent(o));break;case Array:o.forEach((function(o){n=n.concat(t(e+"[]=",o))}));break;case Object:Object.keys(o).forEach((function(r){var c=o[r];n=n.concat(t(e+"["+r+"]",c))}))}return n}function o(e){var t=[];return e.forEach((function(e){"string"==typeof e?t.push(e):t=t.concat(o(e))})),t}
/**
* Vue Jsonp.
* # Carry Your World #
*
* @author: LancerComet
* @license: MIT
*/var n={install:function(e){e.prototype.$jsonp=r}};function r(e,n,r){if(void 0===n&&(n={}),"string"!=typeof e)throw new Error('[Vue-jsonp] Type of param "url" is not string.');if("object"!=typeof n||!n)throw new Error("[Vue-jsonp] Invalid params, should be an object.");return r="number"==typeof r?r:5e3,new Promise((function(c,a){var i="string"==typeof n.callbackQuery?n.callbackQuery:"callback",s="string"==typeof n.callbackName?n.callbackName:"jsonp_"+(Math.floor(1e5*Math.random())*Date.now()).toString(16);n[i]=s,delete n.callbackQuery,delete n.callbackName;var u=[];Object.keys(n).forEach((function(e){u=u.concat(t(e,n[e]))}));var f=o(u).join("&"),l=function(){p(),clearTimeout(b),a({status:400,statusText:"Bad Request"})},p=function(){m.removeEventListener("error",l)},d=function(){document.body.removeChild(m),delete window[s]},b=null;r>-1&&(b=setTimeout((function(){p(),d(),a({statusText:"Request Timeout",status:408})}),r)),window[s]=function(e){clearTimeout(b),p(),d(),c(e)};var m=document.createElement("script");m.addEventListener("error",l),m.src=e+(/\?/.test(e)?"&":"?")+f,document.body.appendChild(m)}))}e.VueJsonp=n,e.jsonp=r,Object.defineProperty(e,"__esModule",{value:!0})}));

20
node_modules/vue-jsonp/dist/utils/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,20 @@
/**
* Generate random string.
*
* @return { string }
*/
declare function randomStr(): string;
/**
* Format params into querying string.
*
* @return {string[]}
*/
declare function formatParams(queryKey: string, value: any): string[];
/**
* Flat querys.
*
* @param {string[] | (string[])[]} array
* @returns
*/
declare function flatten(array: string[] | (string[])[]): string[];
export { formatParams, flatten, randomStr };

50
node_modules/vue-jsonp/package.json generated vendored Normal file
View File

@ -0,0 +1,50 @@
{
"name": "vue-jsonp",
"version": "2.0.0",
"description": "A tiny library for handling JSONP request.",
"main": "./dist/index.js",
"module": "./dist/index.esm.js",
"keywords": [
"Vue",
"JSONP"
],
"files": [
"dist/",
"index.d.ts",
"README.md"
],
"scripts": {
"build": "rollup -c",
"test": "jest",
"pretest": "npm run build",
"preversion": "npm run test",
"prepublish": "npm run test"
},
"author": {
"name": "LancerComet",
"email": "chw644@hotmail.com"
},
"repository": {
"type": "git",
"url": "https://github.com/LancerComet/vue-jsonp.git"
},
"license": "MIT",
"devDependencies": {
"@types/expect-puppeteer": "^4.4.3",
"@types/jest": "^26.0.14",
"@types/jest-environment-puppeteer": "^4.4.0",
"@types/puppeteer": "^3.0.2",
"jest": "^26.4.2",
"jest-puppeteer": "^4.4.0",
"puppeteer": "^5.3.1",
"rollup": "^2.28.2",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.27.3",
"ts-jest": "^26.4.1",
"tslint": "^6.1.3",
"typescript": "^4.0.3",
"vue": "^2.6.12"
}
}

155
package-lock.json generated Normal file
View File

@ -0,0 +1,155 @@
{
"name": "uView",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "uView",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"crypto-js": "^4.2.0",
"html2canvas": "^1.4.1",
"js-md5": "^0.8.3",
"jweixin-module": "^1.6.0",
"vue-i18n": "^8.20.0",
"vue-jsonp": "^2.0.0"
}
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/js-md5": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
},
"node_modules/jweixin-module": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/vue-i18n": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg=="
},
"node_modules/vue-jsonp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/vue-jsonp/-/vue-jsonp-2.0.0.tgz",
"integrity": "sha512-Mzd9GNeuKP5hHFDWZNMWOsCuMILSkA6jo2l4A02wheFz3qqBzH7aSEFTey1BRCZCLizlaf1EqJ5YUtF392KspA=="
}
},
"dependencies": {
"base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
},
"crypto-js": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
},
"css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"requires": {
"utrie": "^1.0.2"
}
},
"html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"requires": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
}
},
"js-md5": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.8.3.tgz",
"integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ=="
},
"jweixin-module": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/jweixin-module/-/jweixin-module-1.6.0.tgz",
"integrity": "sha512-dGk9cf+ipipHmtzYmKZs5B2toX+p4hLyllGLF6xuC8t+B05oYxd8fYoaRz0T30U2n3RUv8a4iwvjhA+OcYz52w=="
},
"text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"requires": {
"utrie": "^1.0.2"
}
},
"utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"requires": {
"base64-arraybuffer": "^1.0.2"
}
},
"vue-i18n": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.20.0.tgz",
"integrity": "sha512-ZiAOoeR4d/JtKpbjipx3I80ey7cYG1ki5gQ7HwzWm4YFio9brA15BEYHjalEoBaEfzF5OBEZP+Y2MvAaWnyXXg=="
},
"vue-jsonp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/vue-jsonp/-/vue-jsonp-2.0.0.tgz",
"integrity": "sha512-Mzd9GNeuKP5hHFDWZNMWOsCuMILSkA6jo2l4A02wheFz3qqBzH7aSEFTey1BRCZCLizlaf1EqJ5YUtF392KspA=="
}
}
}

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "uView",
"version": "1.0.0",
"description": "<p align=\"center\">\r <img alt=\"logo\" src=\"https://uviewui.com/common/logo.png\" width=\"120\" height=\"120\" style=\"margin-bottom: 10px;\">\r </p>\r <h3 align=\"center\" style=\"margin: 30px 0 30px;font-weight: bold;font-size:40px;\">uView</h3>\r <h3 align=\"center\">多平台快速开发的UI框架</h3>",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/YanxinNet/uView.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/YanxinNet/uView/issues"
},
"homepage": "https://github.com/YanxinNet/uView#readme",
"dependencies": {
"crypto-js": "^4.2.0",
"html2canvas": "^1.4.1",
"js-md5": "^0.8.3",
"jweixin-module": "^1.6.0",
"vue-i18n": "^8.20.0",
"vue-jsonp": "^2.0.0"
}
}

678
pages.json Normal file
View File

@ -0,0 +1,678 @@
{
"easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
"condition": {
//
"current": 0,
//(list )
"list": [
{
"name": "test",
//
"path": "pages/login/login/login"
//
// "query": "uuid=c4bba940-f69e-11ea-a419-6bafda9d095e&__id__=1" //onLoad
}
]
},
"pages": [
//
{
"path": "pages/login/login/login",
"style": {
"navigationBarTitleText": "登录",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
// ,
{
"path": "pages/login/register/register",
"style": {
"navigationBarTitleText": "注册",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
//
//
{
"path": "pages/login/perfect/perfect",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
//
{
"path": "pages/login/graduateCertification/graduateCertification",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/home",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/components/recommend/allServices",
"style": {
"navigationBarTitleText": "全部服务",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/components/recommend/moreFriends",
"style": {
"navigationBarTitleText": "更多好友",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// 广,
{
"path": "pages/home/home/components/topic/topicSquare",
"style": {
"navigationBarTitleText": "话题广场",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/components/topic/topicDetail",
"style": {
"navigationBarTitleText": "话题详情",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/components/searchPage/index",
"style": {
"navigationBarTitleText": "搜索",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/home/home/components/contentDetail/index",
"style": {
"navigationBarTitleText": "详情",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/main/index/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/msgList/msgList",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/AlumniCircle/alumnus/alumnus",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/AlumniCircle/forward/forward",
"style": {
"navigationBarTitleText": "转发",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/my/my/my",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
//
// {
// "path": "pages/my/realDetail/realDetail",
// "style": {
// "navigationBarTitleText": "实名认证",
// "enablePullDownRefresh": false
// }
// },
//
{
"path": "pages/my/AddEducation/AddEducation",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/dialogBox/dialogBox",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/interactionList/interactionList",
"style": {
"navigationBarTitleText": "互动消息",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/adminList/adminList",
"style": {
"navigationBarTitleText": "管理列表",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/sysList/sysList",
"style": {
"navigationBarTitleText": "系统消息",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/message/attentionList/attentionList",
"style": {
"navigationBarTitleText": "新增关注",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/AlumniCircle/searchAlumnus/searchAlumnus",
"style": {
"navigationBarTitleText": "搜索",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/my/mySeting/mySeting",
"style": {
"navigationBarTitleText": "设置",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/my/myDetails/myDetails",
"style": {
"navigationBarTitleText": "我的",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
//
{
"path": "uview-ui/components/u-avatar-cropper/u-avatar-cropper",
"style": {
"navigationBarTitleText": "头像裁剪",
"navigationBarBackgroundColor": "#000000",
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/my/authentication/authentication",
"style": {
"navigationBarTitleText": "官方认证",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
//,
{
"path": "pages/my/certificationDetails/certificationDetails",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/main/search/search",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/login/ForgetPassword/ForgetPassword",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/AlumniCircle/ArticleDetails/ArticleDetails",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/AlumniCircle/ReplyDetails/ReplyDetails",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
// ,
{
"path": "pages/AlumniCircle/release/release",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/AlumniCircle/Alumni/Alumni",
"style": {
"navigationBarTitleText": "校友",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/AlumniCircle/userDetail/userDetail",
"style": {
"navigationBarTitleText": "个人主页",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/login/confirmPwd/confirmPwd",
"style": {
"navigationBarTitleText": "确认密码",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/ShoolList/ShoolList",
"style": {
"navigationBarTitleText": "教育经历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/TeacherList/TeacherList",
"style": {
"navigationBarTitleText": "任职院校",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/shoolAuthentication/shoolAuthentication",
"style": {
"navigationBarTitleText": "学历认证",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/ReleaseList/ReleaseList",
"style": {
"navigationBarTitleText": "我的发布",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/examine/examine",
"style": {
"navigationBarTitleText": "审核",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/AuditDeatil/AuditDeatil",
"style": {
"navigationBarTitleText": "审核资料",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/Feedback/Feedback",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/wishlist/wishlist",
"style": {
"navigationBarTitleText": "心愿单",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/wishlist/addwishlist",
"style": {
"navigationBarTitleText": "添加心愿",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackSchool/BackSchool",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackApply/BackApply",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackDetail/BackDetail",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackCode/BackCode",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackSuccess/BackSuccess",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/personalResume/personalResume",
"style": {
"navigationBarTitleText": "个人简历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/personalResume/online",
"style": {
"navigationBarTitleText": "在线简历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/personalResume/workPage",
"style": {
"navigationBarTitleText": "工作经历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/personalResume/proPage",
"style": {
"navigationBarTitleText": "工作经历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/BackCodeLook/BackCodeLook",
"style": {
"navigationBarTitleText": "返校核验",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/fileAcc/fileAcc",
"style": {
"navigationBarTitleText": "附件简历",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/login/roleSelection",
"style": {
"navigationBarTitleText": "角色选择",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/login/teacherCertification",
"style": {
"navigationBarTitleText": "教职工认证",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
}
},
{
"path": "pages/webview/index",
"style": {
"navigationBarTitleText": "网页链接",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/login/recognitionResult/recognitionResult",
"style": {
"navigationBarTitleText": "提示",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/login/recognitionResult/recognitionFailed",
"style": {
"navigationBarTitleText": "认证失败",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/mySeting/mySetPwd",
"style": {
"navigationBarTitleText": "设置密码",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
},
{
"path": "pages/my/myDetails/myInterest",
"style": {
"navigationBarTitleText": "兴趣爱好",
"enablePullDownRefresh": false,
"navigationStyle": "custom"
//
}
}
],
"subPackages": [],
// "preloadRule": {
// "pages/example/components": {
// "network": "all",
// "packages": ["pages/componentsA", "pages/componentsB", "pages/componentsC"]
// }
// },
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uView",
"navigationBarBackgroundColor": "#FFFFFF",
"backgroundColor": "#FFFFFF"
},
"tabBar": {
"color": "#909399",
"selectedColor": "#303133",
"backgroundColor": "#FFFFFF",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/home/home/home",
"iconPath": "/static/common/tabbar/index.png",
"selectedIconPath": "/static/common/tabbar/selectindex.png",
"text": "首页"
},
{
"pagePath": "pages/message/msgList/msgList",
"iconPath": "static/common/tabbar/message.png",
"selectedIconPath": "static/common/tabbar/selectmessage.png",
"text": "消息"
},
{
"pagePath": "pages/main/index/index",
"iconPath": "/static/common/tabbar/findFriends.png",
"selectedIconPath": "/static/common/tabbar/selectFindFridend.png",
"text": "找校友"
},
{
"pagePath": "pages/AlumniCircle/alumnus/alumnus",
"iconPath": "static/common/tabbar/AlumniCircle.png",
"selectedIconPath": "static/common/tabbar/selectAlumniCircle.png",
"text": "校友圈"
},
{
"pagePath": "pages/my/my/my",
"iconPath": "static/common/tabbar/my.png",
"selectedIconPath": "static/common/tabbar/selectmy.png",
"text": "我的"
}
]
}
}

View File

@ -0,0 +1,249 @@
<template>
<view style="background: #fff">
<u-navbar back-text="" title="校友找找" ></u-navbar>
<view class="slot-wrap">
<u-tabs-swiper ref="uTabs" :list="navList" :current="current" :is-scroll="true" gutter='60'
:active-item-style="{ color: '#3CB5FB',transition:'all 0.5s'}" :bar-style="{ background: '#3CB5FB' }"
@change="tabsChange"></u-tabs-swiper>
</view>
<swiper :current="swiperCurrent" @transition="transition" @animationfinish="animationfinish"
style="height: calc(100vh - 0.8rem); width: 100%">
<swiper-item class="swiper-item" v-for="(item, index) in navList" :key="index"
style="height: calc(100vh - 0.8rem); width: 100%">
<scroll-view scroll-y="true" style="height: calc(100vh - 0.8rem); width: 100%"
@scrolltolower="onreachBottom" @refresherrefresh='' :scroll-with-animation="true">
<!-- 学生 -->
<template v-if='item.List.length'>
<view class="flex-col student_list group_7">
<view class="flex-row list-item group_8" :key="i" v-for="(v, i) in item.List"
@click="toDetil(v.userId)">
<u-avatar :src="$u.http.config.imgUrl+v.imageUrl" class="image_1" ></u-avatar>
<view class="justify-between section_4">
<view class="flex-col items-start group_9 view_1">
<text class="text_6">{{v.name}}</text>
<text class="text_24">{{v.college+' '+ v.major}} {{v.startYear}}</text>
</view>
<image src="/static/common/img/16486889538940144558.png" class="image_3" />
</view>
</view>
</view>
</template>
<view v-else style='padding-top:30vh'>
<u-empty text="没有找到匹配的校友" mode="message"></u-empty>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
data() {
return {
swiperCurrent: 0,
current: 0,
List: [],
navList: [{
name: "全部",
List: [],
},
{
name: "学院",
List: [],
},
{
name: "同专业",
List: [],
},
{
name: "同届",
List: [],
},
{
name: "同行",
List: [],
},
{
name: "同城",
List: [],
},
],
PageIndex: 1,
PageSize: 10,
};
},
watch: {
current() {
this.PageIndex = 1
this.getList(1);
},
},
onLoad() {
this.getList(1);
},
onShow() {
// this.getList(1);
},
methods: {
getList(type) {
const data = {
PageIndex: this.PageIndex,
PageSize: this.PageSize,
type: this.current
}
this.$u.api.AlumnSearchList(data).then(res => {
if (this.navList[this.current].List.length == 0 || type == 1) {
this.navList[this.current].List = res.items
} else {
this.navList[this.current].List = this.navList[this.current].List.concat(res.items)
}
})
},
toDetil(id) {
this.$u.route({
url: '/pages/AlumniCircle/userDetail/userDetail?id=' + id + '&type=2'
})
},
// tabsswiper
tabsChange(index) {
this.swiperCurrent = index;
},
// swiper-itemtabs
transition(e) {
let dx = e.detail.dx;
this.$refs.uTabs.setDx(dx);
},
// swiperswiperdx
// swipertabsswiper
animationfinish(e) {
let current = e.detail.current;
this.$refs.uTabs.setFinishCurrent(current);
this.swiperCurrent = current;
this.current = current;
},
// scroll-view
onreachBottom() {
this.PageIndex++
this.getList(2)
},
//
router() {
uni.switchTab({
url: '../../AlumniCircle/alumnus/alumnus'
});
}
},
};
</script>
<style lang="scss" scoped>
::v-deep .u-avatar__sex {
width: 0.1rem !important;
height: 0.1rem !important;
border: none;
}
.student_list {
.list-item {
padding: 0.05rem 0.2rem;
box-shadow: 0px 0.0063rem #eaeaea;
.image_1 {
flex-shrink: 0;
align-self: center;
width: 0.5rem !important;
height: 0.5rem !important;
border-radius: 50%;
flex:0 0 0.5rem !important;
}
.section_4 {
margin-left: 0.05rem;
padding: 0.1rem;
flex: 1 1 auto;
.group_9 {
align-self: flex-start;
color: #020202;
font-size: 0.19rem;
letter-spacing: 0.019rem;
.text_6 {
color: #020202;
font-size: 0.16rem;
line-height: 1;
letter-spacing: 0.019rem;
}
.text_24 {
margin-top: 0.1rem;
color: #b4b6bd;
font-size: 0.14rem;
line-height: 1;
letter-spacing: 0.015rem;
width: 2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.view_1 {
align-self: initial;
color: initial;
font-size: initial;
line-height: initial;
letter-spacing: initial;
white-space: initial;
}
.image_3 {
align-self: center;
width: 0.075rem;
height: 0.14rem;
border-radius: 50%;
}
}
}
}
.list {
margin-top: 0.17rem;
padding: 0 5%;
.list-item {
padding: 0.13rem 0.12rem 0.13rem 0.33rem;
background-color: #f6f7fa;
border-radius: 0.05rem;
.text_6 {
color: #373b48;
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
.text_10 {
color: #ffffff;
line-height: 0.16rem;
}
.image_1 {
margin-bottom: 0.02rem;
width: 0.06rem;
height: 0.11rem;
}
.image_5 {
margin-bottom: 0.04rem;
}
}
.section_5 {
padding: 0.12rem 0.12rem 0.12rem 0.34rem;
background-color: #2e9bff;
margin-top: 0.07rem;
}
}
</style>

View File

@ -0,0 +1,349 @@
<template>
<view style="background: #fff">
<u-navbar back-text="" title="校友找找"></u-navbar>
<view class="slot-wrap">
<u-tabs-swiper ref="uTabs" :list="navList" :current="current" :is-scroll="true" gutter="60"
:active-item-style="{ color: '#3CB5FB', transition: 'all 0.5s' }" :bar-style="{ background: '#3CB5FB' }"
@change="tabsChange"></u-tabs-swiper>
</view>
<swiper :current="swiperCurrent" @transition="transition" @animationfinish="animationfinish"
style="height: calc(100vh - 0.8rem); width: 100%">
<swiper-item class="swiper-item" v-for="(item, index) in navList" :key="index"
style="height: calc(100vh - 0.8rem); width: 100%">
<scroll-view scroll-y="true" style="height: calc(100vh - 0.8rem); width: 100%" @scrolltolower="onreachBottom"
@refresherrefresh="" :scroll-with-animation="true">
<!-- 学生 -->
<template v-if="item.List.length">
<view class="flex-col student_list group_7">
<view class="flex-row list-item group_8" :key="i" v-for="(v, i) in item.List" @click="toDetil(v.userId)">
<u-avatar :src="$u.http.config.imgUrl + v.imageUrl" class="image_1"></u-avatar>
<view class="justify-between section_4">
<view class="flex-col items-start group_9 view_1">
<text class="text_6">{{ v.name }}</text>
<!-- <text class="text_24">
{{ v.college + " " + v.major }} {{ v.startYear }}
</text> -->
<!-- <u-tag
:text="v.college + ' ' + v.major"
type="primary"
mode="plain"
style="margin-top: 0.05rem"
></u-tag> -->
<view class="tag">
<text class="tag-item">{{ v.college }}</text>
<text class="tag-item">{{ v.major }}</text>
</view>
</view>
<!-- <u-button
class="follow-btn"
shape="circle"
:type="v.isFollowed ? 'default' : 'primary'"
@click="handleFollow(v.userId)"
>
{{ v.isFollowed ? "已关注" : "未关注" }}
</u-button> -->
<view class="flex-row ">
<text class="message" @click.stop="toMessage(v.userId)">私信</text>
<!-- <image
src="/static/common/img/16486889538940144558.png"
class="image_3"
/> -->
</view>
</view>
</view>
</view>
</template>
<view v-else style="padding-top: 30vh">
<!-- <u-empty text="没有找到匹配的校友" mode="message"></u-empty> -->
<no-data type="friends" text="没有找到匹配的校友"></no-data>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import NoData from "components/NoData.vue";
export default {
components: {
NoData,
},
data() {
return {
swiperCurrent: 0,
current: 0,
List: [],
navList: [
{
name: "全部",
List: [],
},
{
name: "学院",
List: [],
},
{
name: "同专业",
List: [],
},
{
name: "同届",
List: [],
},
{
name: "同行",
List: [],
},
{
name: "同城",
List: [],
},
],
PageIndex: 1,
PageSize: 10,
};
},
watch: {
current() {
this.PageIndex = 1;
this.getList(1);
},
},
onLoad() {
this.getList(1);
},
onShow() {
// this.getList(1);
},
methods: {
getList(type) {
const data = {
PageIndex: this.PageIndex,
PageSize: this.PageSize,
type: this.current,
};
this.$u.api.AlumnSearchList(data).then((res) => {
if (this.navList[this.current].List.length == 0 || type == 1) {
this.navList[this.current].List = res.items;
} else {
this.navList[this.current].List = this.navList[
this.current
].List.concat(res.items);
}
});
},
toDetil(id) {
this.$u.route({
url: "/pages/AlumniCircle/userDetail/userDetail?id=" + id + "&type=2",
});
},
toMessage(id) {
uni.navigateTo({
url: "../../message/dialogBox/dialogBox?id=" + id + "&chatType=0",
});
},
// tabsswiper
tabsChange(index) {
this.swiperCurrent = index;
},
// swiper-itemtabs
transition(e) {
let dx = e.detail.dx;
this.$refs.uTabs.setDx(dx);
},
// swiperswiperdx
// swipertabsswiper
animationfinish(e) {
let current = e.detail.current;
this.$refs.uTabs.setFinishCurrent(current);
this.swiperCurrent = current;
this.current = current;
},
// scroll-view
onreachBottom() {
this.PageIndex++;
this.getList(2);
},
//
handleFollow(id) {
const data = {
userId: this.vuex_user.id,
carewId: id,
};
this.$u.apiList.InsertOrDelFollow(data).then((res) => {
this.getList(this.current);
});
},
//
router() {
uni.switchTab({
url: "../../AlumniCircle/alumnus/alumnus",
});
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .u-avatar__sex {
width: 0.1rem !important;
height: 0.1rem !important;
border: none;
}
.student_list {
background: #f6f8f9;
.list-item {
width: calc(100% - 48rpx);
margin: 10rpx auto;
padding: 24rpx;
// box-shadow: 0px 0.0063rem #eaeaea;
background: #FFFFFF;
border-radius: 24rpx;
.image_1 {
flex-shrink: 0;
align-self: center;
width: 0.5rem !important;
height: 0.5rem !important;
border-radius: 50%;
flex: 0 0 0.5rem !important;
}
.section_4 {
margin-left: 0.05rem;
// padding: 0.1rem;
flex: 1 1 auto;
.group_9 {
align-self: flex-start;
color: #020202;
font-size: 0.19rem;
letter-spacing: 0.019rem;
.text_6 {
color: #020202;
font-size: 32rpx;
line-height: 1;
margin-top: 15rpx;
// letter-spacing: 0.019rem;
}
.text_24 {
margin-top: 0.1rem;
color: #b4b6bd;
font-size: 0.14rem;
line-height: 1;
letter-spacing: 0.015rem;
width: 2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.view_1 {
align-self: initial;
color: initial;
font-size: initial;
line-height: initial;
letter-spacing: initial;
white-space: initial;
}
.image_3 {
align-self: center;
width: 0.075rem;
height: 0.14rem;
border-radius: 50%;
}
.message {
display: inline-block;
width: 100rpx;
height: 60rpx;
box-shadow: inset 4rpx 8rpx 32rpx 0rpx rgba(248, 248, 248, 0.06);
border-radius: 64rpx 64rpx 64rpx 64rpx;
border: 2rpx solid #3cb5fb;
text-align: center;
line-height: 55rpx;
font-weight: 500;
font-size: 24rpx;
color: #3CB5FB;
}
}
.follow-btn {
width: 120rpx;
height: 64rpx;
line-height: 64rpx;
font-size: 28rpx;
}
}
}
.list {
margin-top: 0.17rem;
padding: 0 5%;
.list-item {
padding: 0.13rem 0.12rem 0.13rem 0.33rem;
background-color: #f6f7fa;
border-radius: 0.05rem;
.text_6 {
color: #373b48;
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
.text_10 {
color: #ffffff;
line-height: 0.16rem;
}
.image_1 {
margin-bottom: 0.02rem;
width: 0.06rem;
height: 0.11rem;
}
.image_5 {
margin-bottom: 0.04rem;
}
}
.section_5 {
padding: 0.12rem 0.12rem 0.12rem 0.34rem;
background-color: #2e9bff;
margin-top: 0.07rem;
}
}
.tag {
display: inline-block;
margin-top: 40rpx;
width: 400rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.tag-item {
background: #F6F8F9;
border-radius: 12rpx;
font-size: 24rpx;
color: rgba(0, 0, 0, 0.8);
font-weight: 400;
padding: 12rpx;
&:first-child {
margin-right: 12rpx;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,349 @@
<template>
<view>
<u-navbar title="评论详细">
<template #right
><view style="width: 50rpx; font-size: 32rpx">
<!-- <u-icon name="star" v-if="true"></u-icon> -->
<!-- <u-icon style="font-size:0.22rem;color:#ffc300" v-else name="star-fill"></u-icon> -->
</view>
</template>
</u-navbar>
<!-- 评论 -->
<view class="comment">
<view class="flex-col section_4">
<view class="justify-between group_8">
<text class="text_22">回复 {{total}}</text>
</view>
<view class="flex-col group_27">
<view class="flex-col group">
<view class="justify-between group_6">
<view class="flex-row">
<image
:src="$u.http.config.imgUrl + headData.userHead"
class="image image_6"
/>
<text class="text_24">{{headData.userName}}</text>
<text class="text_27">{{headData.creationTime}}</text>
</view>
<view class="flex-row group_12">
<text class="text_25">{{headData.likesCount}}</text>
<image
src="/static/common/img/homepage/like.png"
class="image_8"
/>
</view>
</view>
<view class="flex-col">
<text class="text_26" @click="onreply">{{headData.content}}</text>
<!-- <view class="justify-evenly section_5">
<text class="text_42">{{total}}回复</text>
<image
src="/static/common/img/16486282410596443868.png"
class="image_12"
/>
</view> -->
<!-- <text class="text_27">{{headData.creationTime}}</text> -->
</view>
<view class="flex-col items-start group_9" v-for="(i,index) in commonData" :key="index">
<view class="flex-row group_13">
<image
:src="$u.http.config.imgUrl + i.userHead"
class="image image_9"
/>
<view class="group_14">
<text class="text_28">{{i.userName}}</text>
<text class="text_30">{{i.creationTime}}</text>
<view class="flex-col items-start group_15">
<text class="text_29">{{i.content}}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<u-mask :show="show" @click="isMask">
<msgbox @onsend="onSend" @onmsgShow="onMsgShow" ref="msg" :placeholder="placeholder"></msgbox>
</u-mask>
</view>
</template>
<script>
import msgbox from "../../../components/messageBox.vue";
export default {
data(){
return {
data : {
PageIndex:1,
PageSize:10,
Title:"",
Keyword:"",
id:"",
},
show:false,
headData:{},
commonData:[],
placeholder:"",
total:0,
}
},
onLoad(e){
this.headData = JSON.parse(e.head)
this.data = JSON.parse(e.data)
this.data.PageIndex = 1
this.data.PageSize = 10
},
created(){
this.getComment()
},
methods:{
getComment(){
this.$u.apiList.GetComment(this.data).then((res)=>{
this.commonData = res.items
this.total = res.items.length
})
},
onreply(){
this.show = true
this.placeholder = '回复'+this.headData.userName
this.$refs.msg.placeholder = this.placeholder
},
isMask(){
this.show =false
},
onSend(msg){
const data = {
commendId:this.headData.commendId,
articleId:this.headData.articleId,
userId:this.vuex_user.id,
replyUserId:this.headData.userId,
content:msg,
level:1,
type:this.headData.type
}
this.$u.apiList.InsertComment(data).then((res)=>{
this.getComment()
})
},
onMsgShow(val){
this.isMsgShow = val
this.show = val
},
},
components: {
msgbox: msgbox,
},
}
</script>
<style lang="scss" scoped>
.comment {
.section_4 {
padding: 0.26rem 0.14rem 0.61rem 0.16rem;
background-color: rgb(255, 255, 255);
// margin-top:0.1rem;
.section_5 {
margin-top: 0.13rem;
padding: 0.04rem 0.05rem 0.05rem 0.095rem;
background-color: rgb(246, 247, 250);
border-radius: 0.1rem;
width: 0.6rem;
.text_42 {
color: rgb(2, 2, 2);
font-size: 0.12rem;
font-family: Adobe Heiti Std;
line-height: 0.11rem;
}
.image_12 {
margin-top: 0.015rem;
width: 0.05rem;
height: 0.09rem;
}
}
.group_8 {
margin-left: 0.025rem;
.text_22 {
margin-bottom: 0.02rem;
color: rgb(2, 2, 2);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.14rem;
}
.text_23 {
color: rgb(180, 182, 189);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.17rem;
}
}
.group_27 {
margin-top: 0.25rem;
.group {
padding: 0 0.005rem;
.group_6 {
margin-right: 0.02rem;
.group_12 {
margin-top: 0.04rem;
.text_25 {
margin-top: 0.04rem;
color: rgb(2, 2, 2);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
.image_8 {
margin-left: 0.045rem;
flex-shrink: 0;
width: 0.16rem;
height: 0.15rem;
transform: translateY(0.02rem);
}
}
.image_6 {
flex-shrink: 0;
}
.text_24 {
margin-left: 0.13rem;
margin-top: 0.07rem;
color: rgb(2, 2, 2);
font-size: 0.13rem;
font-family: Adobe Heiti Std;
line-height: 0.13rem;
}
.text_27 {
margin-left: 0.13rem;
margin-top: 0.07rem;
align-self: flex-start;
color: rgb(180, 182, 189);
font-size: 0.12rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
}
.text_26 {
width: 100%;
padding-left: 0.4rem;
margin-top: 0.075rem;
align-self: center;
color: rgb(55, 59, 72);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.14rem;
}
}
.group_9 {
margin-top: 0.14rem;
padding: 0 0.38rem;
.group_13 {
margin-left: 0.035rem;
.image_9 {
flex-shrink: 0;
}
.group_14 {
margin-left: 0.18rem;
margin-top: 0.05rem;
flex: 1 1 auto;
.text_28 {
align-self: flex-start;
color: rgb(2, 2, 2);
font-size: 0.13rem;
font-family: Adobe Heiti Std;
line-height: 0.13rem;
}
.text_30 {
margin-left: 0.13rem;
margin-top: 0.045rem;
color: rgb(180, 182, 189);
font-size: 0.12rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
.group_15 {
margin-top: 0.12rem;
.text_29 {
color: rgb(55, 59, 72);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.14rem;
}
}
}
}
.group_16 {
margin-left: 0.035rem;
margin-top: 0.11rem;
width: 1.09rem;
.group_17 {
margin-top: 0.075rem;
.text_31 {
align-self: flex-start;
color: rgb(2, 2, 2);
font-size: 0.13rem;
font-family: Adobe Heiti Std;
line-height: 0.1rem;
}
.group_18 {
margin-top: 0.14rem;
padding-left: 0.015rem;
.text_32 {
color: rgb(55, 59, 72);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.14rem;
}
.text_33 {
margin-top: 0.03rem;
color: rgb(180, 182, 189);
font-size: 0.12rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
}
}
}
.group_19 {
margin-left: 0.05rem;
margin-top: 0.12rem;
width: 1.07rem;
.group_20 {
margin-top: 0.07rem;
.text_34 {
align-self: flex-start;
color: rgb(2, 2, 2);
font-size: 0.13rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
.group_21 {
margin-top: 0.14rem;
.text_35 {
color: rgb(55, 59, 72);
font-size: 0.15rem;
font-family: Adobe Heiti Std;
line-height: 0.14rem;
}
.text_36 {
margin-left: 0.01rem;
margin-top: 0.03rem;
color: rgb(180, 182, 189);
font-size: 0.12rem;
font-family: Adobe Heiti Std;
line-height: 0.12rem;
}
}
}
}
}
.image {
width: 0.3rem;
height: 0.3rem;
border-radius:50%;
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
<template>
<view class="flex-col forward">
<u-navbar title="转发" ></u-navbar>
<view class="flex-col group1">
<view>
<u-input v-model="value" :type="type" :border="border" :height="height" :auto-height="autoHeight" placeholder="转发分享内容"/>
</view>
<view class="flex-col list-item">
<view class="flex-row group_8 view">
<image :src="$u.http.config.imgUrl+forwardData.userHead" class="image_3" />
<text class="text_8 text_43">{{forwardData.userName}}</text>
<text class="text_9">{{forwardData.creationTime}}</text>
<text class="text_11">{{forwardData.schoolName}}</text>
</view>
<view class="flex-col group_9">
<text class="text_14">{{forwardData.title}}</text>
<text class="text_15">
{{forwardData.content}}
</text>
<view class="imgList flex-col" v-if="true">
<view class="flex-row group_10">
<!-- <image :src="$u.http.config.imgUrl + forwardData.imageUrl"
class="image_10" /> -->
<image v-for="(v, i) in forwardData.imageUrl.split(',')" @click="clickImg(v)" :key="i" :src="v?$u.http.config.imgUrl + v:''"
class="image_10" />
</view>
</view>
</view>
</view>
</view>
<view class="flex-col items-center button" @click="onSend">
<text>发送</text>
</view>
<view>
<u-toast ref="uToast" />
<u-top-tips :z-index='999999' ref="uTips" :navbar-height="0"></u-top-tips>
</view>
</view>
</template>
<script>
export default {
data(){
return {
value:'',
type:'textarea',
border: true,
height: 150,
autoHeight: true,
forwardData:{},
}
},
onLoad(e){
this.forwardData = JSON.parse(e.data)
},
methods:{
onSend(){
if(this.value == ""){
// return this.$tips("", "error");
return this.$refs.uToast.show({
title: '请输入标题',
type: 'warning',
})
}
const data = {
title:this.value,
content:this.forwardData.content,
sysSignStr:this.forwardData.sysSignStr,
userId:this.vuex_user.id,
path:this.forwardData.imageUrl,
forwardId:this.forwardData.id
}
if(this.forwardData.schoolId){
data.schoolId = this.forwardData.schoolId
}
this.$u.apiList.ForwardHelpArticle(data).then((res)=>{
/* uni.showToast({
title: "转发成功",
duration: 2000,
}); */
this.$refs.uToast.show({
title: '转发成功',
type: 'success',
})
uni.$emit('echoList',{
type:'forward',
data:{}
})
setTimeout(()=>{
uni.switchTab({
url: '../../AlumniCircle/alumnus/alumnus'
});
},1000)
})
},
//
clickImg(item){
item = this.$u.http.config.imgUrl + item
var images = [];
images.push(item);
uni.previewImage({ // => ['']
current: 0,
urls: images,
});
},
//
router(){
if(this.forwardData.route==2){
this.$u.route({
url:'pages/AlumniCircle/userDetail/userDetail?id='+this.forwardData.userId
})
}else{
uni.switchTab({
url: '../../AlumniCircle/alumnus/alumnus'
});
}
}
}
}
</script>
<style lang="scss" scoped>
.forward{
background-color: #ffffff;
height: 100vh;
.group1{
padding: 0.2rem 0.15rem;
}
.list-item {
padding: 0.18rem 0 0.21rem 0.16rem;
background-color: #F2F2F2;
margin-bottom: 0.1rem;
.view {
margin-right: 0.051rem;
}
.group_9 {
margin-right: 0.13rem;
margin-top: 0.17rem;
.text_14 {
align-self: flex-start;
color: rgb(2, 2, 2);
font-size: 32rpx;
font-family: Adobe Heiti Std;
line-height: 0.17rem;
}
.text_15 {
margin-top: 0.11rem;
color: rgb(73, 76, 87);
font-size: 28rpx;
font-family: Adobe Heiti Std;
line-height: 0.24rem;
text-indent: 0.2rem;
}
.text_16 {
margin-left: 0.04rem;
margin-top: 0.12rem;
align-self: flex-start;
color: rgb(44, 109, 255);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
}
.group_21 {
margin-top: 0.1rem;
justify-content: space-between;
width: 90%;
margin: 0.1rem auto 0;
.group_20 {
margin: 0.025rem 0;
.image_6 {
flex-shrink: 0;
width: 0.22rem;
height: 0.21rem;
}
.text_17 {
margin-left: 0.08rem;
margin-top: 0.065rem;
color: rgb(180, 182, 189);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.11rem;
}
}
.equal-division-item_1 {
padding: 0.03rem 0;
.image_8 {
width: 0.2rem;
height: 0.2rem;
}
.text_19 {
margin-left: 0.095rem;
margin-top: 0.06rem;
color: rgb(180, 182, 189);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.11rem;
}
}
}
}
.group_8 {
height: 0.32rem;
position: relative;
.image_3 {
width: 0.3rem;
height: 0.3rem;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
}
.text_8 {
color: rgb(2, 2, 2);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
.text_43 {
position: absolute;
left: 0.37rem;
top: 0.02rem;
}
.text_9 {
color: rgb(184, 184, 184);
font-size: 0.12rem;
font-family: PingFang;
line-height: 0.12rem;
position: absolute;
right: 15rpx;
top: 0.035rem;
}
.text_11 {
color: rgb(184, 184, 184);
font-size: 0.12rem;
font-family: PingFang;
line-height: 0.12rem;
position: absolute;
left: 0.37rem;
bottom: 0;
}
.text_20 {
position: absolute;
left: 0.36rem;
top: 0.02rem;
}
}
.button {
margin-top: 0.18rem;
padding: 0.13rem 0 0.12rem;
align-self: center;
color: rgb(255, 255, 255);
font-size: 0.15rem;
line-height: 0.16rem;
letter-spacing: 0.03rem;
white-space: nowrap;
background-color: #3cb4fb;
border-radius: 100rpx;
width: 3.1rem;
cursor: pointer;
}
.imgList {
image {
// flex: 31%;
width: 0.94rem;
height: 0.91rem;
margin: 0.01rem;
}
.group_10 {
flex-wrap: wrap;
}
}
}
</style>

View File

@ -0,0 +1,565 @@
<template>
<view>
<u-navbar title="发布"></u-navbar>
<view class="flex-col page">
<view class="flex-col group">
<view class="flex-col items-center text-wrapper">
<u-input :maxlength='vuex_user.isAttestationGLY ? 35 : 20' type="text" v-model='title'
:custom-style="{fontSize:'32rpx'}"
@focus="inputFocus" placeholder="添加标题" class="text_1" />
</view>
<view class="flex-col items-start section_3">
<view class="group_1">
<u-input type="textarea" v-model='content' @click="shuru" @blur="inputBlur" @focus="inputFocus"
maxlength="300" :custom-style="textareaStyle" placeholder="添加正文" />
</view>
<view class="flex-col section_5" v-if="type == 1">
<scroll-view scroll-x="true">
<view class="flex-row group_5">
<view v-for="(item, index) in tabs" :key="index"
class="flex-col items-center text-wrapper_1"
:class="{ 'text-wrapper_2': arr1.includes(item.name) }"
@click="current(index, item)">
<image
src="/static/common/img/icon-lineRounded.png"
class="image_3"
/>
<text class="text_13" :class="{ 'text_16': arr1.includes(item.name) }">{{ item.name
}}</text>
</view>
<!-- <view class="flex-col items-center text-wrapper_2"><text class="text_16">找工作</text></view> -->
</view>
</scroll-view>
</view>
<view class="justify-between section_4">
<view class="flex-row expression-box" @click='emoji = !emoji'>
<image src="/static/common/img/icon-happy-face.png"
class="image_3" />
<text class="text_10">表情</text>
</view>
<view class="flex-row group_2">
<!-- <view class="flex-row">
<text class="text_9">@</text>
<text class="text_10">用户</text>
</view> -->
<!-- <view class="flex-row group_4">
<image src="/static/common/img/16535374509810688026.png" class="image_4" />
<text class="text_11">位置</text>
</view> -->
</view>
</view>
<view class="uping">
<u-upload :max-size="5 * 1024 * 1024" max-count="9" :header='header'
:action="$u.http.config.baseUrl + action" @on-success="onSuccess" @on-remove="onRemove"
ref="uUpload" width="140" height="140"></u-upload>
</view>
</view>
</view>
</view>
<view class="flex-col items-center text-wrapper_4" @click="onRelease"><text class="text_18"> </text></view>
<!-- emoji 表情 -->
<div @click='emoji = !emoji' class='back' v-show="emoji"></div>
<swiper class="slider" :current="emojicurrent" :class="emoji ? 'emojishow' : ''">
<swiper-item v-for="(item, key) in emojiData" :key="key" class="slider-emoji"
:class="[key == emojiData.length - 1 ? 'lastbox' : '']">
<text v-for="(value, index) in item" :key="index" @click="selemoji(value)" class="slider-emoji-icon">{{
value }}</text>
</swiper-item>
</swiper>
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
<u-toast ref="uToast"/>
</view>
</template>
<script>
import { Debounce } from '../../../common/utils.js'
import emoji from "../../../static/common/js/emoji";
export default {
data() {
return {
textareaStyle: {
width: "80%",
minHeight: "300rpx"
},
fileList: [],
title: '',
content: '',
emojiData: [],
emoji: false,
emojicurrent: 0,
header: {
Authorization: ""
},
action: '/app/User/File',
imgData: [],
schoolId: "",
sysSignStr: [],
num: "",
tabs: [],
arr1: [],
type: "",
url: false,
time: null,
};
},
onLoad(e) {
this.header.Authorization = "Bearer " + this.vuex_token;
this.schoolId = e.Id
this.type = e.type
this.url = e.url
this.emojiInit();
this.getSign()
},
methods: {
//
tips(title, type, time) {
this.$refs.uToast.show({
title: title ? title : "",
type: type ? type : "success",
duration: time ? time + "" : "1000",
});
},
getSign() {
this.$u.apiList.GetSign().then((res) => {
if (!this.vuex_user.isAttestationQY) {
this.tabs = res.filter(item => {
return item.name != '企业招聘'
})
} else {
this.tabs = res
}
})
},
inputFocus() {
this.emoji = false;
},
current(i, item) {
if (this.arr1.includes(item.name)) {
this.arr1.splice(this.arr1.indexOf(item.name), 1)
} else {
this.arr1.push(item.name)
}
},
onRelease() {
// uni.$emit('helpAdd')
// uni.switchTab({
// url: '/pages/AlumniCircle/alumnus/alumnus?add=true',
// });
// return
if (!this.time) {
}
if (this.title === "") {
this.tips('请输入标题', 'error')
return
}
if (this.content === "") {
this.tips('请输入内容', 'error')
return
}
// let files = this.$refs.uUpload.lists[0];
if (this.type == 1) {
if (this.arr1 == "") {
this.tips("请选择标签", "error")
return
}
}
let file = this.imgData.join(',')
// if(!file){
// this.tips("","error");
// return false
// }
let sysSignStr = this.arr1.join(',')
const data = {
title: this.title,
content: this.content,
path: file,
forwardId: "",
sysSignStr: sysSignStr,
userId: this.vuex_user.id,
schoolId: this.schoolId,
}
if (this.type == 0) {
data.sysSignStr = ""
this.onJourna(data)
} else if (this.type == 1) {
this.onHelp(data)
}
},
//
onJourna: Debounce(function (data) {
this.$u.apiList.InsertJournaArticle(data).then((res) => {
/* uni.showToast({
title: "发布成功",
duration: 2000,
}); */
this.$refs.uToast.show({
title: '发布成功',
type: 'success',
})
setTimeout(() => {
uni.switchTab({
url: "../../../pages/my/my/my"
});
}, 1000)
})
}, 1000),
//
onHelp: Debounce(function (data) {
this.$u.apiList.InsertHelpArticle(data).then((res) => {
/* uni.showToast({
title: "发布成功",
duration: 2000,
}); */
this.$refs.uToast.show({
title: '发布成功',
type: 'success',
})
uni.$emit('helpAdd')
setTimeout(() => {
if (this.url) {
uni.switchTab({
url: '../../AlumniCircle/alumnus/alumnus?add=true'
});
} else {
uni.switchTab({
url: "../../../pages/my/my/my"
});
}
}, 1000)
})
}, 1000),
onSuccess(res) {
this.imgData.push(res.data)
},
onRemove(index, lists) {
let imgs = []
lists.forEach(item => {
imgs.push(item.response.data)
})
this.imgData = imgs
},
inputBlur() {
;
},
shuru() {
;
},
selemoji(m) {
this.content += m;
},
//
emojiInit() {
var number = emoji.length;
// var page = Math.ceil(emoji.length / number);
var page = 1;
for (let i = 0; i < page; i++) {
this.emojiData[i] = [];
for (let k = 0; k < number; k++) {
emoji[i * number + k] ?
this.emojiData[i].push(emoji[i * number + k]) :
"";
}
}
},
//
router() {
if (this.url) {
uni.switchTab({
url: '../../AlumniCircle/alumnus/alumnus'
});
} else {
uni.switchTab({
url: '../../my/my/my'
});
}
}
},
};
</script>
<style lang="scss" scoped>
.emojishow {
height: 3rem !important;
}
.back {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: #fff;
opacity: 0.2;
}
.slider {
background: #fff;
width: 7.75rem;
height: 0rem;
transition: all 0.3s;
box-shadow: 0 0 4px #999;
position: fixed;
bottom: 0;
.slider-emoji {
overflow-y: scroll;
width: 100vw !important;
}
&-emoji {
width: 6.75rem;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
&-icon {
font-size: 0.265rem;
display: inline-block;
width: 11%;
text-align: center;
padding: 0.02rem 0;
border-radius: 0.1rem;
// border-bottom: 1px solid #ccc;
}
&-icon:active {
background: #ccc;
}
}
}
.page {
// padding-bottom: 0.5rem;
overflow-y: auto;
width: calc(100% - 48rpx);
overflow-x: hidden;
height: 100%;
background: #FFFFFF;
border-radius: 24rpx;
margin: 28rpx auto 0;
.group {
padding-top: 0.015rem;
.text-wrapper {
padding: 20rpx 40rpx;
background-color: rgb(255, 255, 255);
box-shadow: 0.00018rem 0.005rem rgba(0, 0, 0, 0.1);
.text_1 {
color: rgb(2, 2, 2);
font-size: 32rpx;
font-family: Adobe Heiti Std;
line-height: 0.24rem;
width: 100%;
}
}
.section_3 {
margin-top: 0.015rem;
padding: 0.13rem 0 0.24rem;
background-color: rgb(255, 255, 255);
box-shadow: 0.00018rem 0.005rem rgba(0, 0, 0, 0.03);
.group_1 {
width: 100%;
padding: 0 40rpx;
margin: 0 auto;
}
.uping {
width: 100%;
padding: 0 40rpx;
margin: 0 auto;
}
}
.section_4 {
margin-top: 0.01rem;
// padding: 0.12rem 0.28rem 0.14rem 0.2rem;
padding: 30rpx 40rpx;
background-color: rgb(255, 255, 255);
box-shadow: 0.00018rem 0.005rem rgba(0, 0, 0, 0.03);
// width: calc(100% - 0.44rem);
width: 100%;
margin: 0 auto;
border-top: 1px solid #E7E7E7;
.image_2 {
margin-top: 0.02rem;
width: 0.23rem;
height: 0.18rem;
}
.expression-box {
display: flex;
align-items: center;
justify-content: center;
width: 128rpx;
height: 60rpx;
background: #F6F8F9;
border-radius: 200rpx 200rpx 200rpx 200rpx;
}
.image_3 {
margin-right: 8rpx;
width: 30rpx;
height: 30rpx;
}
.group_2 {
margin-top: 0.01rem;
.group_4 {
margin-left: 0.3rem;
margin-bottom: 0.02rem;
.image_4 {
flex-shrink: 0;
width: 0.14rem;
height: 0.21rem;
}
.text_11 {
margin-left: 0.06rem;
align-self: center;
color: rgb(160, 162, 172);
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
}
.text_9 {
color: rgb(80, 80, 81);
font-size: 0.24rem;
font-family: PingFang;
line-height: 0.24rem;
}
.text_10 {
margin-top: 0.03rem;
// color: rgb(160, 162, 172);
color: red;
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
}
}
.section_5 {
margin-top: 0.06rem;
padding: 30rpx 40rpx;
background-color: rgb(255, 255, 255);
box-shadow: 0.00018rem 0.005rem rgba(0, 0, 0, 0.03);
// border:1px solid red;
width: 100%;
// width: 700rpx;
// overflow: hidden;
.group_5 {
margin-top: 0.3rem;
margin-bottom: 0.1rem;
.text-wrapper_1 {
padding: 16rpx 20rpx;
// background-color: rgb(255, 255, 255);
background: #F6F8F9;
border-radius: 200rpx;
height: 0.3rem;
margin-right: 20rpx;
// border: solid 0.005rem rgb(193, 196, 204);
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
.image_3 {
margin-right: 8rpx;
width: 30rpx;
height: 30rpx;
}
.text_13 {
// color: #191919;
color: rgba(0, 0, 0, 0.90);
font-size: 28rpx;
font-family: PingFang;
line-height: 0.16rem;
white-space: nowrap;
}
}
.view_1 {
margin-left: 0.055rem;
}
.text-wrapper_2 {
background-color: #3cb4fb;
border-radius: 200rpx;
height: 0.3rem;
margin-right: 20rpx;
padding: 16rpx 20rpx;
.text_16 {
color: rgb(255, 255, 255);
font-size: 0.13rem;
font-family: PingFang;
line-height: 0.16rem;
white-space: nowrap;
}
}
.text-wrapper_3 {
margin-left: 0.055rem;
padding: 0.07rem 0 0.06rem;
flex: 1 1 0.79rem;
background-color: rgb(255, 255, 255);
border-radius: 0.05rem;
height: 0.3rem;
border: solid 0.005rem rgb(193, 196, 204);
.text_17 {
color: rgb(160, 162, 172);
font-size: 0.13rem;
font-family: PingFang;
line-height: 0.16rem;
}
}
}
}
}
}
.text-wrapper_4 {
margin: 0.31rem 0.24rem 0 0.23rem;
padding: 30rpx 0;
background-color: #3cb4fb;
border-radius: 50rpx;
.text_18 {
color: rgb(255, 255, 255);
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.16rem;
}
}
</style>

View File

@ -0,0 +1,854 @@
<template>
<view>
<u-navbar :is-back="true" title="" :custom-back="router">
<view class="slot-wrap flex-row search">
<u-search v-model='searchText' :input-style="searchStyle" search-icon="search" @custom="search" :search='search' :show-action="false" >
</u-search>
<u-button style="width: 120rpx;height: 60rpx;border-radius: 50rpx;margin-left: 20rpx;" type="primary" @click="toSearch">搜索</u-button>
</view>
</u-navbar>
<view class="flex-col group_1">
<view class="flex-col section_1" v-if="!shoolList.length && !helpList.length && historyWord.length">
<view class="section-title">
<text class="text_1 text_2">历史记录</text>
<image src="/static/common/img/delete.png" style="width: 50rpx;height: 50rpx;"
@click="deleteHistory"></image>
</view>
<view class="justify-left group_2" style="margin-top:0.2rem;">
<view class="flex-row" style='flex-wrap:wrap;' >
<text class="text_1 text_5" @click='search(item)' v-for="(item, index) in historyWord"
:key='index'>{{ item }}</text>
</view>
</view>
</view>
<information @clickImg="clickImg" @onStar="onStar" :list="shoolList" type="0" :bottom="bottomState2"
v-if="current == 0">
</information>
<information @onStar="onStar" @clickImg="clickImg" :list="helpList" type="1" :bottom="bottomState" v-else
@onSign="onSign">
</information>
<!-- <view class="flex-col section_2">
<text class="text_1 text_6">可能认识的人</text>
<view class="flex-col group_4">
<scroll-view scroll-x="true" class="flex-row equal-division">
<view class="flex-col items-center equal-division-item" @click="toDetil(item.userId)" v-for="(item, index) in mayKnowList"
:key="index">
<u-avatar :src="$u.http.config.imgUrl+item.imageUrl" class="image_2" ></u-avatar>
<text class="text_1 text_7">{{item.name.length > 3? item.name.slice(0, 3) + "...": item.name}}</text>
</view>
</scroll-view>
</view>
</view> -->
</view>
</view>
</template>
<script>
import noData from '@/components/NoData.vue'
import information from "../../../components/Information.vue";
export default {
components: {
noData,
information
},
data() {
return {
searchText: '',//
searchStyle: {
width: "100%",
},
historyWord: [],
searchList: [],
isonShow: true,
bottomState: false,
bottomState2: false,
helpList: [],
shoolList: [],
isLoad: false,
PageIndex: 1,
PageSize: 10,
PageIndex2: 1,
PageSize2: 10,
Keyword: '全部',
Title: "",
current: 0,
};
},
onLoad(e) {
this.getSearchInfo()
this.Keyword = e.class
this.current = e.type
console.log(this.Keyword, 'this.Keyword', this.current);
},
methods: {
//
gethelpList() {
this.isLoad = true
const data = {
PageIndex: this.PageIndex,
PageSize: this.PageSize,
Keyword: this.Keyword,
// DateBegin:'',
// DateEnd:'',
// SkipCount:1,
// key:,
};
if (this.Keyword != '全部') {
data.Keyword = this.Keyword
}
if (this.Title) {
// this.helpList = []
data.Title = this.Title
}
this.$u.api.GetHelpList(data).then((res) => {
console.log(res, 'res--帮帮列表')
this.isLoad = false
this.total2 = res.total
if (this.helpList.length >= this.total2) {
this.bottomState = true;
return
}
if (this.total2 == res.items.length) {
this.bottomState = true;
}
this.helpList.push(...res.items)
});
},
//
getShoolList() {
const data = {
PageIndex: this.PageIndex2,
PageSize: this.PageSize2,
// Keyword:this.Keyword,
// DateBegin:'',
// DateEnd:'',
// SkipCount:1,
// key:,
};
if (this.Title) {
// this.shoolList = []
data.Title = this.Title
}
this.$u.api.GetSchoolList(data).then((res) => {
this.total1 = res.total
if (this.shoolList.length >= this.total1) {
this.bottomState2 = true;
return
}
if (this.total1 == res.items.length) {
this.bottomState2 = true;
}
this.shoolList.push(...res.items)
});
},
getList() {
if (this.current == 0) {
this.shoolList = []
this.PageIndex2 = 1
this.PageSize2 = 10
this.getShoolList();
} else {
this.helpList = []
this.PageIndex = 1
this.PageSize = 10
if (!this.isLoad) {
this.gethelpList();
}
}
},
//
clickImg(item) {
this.isonShow = false
item = this.$u.http.config.imgUrl + item
var images = [];
images.push(item);
uni.previewImage({ // => ['']
current: 0,
urls: images,
});
},
//
async onStar(val) {
console.log('收藏--');
//
const req = {
userId: this.vuex_user.id,
}
const res = await this.$u.apiList.MyPage(req)
console.log(JSON.parse(JSON.stringify(res)), 'res')
const edcationList = res.edcationList
if (!edcationList.length) {
return this.$refs.uToast.show({
title: '认证后可进行收藏操作',
type: 'none',
})
}
const findRow = edcationList.find(x => x.isSelected === true);
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: '认证后可进行收藏操作',
type: 'none',
})
}
const data = {
id: val.id,
type: val.type
}
this.$u.apiList.LikeCollect(data)
.then((res) => {
if (val.isCllect) {
if (val.collectCount > 0) {
val.isCllect = false
val.collectCount--
this.$refs.uToast.show({
title: '取消收藏成功',
type: 'success',
})
}
} else {
val.isCllect = true
val.collectCount++
this.$refs.uToast.show({
title: '收藏成功',
type: 'success',
})
}
})
.catch((err) => {
this.$refs.uToast.show({
title: '收藏失败',
type: 'error',
})
})
},
//
deleteHistory() {
if (!this.historyWord.length) {
this.$u.toast('暂无历史记录')
return;
}
uni.showModal({
// title: '',
content: '是否清空历史记录?',
success: (res) => {
this.historyWord = []
window.localStorage.setItem('searchHistory', JSON.stringify([]))
}
})
},
toSearch(){
this.search(this.searchText)
},
//
search(value) {
this.searchText = value
if (!value) {
this.$u.toast('请输入搜索词')
return;
}
this.Title = value
if (this.current == 0) {
this.shoolList = []
this.getShoolList()
} else {
this.helpList = []
this.gethelpList()
}
if (!this.historyWord.includes(value)) {
this.historyWord.push(value)
window.localStorage.setItem('searchHistory', JSON.stringify(this.historyWord))
}
},
router() {
uni.switchTab({
url: '../alumnus/alumnus'
})
},
//
getSearchInfo() {
this.historyWord = JSON.parse(window.localStorage.getItem('searchHistory')) || []
}
},
};
</script>
<style lang="scss" scoped>
::v-deep .u-avatar__sex {
width: 0.1rem !important;
height: 0.1rem !important;
border: none;
}
::v-deep .u-slot-content {
display: block;
}
.search ::v-deep {
padding: 0 20rpx;
// .u-content {
// border-bottom-left-radius: 0 !important;
// border-top-left-radius: 0 !important;
// padding:0,
// }
.u-input__input {
width: 0.25rem;
min-height: 0.32rem !important;
padding-left: 0.1rem;
font-size: 0.12rem;
}
.u-input {
background-color: rgb(242, 242, 242);
border-radius: 50px;
border-bottom-right-radius: 0 !important;
border-top-right-radius: 0 !important;
padding-left: 0.05rem
}
}
.group_1 {
padding: 0.14rem 0rem 0.2rem;
flex: 1 1 auto;
overflow-y: auto;
.section_1 {
padding: 0.2rem 0.17rem;
background-color: rgb(255, 255, 255);
border-radius: 0.1rem;
.section-title {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.text_2 {
color: rgb(56, 58, 63);
font-size: 0.16rem;
white-space: nowrap;
font-weight: 700;
}
.group_2 {
margin-top: 0.23rem;
padding: 0 0.015rem;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
position: relative;
.text_3 {
text-transform: uppercase;
position: absolute;
left: 0.015rem;
top: 50%;
transform: translateY(-50%);
}
.text_5 {
border: 2rpx solid rgba(0, 0, 0, 0.1);
;
border-radius: 40rpx;
padding: 20rpx;
margin-right: 20rpx;
margin-bottom: 20rpx;
}
}
}
.section_2 {
margin-top: 0.18rem;
padding: 0.2rem 0.17rem;
background-color: rgb(255, 255, 255);
border-radius: 0.1rem;
.text_6 {
// margin-left: 0.17rem;
color: rgb(56, 58, 63);
font-size: 0.16rem;
line-height: 0.17rem;
white-space: nowrap;
}
.group_4 {
margin-top: 0.15rem;
// padding: 0.8rem 0 0.01rem;
// position: relative;
// .section_3 {
// margin-left: 0.17rem;
// margin-right: 0.2rem;
// background-image: url("https://codefun-proj-user-res-1256085488.cos.ap-guangzhou.myqcloud.com/6216dee45a7e3f031061d0f1/621c59e162a7d90011002985/16460344151483836600.png");
// background-size: 100% 100%;
// background-repeat: no-repeat;
// height: 0.2rem;
// }
.equal-division {
top: 0;
right: 0;
bottom: 0;
left: 0;
width: auto;
::v-deep .uni-scroll-view-content {
display: flex;
white-space: nowrap;
}
// position: absolute;
.equal-division-item {
padding: 0.065rem 0 0.05rem;
margin-right: 6%;
.text_7 {
margin-top: 0.095rem;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
}
.text_8 {
margin-top: 0.06rem;
color: rgb(46, 155, 255);
font-size: 0.1rem;
line-height: 0.1rem;
white-space: nowrap;
background: #eaf5ff;
border-radius: 0.2rem;
padding: 0.05rem 0.1rem;
}
}
.equal-division-item_1 {
padding: 0.065rem 0 0.055rem;
flex: 1 1 0.66rem;
.text_9 {
margin-top: 0.095rem;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
}
.text_10 {
margin-top: 0.15rem;
color: rgb(46, 155, 255);
font-size: 0.1rem;
line-height: 0.1rem;
white-space: nowrap;
}
}
.equal-division-item_2 {
padding: 0.065rem 0.035rem 0.06rem 0.14rem;
flex: 1 1 0.66rem;
.text_11 {
margin-top: 0.095rem;
align-self: center;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
}
.text_12 {
margin-top: 0.15rem;
align-self: center;
color: rgb(46, 155, 255);
font-size: 0.1rem;
line-height: 0.095rem;
white-space: nowrap;
}
}
.equal-division-item_3 {
padding: 0.05rem 0.065rem 0.06rem 0.14rem;
flex: 1 1 0.66rem;
.text_13 {
margin-top: 0.11rem;
align-self: flex-end;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
}
.text_14 {
margin-right: 0.07rem;
margin-top: 0.15rem;
align-self: flex-end;
color: rgb(46, 155, 255);
font-size: 0.1rem;
line-height: 0.095rem;
white-space: nowrap;
}
}
.equal-division-item_4 {
padding: 0.05rem 0 0.06rem;
flex: 1 1 0.66rem;
.text_15 {
margin-top: 0.12rem;
color: rgb(63, 63, 63);
font-size: 0.14rem;
line-height: 0.13rem;
white-space: nowrap;
}
.text_16 {
margin-top: 0.15rem;
color: rgb(46, 155, 255);
font-size: 0.1rem;
line-height: 0.095rem;
white-space: nowrap;
}
}
.image_2 {
border-radius: 50%;
width: 0.4rem;
height: 0.4rem;
box-shadow: 0 0 1px #6f6f6f;
}
}
}
}
.section_4 {
margin-top: 0.14rem;
padding: 0.14rem 0.21rem 0.25rem;
background-color: rgb(255, 255, 255);
border-radius: 0.1rem;
.text_17 {
color: rgb(56, 58, 63);
font-size: 0.18rem;
line-height: 0.15rem;
white-space: nowrap;
}
.group_5 {
margin-top: 0.22rem;
padding: 0 0.28rem;
.section_5 {
margin-top: 0.04rem;
padding: 0.1rem 0.015rem 0.14rem 0.16rem;
color: rgb(255, 255, 255);
font-size: 0.09rem;
line-height: 0.075rem;
white-space: nowrap;
background-image: url("https://codefun-proj-user-res-1256085488.cos.ap-guangzhou.myqcloud.com/6216dee45a7e3f031061d0f1/621c59e162a7d90011002985/16480042463399723422.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 1.16rem;
height: 1.16rem;
.group_7 {
margin-top: 0.29rem;
.text_22 {
margin-top: 0.07rem;
align-self: center;
}
}
.text_18 {
align-self: center;
}
.text_19 {
margin-top: 0.1rem;
}
.text_20 {
margin-top: 0.07rem;
align-self: flex-end;
}
}
.group_8 {
margin-bottom: 0.035rem;
width: 0.96rem;
.text_23 {
color: rgb(56, 58, 63);
font-size: 0.15rem;
line-height: 0.15rem;
white-space: nowrap;
}
.group_9 {
color: rgb(56, 58, 63);
font-size: 0.13rem;
line-height: 0.15rem;
white-space: nowrap;
padding: 0 0.025rem;
.section_6 {
margin: 0.025rem 0 0.02rem;
background-color: rgb(255, 190, 11);
width: 0.1rem;
height: 0.1rem;
}
.text_24 {
margin-left: 0.1rem;
}
.section_7 {
margin: 0.015rem 0 0.03rem;
background-color: rgb(251, 86, 7);
width: 0.1rem;
height: 0.1rem;
}
.text_25 {
margin-left: 0.095rem;
}
.section_8 {
margin: 0.025rem 0 0.02rem;
background-color: rgb(131, 56, 236);
width: 0.1rem;
height: 0.1rem;
}
.text_26 {
margin-left: 0.095rem;
}
.section_9 {
margin: 0.015rem 0 0.03rem;
background-color: rgb(58, 134, 255);
width: 0.1rem;
height: 0.1rem;
}
.text_27 {
margin-left: 0.1rem;
}
.section_10 {
margin: 0.015rem 0 0.03rem;
background-color: rgb(83, 207, 142);
width: 0.1rem;
height: 0.1rem;
}
.text_28 {
margin-left: 0.095rem;
}
}
.view {
margin-top: 0.1rem;
}
.view_1 {
margin-top: 0.045rem;
}
.view_2 {
margin-top: 0.03rem;
}
.view_3 {
margin-top: 0.045rem;
}
.view_4 {
margin-top: 0.035rem;
}
}
}
}
.text_1 {
text-transform: uppercase;
}
}
.userList {
background: #fff;
.list-item {
padding-left: 0.2rem;
}
.image_1 {
align-self: center;
width: 0.4rem;
height: 0.4rem;
border-radius: 50%;
box-shadow: 0 0 1px #6f6f6f;
}
.right-section {
margin-left: 0.15rem;
padding: 0.14rem 0 0.18rem;
flex: 1 1 auto;
box-shadow: 0px 0.005rem rgb(234, 234, 234);
height: 0.66rem;
}
.top-group {
margin-right: 0.1rem;
}
.text_6 {
margin-top: 0.09rem;
color: rgb(180, 182, 189);
font-size: 0.12rem;
line-height: 0.12rem;
letter-spacing: 0.012rem;
white-space: nowrap;
}
.text_2 {
color: rgb(2, 2, 2);
font-size: 0.15rem;
line-height: 0.14rem;
letter-spacing: 0.015rem;
white-space: nowrap;
}
.text_4 {
margin-bottom: 0.05rem;
color: rgb(193, 196, 204);
font-size: 0.12rem;
line-height: 0.095rem;
letter-spacing: 0.012rem;
white-space: nowrap;
}
.text_11 {
margin-bottom: 0.03rem;
color: rgb(2, 2, 2);
font-size: 0.15rem;
line-height: 0.14rem;
letter-spacing: 0.015rem;
white-space: nowrap;
}
.right-text-wrapper {
padding: 0.035rem 0.08rem;
color: rgb(115, 129, 255);
margin-left: 0.1rem;
font-size: 0.11rem;
line-height: 0.11rem;
letter-spacing: 0.011rem;
white-space: nowrap;
background-color: rgba(115, 129, 255, 0.1);
border-radius: 0.09rem;
height: 0.18rem;
}
.text_13 {
margin-right: 0.03rem;
}
// .group_2 {
// padding-bottom: 0.15rem;
// flex: 1 1 auto;
// overflow-y: auto;
// }
.group_4 {
padding: 0 0.01rem;
padding-left: 0.2rem;
}
.group_5 {
padding-left: 0.2rem;
margin-top: 0.015rem;
}
.group_4:active,
.group_5:active {
background: #efefef;
}
.group_8 {
padding-left: initial;
}
.view_2 {
margin-left: 0.11rem;
padding: 0.18rem 0.035rem 0.14rem;
height: 0.67rem;
margin-right: 0.03rem;
}
.view_4 {
margin-left: 0.16rem;
padding: 0.15rem 0 0.14rem;
height: 0.67rem;
}
.view_3 {
margin-right: initial;
}
.view_5 {
margin-right: initial;
}
.text_16 {
margin-top: 0.07rem;
color: rgb(193, 196, 204);
line-height: 0.095rem;
margin-right: 0.095rem;
}
.text_28 {
margin-top: initial;
position: absolute;
left: 0;
bottom: 0.17rem;
}
.text_8 {
line-height: 0.14rem;
}
.text_9 {
margin-right: 0.025rem;
}
.view_6 {
color: initial;
font-size: initial;
line-height: initial;
letter-spacing: initial;
white-space: initial;
}
.text_15 {
margin-bottom: initial;
color: rgb(180, 182, 189);
line-height: 0.12rem;
margin-top: 0.08rem;
}
.view_19 {
margin-left: 0.045rem;
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,812 @@
<template>
<view>
<u-navbar back-text="" title="个人主页"></u-navbar>
<!-- 用户信息详情 -->
<view class="user-detail">
<!-- 背景图 -->
<view class="user-bg">
<image :src="mybg"></image>
</view>
<!-- 详细信息 -->
<view class="user-detail-info">
<view class="user-detail-top">
<!-- 头像 私信 关注 -->
<view class="user-avatar-box">
<view class="user-detail-info-avatar">
<u-avatar class="image_2" size="144" :src="$u.http.config.imgUrl + userInfo.baseData.head">
</u-avatar>
</view>
<view class="user-operate">
<u-button shape="circle" v-if="userInfo.carewState&&vuex_user.id !== userId" :type="userInfo.carewState.includes('未关注') ? 'primary' : 'default'" @click="onFollow">{{
userInfo.carewState.includes('未关注')?'关注':userInfo.carewState }}</u-button>
<view class="user-message" @click="GoChat" v-if="vuex_user.id !== userId">
<image src="/static/common/img/homepage/message.png"></image>
</view>
<view v-else style="height: 96rpx;"></view>
</view>
</view>
<!-- 用户姓名 -->
<view class="user-name">
<text>{{ attestation.name||userInfo.baseData.name || "-" }}</text>
<image v-if="userInfo.isCertifyStatus" src="/static/common/img/homepage/frame.png"></image>
</view>
<!-- 用户学校信息 -->
<view class="user-school" v-if="baseShow === true && otherUserType === 0">
<text>{{ findRow.schoolName || "-" }}</text>
<!-- 学院 -->
<text v-if="findRow.college">{{
findRow.college
}}</text>
<text class="text_2" style="margin-right: 0.05rem" v-if="findRow.major">{{ findRow.major }}</text>
<!-- 年级 -->
<text class="text_2" v-if="findRow.startYear">{{
findRow.startYear + "级"
}}</text>
</view>
<!-- 用户地址 先不放开 -->
<view class="user-identity"> </view>
<!-- 获赞 粉丝 关注 -->
<!-- <view class="user-like">
<view class="likes" v-for="(item, index) in userlikes" :key="index">
<text class="like-num">{{ item.num }}</text>
<text class="like-name">{{ item.name }}</text>
</view>
</view> -->
<view class="user-tabs">
<view class="user-tabs-item" :class="{ 'tabs-active': swiperCurrent == index }"
v-for="(item, index) in userTabs" :key="index" @click="tabsChange(index)">
<image :src="swiperCurrent == index ? item.selectedImage : item.image"></image>
<text>{{ item.name }}</text>
</view>
</view>
</view>
<view class="content">
<view class="release-content" v-if="swiperCurrent == 0">
<information :list="userList" @onStar="onStar" type="1" :schoolId="schoolId" route="2" :flag="type" :borderRadius="true">
</information>
</view>
<view class="user-info" v-if="swiperCurrent == 1">
<view class="userinfo-box" v-if="userInfo">
<view class="userinfo-title">
<text>基本信息</text>
</view>
<view class="userinfo-detail">
<view class="justify-between detail-row">
<text class="detail-title">手机号码</text>
<text class="detail-content">{{ userInfo.baseData.phone }}</text>
</view>
<view class="justify-between detail-row">
<text class="detail-title">年龄</text>
<text class="detail-content">{{
userInfo.baseData.age
}}</text>
</view>
<view class="justify-between detail-row">
<text class="detail-title">现居地</text>
<text class="detail-content">{{
userInfo.baseData.address
}}</text>
</view>
<view class="justify-between detail-row">
<text class="detail-title">工作领域</text>
<text class="detail-content">{{
userInfo.baseData.workField
}}</text>
</view>
</view>
</view>
<!-- 教育经历 -->
<view class="" v-if="userInfo && otherUserType === 0">
<view class="userinfo-title"><text class="">教育经历</text>
</view>
<view class="userinfo-detail">
<view class="detail-row school-row" v-for="(item, index) in userInfo.edcationList"
v-if="item.certifyStatus == 1 || true" :key="index">
<view class="detail-row-item">
<image :src="$u.http.config.imgUrl + item.schoolLogo.slice(1)" />
<view class="school-info">
<view class="school-name">
<view class="text_24">{{ item.schoolName }}</view>
<view class="text_25 status-box" :class="item.certifyStatus == 0
? 'color2'
: item.certifyStatus == 1
? 'color1'
: 'color3'
">{{ certifyArr[item.certifyStatus] }}</view>
</view>
<view class="professional-info">
<view>{{ item.startYear }}</view>
<view class="text_27">{{ item.major }}</view>
<view class="text_28">{{ item.educationStr }}</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 任职院校 -->
<view class="" v-if="userInfo && otherUserType === 1">
<view class="userinfo-title"><text class="text_21">任职院校</text>
</view>
<view class="userinfo-detail">
<view class="detail-row school-row" v-for="(item, index) in userInfo.edcationList"
v-if="item.certifyStatus == 1 || true" :key="index">
<view class="detail-row-item">
<image :src="$u.http.config.imgUrl + item.logo.slice(1)" class="image_17" />
<view class="school-info">
<view class="school-name">
<text class="text_24">{{ item.school }}</text>
<text class="text_25 status-box" :class="item.certifyStatus == 0
? 'color2'
: item.certifyStatus == 1
? 'color1'
: 'color3'
">{{ certifyArr[item.certifyStatus] }}</text>
</view>
<view class="flex-row group_20">
<text>{{ item.schoolJob }}</text>
<!-- <text>{{item.startYear}}年入学</text> -->
<!-- <text class="text_27">{{item.major}}</text> -->
<!-- <text class="text_28">{{item.educationStr}}</text> -->
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import information from "../../../components/Information.vue";
import release from "@/static/common/img/homepage/released.png";
import releaseSelected from "@/static/common/img/homepage/released-selected.png";
import person from "@/static/common/img/homepage/person.png";
import personSelected from "@/static/common/img/homepage/person-selected.png";
import mybg1 from '@/static/common/img/my/mybg1.png'
import mybg2 from '@/static/common/img/my/mybg2.png'
import mybg3 from '@/static/common/img/my/mybg3.png'
import mybg4 from '@/static/common/img/my/mybg4.png'
import mybg5 from '@/static/common/img/my/mybg5.png'
import mybg6 from '@/static/common/img/my/mybg6.png'
import mybg7 from '@/static/common/img/my/mybg7.png'
import mybg8 from '@/static/common/img/my/mybg8.png'
import mybg9 from '@/static/common/img/my/mybg9.png'
import mybg10 from '@/static/common/img/my/mybg10.png'
import mybg11 from '@/static/common/img/my/mybg11.png'
import mybg12 from '@/static/common/img/my/mybg12.png'
import mybg13 from '@/static/common/img/my/mybg13.png'
import mybg14 from '@/static/common/img/my/mybg14.png'
import mybg15 from '@/static/common/img/my/mybg15.png'
import mybg16 from '@/static/common/img/my/mybg16.png'
import mybg17 from '@/static/common/img/my/mybg17.png'
import mybg18 from '@/static/common/img/my/mybg18.png'
import mybg19 from '@/static/common/img/my/mybg19.png'
import mybg20 from '@/static/common/img/my/mybg20.png'
export default {
components: {
information: information,
},
data() {
return {
userId: "",
swiperCurrent: 0,
current: 0,
schoolId: "",
type: "",
userList: [],
navList: [
{
name: "个人信息",
},
{
name: "Ta的发布",
},
],
certifyArr: {
0: "未认证",
1: "已认证",
2: "审核中",
},
userInfo: {},
word: "",
otherUserType: true,
attestation: {},
//
findRow: {},
//
qyRow: {},
//
baseShow: true,
//
qyShow: false,
userlikes: [
{
num: 200,
name: "获赞",
},
{
num: 200,
name: "粉丝",
},
{
num: 200,
name: "关注",
},
],
userTabs: [
{
image: release,
selectedImage: releaseSelected,
name: "发布",
},
{
image: person,
selectedImage: personSelected,
name: "个人信息",
},
],
mybg1,
mybg2,
mybg3 ,
mybg4 ,
mybg5 ,
mybg6 ,
mybg7 ,
mybg8 ,
mybg9 ,
mybg10,
mybg11,
mybg12,
mybg13,
mybg14,
mybg15,
mybg16,
mybg17,
mybg18,
mybg19,
mybg20,
mybg: '',
};
},
computed: {
randomBg() {
const bgArray = [
this.mybg1, this.mybg2, this.mybg3, this.mybg4, this.mybg5,
this.mybg6, this.mybg7, this.mybg8, this.mybg9, this.mybg10,
this.mybg11, this.mybg12, this.mybg13, this.mybg14, this.mybg15,
this.mybg16, this.mybg17, this.mybg18, this.mybg19, this.mybg20
];
const randomIndex = Math.floor(Math.random() * bgArray.length);
return bgArray[randomIndex];
}
},
created() {
this.mybg = this.randomBg;
},
onLoad(e) {
if (!e.id) {
uni.switchTab({
url: "../../main/index/index",
});
return;
}
this.type = e.type;
this.userId = e.id;
this.word = e.word;
// this.getDetail();
// this.getUserSchool();
},
onShow() {
this.getDetail();
this.mybg = this.randomBg;
// getDetail
/* if (this.current == 0) {
setTimeout(() => {
this.getUserHelp();
}, 500);
} */
},
methods: {
lookQY() {
console.log(7777777);
},
getUserHelp() {
console.log('this.findRow--------------',this.findRow);
const data = {
userId: this.userId,
schoolId:this.findRow.schoolId,
pageIndex: 1,
pageSize: 10,
};
this.$u.apiList.Publishs(data).then((res) => {
this.userList = res.items;
});
//
/* this.$u.apiList.UserHelp(data).then((res) => {
this.userList = res.items;
}); */
},
getDetail() {
this.$u.api
.getUserInfo({
userId: this.userId,
})
.then((res) => {
console.log('res-----',res);
this.userInfo = res;
this.attestation = Object.assign(this.attestation, res.attestation);
this.otherUserType = res.userType;
// console.log(this.userInfo, 1)
this.findRow = res.edcationList[0];
if (res.qyAttestation) {
this.qyShow = true;
this.qyRow = res.qyAttestation;
}
// id id
this.getUserHelp();
});
},
//
GoChat() {
uni.navigateTo({
url:
"../../message/dialogBox/dialogBox?id=" + this.userId + "&chatType=0",
});
},
// tabsswiper
tabsChange(index) {
if (index == 0) {
this.getUserHelp();
}
this.swiperCurrent = index;
},
// swiper-itemtabs
transition(e) {
let dx = e.detail.dx;
this.$refs.uTabs.setDx(dx);
},
// swiperswiperdx
// swipertabsswiper
animationfinish(e) {
let current = e.detail.current;
this.$refs.uTabs.setFinishCurrent(current);
this.swiperCurrent = current;
this.current = current;
},
onFollow() {
const data = {
userId: this.vuex_user.id,
carewId: this.userId,
};
this.$u.apiList.InsertOrDelFollow(data).then((res) => {
this.getDetail();
});
},
getUserSchool() {
this.$u.apiList.GetUserSchool().then((res) => {
//
if ([0,2].includes(this.vuex_user.userType)) {
this.schoolId = res.items.schoolId;
}
//
if (this.vuex_user.userType === 1) {
this.schoolId = res.jzgItems.schoolId;
}
});
},
async onStar(val) {
console.log("收藏--");
//
const req = {
userId: this.vuex_user.id,
};
const result = await this.$u.apiList.MyPage(req);
console.log(JSON.parse(JSON.stringify(result)), "result");
const edcationList = result.edcationList;
if (!edcationList.length) {
return this.$refs.uToast.show({
title: "认证后可进行收藏操作",
type: "none",
});
}
// const findRow = edcationList.find((x) => x.isSelected === true);
const findRow = edcationList[0];
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "认证后可进行收藏操作",
type: "none",
});
}
// return
const data = {
id: val.id,
type: val.type,
};
this.$u.apiList
.LikeCollect(data)
.then((res) => {
if (val.type == 0) {
if (val.isCllect) {
val.isCllect = false;
val.collectCount -= 1;
this.$refs.uToast.show({
title: "取消收藏成功",
type: "success",
});
} else {
val.isCllect = true;
val.collectCount += 1;
this.$refs.uToast.show({
title: "收藏成功",
type: "success",
});
}
} else if (val.type == 1) {
if (val.isCllect) {
val.isCllect = false;
val.collectCount -= 1;
this.$refs.uToast.show({
title: "取消收藏成功",
type: "success",
});
} else {
val.isCllect = true;
val.collectCount += 1;
this.$refs.uToast.show({
title: "收藏成功",
type: "success",
});
}
}
})
.catch((err) => {
this.$refs.uToast.show({
title: "收藏失败",
type: "error",
});
});
},
//
router() {
if (this.type == 0) {
uni.switchTab({
url: "../../message/msgList/msgList",
});
} else if (this.type == 1) {
uni.navigateTo({
url:
"../../message/dialogBox/dialogBox?id=" +
this.userId +
"&chatType=0&type=0",
});
} else if (this.type == 2) {
this.$u.route({
url: "pages/AlumniCircle/Alumni/Alumni",
});
} else if (this.type == 3) {
let url = "pages/main/search/search";
if (this.word) {
url = "pages/main/search/search?word=" + this.word;
}
this.$u.route({
url: url,
});
} else if (this.type == 4) {
uni.navigateBack({
delta: 1,
});
} else {
uni.switchTab({
url: "pages/main/index/index",
});
}
},
// scroll-view
onreachBottom() { },
},
};
</script>
<style lang="scss" scoped>
.user-detail {
position: relative;
background: #f6f8fa;
width: 100%;
min-height: 100vh;
}
.user-bg {
position: absolute;
width: 100%;
height: 320rpx;
overflow: hidden;
image {
width: 100%;
object-fit: cover;
}
}
.user-detail-info {
width: 100%;
position: absolute;
top: 320rpx;
.user-detail-top {
padding: 0 48rpx;
background: #fff;
}
.user-avatar-box {
width: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
.user-operate {
display: flex;
flex-direction: row-reverse;
align-items: center;
width: 300rpx;
justify-content: space-between;
padding-top: 20rpx;
.user-message {
width: 96rpx;
height: 96rpx;
border-radius: 50%;
background: #f6f8f9;
display: flex;
align-items: center;
justify-content: center;
image {
width: 48rpx;
height: 48rpx;
}
}
}
}
.user-detail-info-avatar {
width: 154rpx;
height: 154rpx;
border-radius: 50%;
background-color: #fefcff;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: -50rpx;
left: 48rpx;
}
}
.user-name {
margin-top: 15rpx;
margin-bottom: 16rpx;
font-size: 32rpx;
font-weight: 800;
color: #1f2232;
display: flex;
align-items: center;
image {
width: 40rpx;
height: 40rpx;
margin-left: 10rpx;
}
}
.user-school {
text {
display: inline-block;
background: #f6f8f9;
height: 60rpx;
line-height: 60rpx;
padding: 0 10rpx;
margin-right: 16rpx;
font-size: 24rpx;
margin-bottom: 16rpx;
}
}
.user-like {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 30rpx 30rpx;
.likes {
display: flex;
flex-direction: column;
align-items: center;
.like-num {
font-weight: 800;
font-size: 36rpx;
color: #1f2232;
}
.like-name {
font-weight: 500;
font-size: 24rpx;
color: #616977;
}
}
}
.user-tabs {
display: flex;
flex-direction: row;
justify-content: space-between;
.user-tabs-item {
width: 50%;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 4rpx solid #fff;
padding-bottom: 20rpx;
color: #8697ac;
font-weight: bold;
image {
width: 48rpx;
height: 48rpx;
margin-right: 20rpx;
}
}
.tabs-active {
border-bottom: 4rpx solid #48adde;
text {
color: #3cb5fb;
}
}
}
.user-info {
padding: 32rpx;
}
.userinfo-title {
font-weight: bold;
font-size: 32rpx;
color: rgba(0, 0, 0, 0.9);
height: 60rpx;
}
.userinfo-box {
margin-bottom: 32rpx;
}
.userinfo-detail {
padding:10rpx 32rpx;
background: #fff;
border-radius: 32rpx;
border: 3rpx solid;
border-image: linear-gradient(180deg, rgba(255, 255, 255, 0.4), rgba(255, 255, 255, 0), rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.1)) 3 3;
.detail-row {
height: 106rpx;
line-height: 106rpx;
border-bottom: 2rpx solid #F6F8F9;
&:last-child {
border-bottom: none;
}
.detail-title {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.9);
}
.detail-content {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.6);
}
image {
width: 102rpx;
height: 102rpx;
}
.detail-row-item {
height: 106rpx;
display: flex;
flex-direction: row;
align-items: center;
image {
margin-right: 30rpx;
}
}
.school-info {
display: flex;
flex-direction: column;
height: 102rpx;
.school-name {
// height: 50%;
height: 51rpx;
line-height: 51rpx;
font-weight: bold;
font-size: 28rpx;
color: rgba(0, 0, 0, 0.9);
view {
display: inline-block;
}
}
.professional-info {
height: 51rpx;
line-height: 51rpx;
view {
display: inline-block;
margin-right: 20rpx;
font-size: 24rpx;
color: #8697AC;
}
}
}
}
.school-row {
// line-height: 126rpx;
height: 126rpx;
display: flex;
align-items: center;
}
.status-box{
width: 100rpx;
height: 40rpx;
line-height: 40rpx;
text-align: center;
border-radius: 12rpx;
font-size: 24rpx;
margin-left: 20rpx;
font-weight: normal;
display: inline-block;
&.color1 {
background-color: #3cb4fb;
color: #fff;
}
&.color2 {
background-color: #ffeceb;
color: #ff453a;
}
&.color3 {
background-color: #FFB800;
color: #fff;
}
}
}
</style>

View File

@ -0,0 +1,367 @@
const SCHOOL_CONFIG = {
南昌理工: {
ai: {
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
index: 0,
},
welcome: {
name: "迎新",
icon: "/static/common/img/homepage/icon_迎新.png",
icon2: "/static/common/img/homepage/icon_迎新_gray.png",
url: "https://yxxt.nut.edu.cn:8090/#/",
type: "http",
index: 4,
},
repair: {
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 7,
},
score: {
name: "成绩查询",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "https://iwglxt.nut.edu.cn/",
type: "http",
index: 5,
},
oldStudent: {
name: "老生缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "https://pay.nut.edu.cn/",
type: "http",
index: 1,
},
electricityBill: {
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "https://if.nut.edu.cn/",
type: "http",
index: 6,
},
},
新能源: {
ai: {
name: "源小新",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://ai.tynxy.com:8001/",
type: "http",
index: 0,
},
welcome: {
name: "迎新",
icon: "/static/common/img/homepage/icon_迎新.png",
icon2: "/static/common/img/homepage/icon_迎新_gray.png",
url: "https://yx.tynxy.com:8090/#/login",
type: "http",
index: 4,
},
library: {
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://a.xiumi.us/stage/v5/33A6c/151995615#/",
type: "http",
index: 10,
},
score: {
name: "成绩查询",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "http://cas.tynxy.com:7171/cas/login/",
type: "http",
index: 5,
},
electricityBill: {
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "http://vpn.tynxy.com:10081/",
type: "http",
index: 6,
},
},
亚视: {
repair: {
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "http://gdysyx.gdatv.edu.cn:8099/#/",
type: "http",
index: 7,
},
},
};
/**
* 获取特定学校的所有功能配置
* @param {string} schoolName - 学校名称
* @returns {Object} - 该学校的所有功能配置
*/
export const getSchoolConfig = (schoolName = "") => {
// 查找匹配的学校配置
const matchedSchool = Object.keys(SCHOOL_CONFIG).find((key) =>
schoolName.includes(key)
);
return matchedSchool ? SCHOOL_CONFIG[matchedSchool] : {};
};
// 保留之前的单项获取函数,以便向后兼容(首页使用)
export const getAIAssistantConfig = (schoolName = "") => {
const config = getSchoolConfig(schoolName);
return (
config.ai || {
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
}
);
};
export const getOldStudentConfig = (schoolName = "") => {
const config = getSchoolConfig(schoolName);
return (
config.oldStudent || {
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
}
);
};
/**
* 首页功能列表数据
*/
export const functionListing = [
{
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
},
{
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
},
{
name: "返校预约",
icon: "/static/common/img/homepage/icon_返校预约.png",
icon2: "/static/common/img/homepage/icon_返校预约_gray.png",
url: "/pages/my/BackSchool/BackSchool",
type: "page",
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
// {
// name: "查询档案",
// icon: "/static/common/img/homepage/icon_查询档案.png",
// url: "",
// type: "page",
// },
{
name: "全部服务",
icon: "/static/common/img/homepage/icon_全部服务.png",
icon2: "/static/common/img/homepage/icon_全部服务.png",
},
];
// 教师首页配置 vuex_user.userType==1
export const TEACHER_CONFIG = [
{
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
index: 0,
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 7,
},
{
name: "DL",
icon: "/static/common/img/homepage/icon_DL.png",
icon2: "/static/common/img/homepage/icon_DL_gray.png",
url: "",
type: "page",
},
];
/**
* 全部服务
*/
export const functionListing2 = [
{
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
},
{
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
},
{
name: "返校预约",
icon: "/static/common/img/homepage/icon_返校预约.png",
icon2: "/static/common/img/homepage/icon_返校预约_gray.png",
url: "/pages/my/BackSchool/BackSchool",
type: "page",
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "迎新",
icon: "/static/common/img/homepage/icon_迎新.png",
icon2: "/static/common/img/homepage/icon_迎新_gray.png",
url: "",
type: "http",
},
{
name: "就业帮助",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "",
type: "page",
},
{
name: "活动报名",
icon: "/static/common/img/homepage/icon_活动报名.png",
icon2: "/static/common/img/homepage/icon_活动报名_gray.png",
url: "",
type: "page",
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "",
type: "http",
},
{
name: "勤工俭学",
icon: "/static/common/img/homepage/icon_勤工俭学.png",
icon2: "/static/common/img/homepage/icon_勤工俭学_gray.png",
url: "",
type: "page",
},
{
name: "办事指南",
icon: "/static/common/img/homepage/icon_办事指南.png",
icon2: "/static/common/img/homepage/icon_办事指南_gray.png",
url: "",
type: "page",
},
{
name: "图书借阅",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "",
type: "page",
},
{
name: "查询档案",
icon: "/static/common/img/homepage/icon_查询档案.png",
icon2: "/static/common/img/homepage/icon_查询档案_gray.png",
url: "",
type: "page",
},
{
name: "选课",
icon: "/static/common/img/homepage/icon_选课.png",
icon2: "/static/common/img/homepage/icon_选课_gray.png",
url: "",
type: "page",
},
{
name: "DL",
icon: "/static/common/img/homepage/icon_DL.png",
icon2: "/static/common/img/homepage/icon_DL_gray.png",
url: "",
type: "page",
},
{
name: "校园跑",
icon: "/static/common/img/homepage/icon_校园跑.png",
icon2: "/static/common/img/homepage/icon_校园跑_gray.png",
url: "",
type: "page",
},
];
export const functionListing3 = [
{
name: "校友名片",
icon: "/static/common/img/homepage/icon_校友名片.png",
icon2: "/static/common/img/homepage/icon_校友名片_gray.png",
url: "",
type: "page",
},
{
name: "校友活动",
icon: "/static/common/img/homepage/icon_校友活动.png",
icon2: "/static/common/img/homepage/icon_校友活动_gray.png",
url: "",
type: "page",
},
{
name: "电子校友卡",
icon: "/static/common/img/homepage/icon_电子校友卡.png",
icon2: "/static/common/img/homepage/icon_电子校友卡_gray.png",
url: "",
type: "page",
},
{
name: "校友会组织",
icon: "/static/common/img/homepage/icon_校友会组织.png",
icon2: "/static/common/img/homepage/icon_校友会组织_gray.png",
url: "",
type: "page",
},
{
name: "助力母校",
icon: "/static/common/img/homepage/icon_助力母校.png",
icon2: "/static/common/img/homepage/icon_助力母校_gray.png",
url: "",
type: "page",
},
];

596
pages/home/data/index.js Normal file
View File

@ -0,0 +1,596 @@
const SCHOOL_CONFIG = {
南昌理工: {
ai: {
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
index: 0,
},
// welcome: {
// name: "迎新",
// icon: "/static/common/img/homepage/icon_迎新.png",
// icon2: "/static/common/img/homepage/icon_迎新_gray.png",
// url: "https://yxxt.nut.edu.cn:8090/#/",
// type: "http",
// index: 4,
// },
repair: {
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 6,
},
score: {
name: "成绩查询",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "https://iwglxt.nut.edu.cn/",
type: "http",
index: 4,
},
oldStudent: {
name: "老生缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "https://pay.nut.edu.cn/",
type: "http",
index: 1,
},
electricityBill: {
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "https://if.nut.edu.cn/",
type: "http",
index: 5,
},
},
新能源: {
ai: {
name: "源小新",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://ai.tynxy.com:8001/",
type: "http",
index: 0,
},
// welcome: {
// name: "迎新",
// icon: "/static/common/img/homepage/icon_迎新.png",
// icon2: "/static/common/img/homepage/icon_迎新_gray.png",
// url: "https://yx.tynxy.com:8090/#/login",
// type: "http",
// index: 4,
// },
library: {
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://a.xiumi.us/stage/v5/33A6c/151995615#/",
type: "http",
index: 9,
},
score: {
name: "成绩查询",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "http://cas.tynxy.com:7171/cas/login/",
type: "http",
index: 4,
},
electricityBill: {
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "http://vpn.tynxy.com:10081/",
type: "http",
index: 5,
},
},
亚视: {
ai: {
name: "广小演",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://gxy.gdatv.edu.cn:8103/",
type: "http",
index: 0,
},
electricityBill: {
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "https://payment.gdatv.edu.cn/df?code=021aLZZv3Knm753sCR0w3k1W7w3aLZZu&state=1",
type: "http",
index: 5,
},
repair: {
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "http://gdysyx.gdatv.edu.cn:8099/#/",
type: "http",
index: 6,
},
library: {
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://v1.chaoxing.com/wechatSet/mobileIndex?fidEnc=edb7ce62838ef070&pageId=2572",
type: "http",
index: 9,
},
},
};
/**
* 获取特定学校的所有功能配置
* @param {string} schoolName - 学校名称
* @returns {Object} - 该学校的所有功能配置
*/
export const getSchoolConfig = (schoolName = "") => {
// 查找匹配的学校配置
const matchedSchool = Object.keys(SCHOOL_CONFIG).find((key) =>
schoolName.includes(key)
);
return matchedSchool ? SCHOOL_CONFIG[matchedSchool] : {};
};
// 保留之前的单项获取函数,以便向后兼容(首页使用)
export const getAIAssistantConfig = (schoolName = "") => {
const config = getSchoolConfig(schoolName);
return (
config.ai || {
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
}
);
};
export const getOldStudentConfig = (schoolName = "") => {
const config = getSchoolConfig(schoolName);
return (
config.oldStudent || {
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
}
);
};
/**
* 首页功能列表数据
*/
export const functionListing = [
{
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
},
{
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
},
{
name: "返校预约",
icon: "/static/common/img/homepage/icon_返校预约.png",
icon2: "/static/common/img/homepage/icon_返校预约_gray.png",
url: "/pages/my/BackSchool/BackSchool",
type: "page",
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "全部服务",
icon: "/static/common/img/homepage/icon_全部服务.png",
icon2: "/static/common/img/homepage/icon_全部服务.png",
},
];
// 教师首页配置 vuex_user.userType==1
export const TEACHER_CONFIG = [
{
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
index: 0,
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 7,
},
{
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://book.nut.edu.cn/",
type: "http",
index: 9,
},
];
// 南昌理工学院配置
export const NANCHANG_CONFIG = {
在校生: [
{
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
},
{
name: "老生缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "https://pay.nut.edu.cn/",
type: "http",
index: 1,
},
{
name: "网上购电",
icon: "/static/common/img/homepage/icon_网上购电.png",
icon2: "/static/common/img/homepage/icon_网上购电_gray.png",
url: "https://if.nut.edu.cn/",
type: "http",
index: 5,
},
{
name: "成绩查询",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "https://iwglxt.nut.edu.cn/",
type: "http",
index: 4,
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 6,
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://book.nut.edu.cn/",
type: "http",
index: 9,
},
{
name: "选课",
icon: "/static/common/img/homepage/icon_选课.png",
icon2: "/static/common/img/homepage/icon_选课_gray.png",
url: "",
type: "page",
},
{
name: "办事指南",
icon: "/static/common/img/homepage/icon_办事指南.png",
icon2: "/static/common/img/homepage/icon_办事指南_gray.png",
url: "",
type: "page",
},
{
name: "勤工俭学",
icon: "/static/common/img/homepage/icon_勤工俭学.png",
icon2: "/static/common/img/homepage/icon_勤工俭学_gray.png",
url: "",
type: "page",
},
{
name: "校园跑",
icon: "/static/common/img/homepage/icon_校园跑.png",
icon2: "/static/common/img/homepage/icon_校园跑_gray.png",
url: "",
type: "page",
},
{
name: "查询档案",
icon: "/static/common/img/homepage/icon_查询档案.png",
icon2: "/static/common/img/homepage/icon_查询档案_gray.png",
url: "",
type: "page",
},
],
毕业生: [
{
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
},
{
name: "返校预约",
icon: "/static/common/img/homepage/icon_返校预约.png",
icon2: "/static/common/img/homepage/icon_返校预约_gray.png",
url: "/pages/my/BackSchool/BackSchool",
type: "page",
},
{
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://book.nut.edu.cn/",
type: "http",
index: 9,
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "DL",
icon: "/static/common/img/homepage/icon_DL.png",
icon2: "/static/common/img/homepage/icon_DL_gray.png",
url: "",
type: "page",
},
{
name: "校友名片",
icon: "/static/common/img/homepage/icon_校友名片.png",
icon2: "/static/common/img/homepage/icon_校友名片_gray.png",
url: "",
type: "page",
},
{
name: "校友活动",
icon: "/static/common/img/homepage/icon_校友活动.png",
icon2: "/static/common/img/homepage/icon_校友活动_gray.png",
url: "",
type: "page",
},
{
name: "电子校友卡",
icon: "/static/common/img/homepage/icon_电子校友卡.png",
icon2: "/static/common/img/homepage/icon_电子校友卡_gray.png",
url: "",
type: "page",
},
{
name: "校友会组织",
icon: "/static/common/img/homepage/icon_校友会组织.png",
icon2: "/static/common/img/homepage/icon_校友会组织_gray.png",
url: "",
type: "page",
},
{
name: "助力母校",
icon: "/static/common/img/homepage/icon_助力母校.png",
icon2: "/static/common/img/homepage/icon_助力母校_gray.png",
url: "",
type: "page",
},
],
教师: [
{
name: "南小翼",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "http://sl.vrgon.com:2222/",
type: "http",
index: 0,
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "https://bx.nut.edu.cn/#/",
type: "http",
index: 7,
},
{
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "https://book.nut.edu.cn/",
type: "http",
index: 9,
},
// {
// name: "DL",
// icon: "/static/common/img/homepage/icon_DL.png",
// icon2: "/static/common/img/homepage/icon_DL_gray.png",
// url: "",
// type: "page",
// },
],
};
/**
* 全部服务
*/
export const functionListing2 = [
{
name: "ai智能",
icon: "/static/common/img/homepage/icon_南小翼.png",
icon2: "/static/common/img/homepage/icon_南小翼_gray.png",
url: "",
},
{
name: "缴费",
icon: "/static/common/img/homepage/icon_缴费.png",
icon2: "/static/common/img/homepage/icon_缴费_gray.png",
url: "",
type: "page",
},
{
name: "返校预约",
icon: "/static/common/img/homepage/icon_返校预约.png",
icon2: "/static/common/img/homepage/icon_返校预约_gray.png",
url: "/pages/my/BackSchool/BackSchool",
type: "page",
},
{
name: "心愿单",
icon: "/static/common/img/homepage/icon_心愿单.png",
icon2: "/static/common/img/homepage/icon_心愿单_gray.png",
url: "/pages/my/wishlist/wishlist",
type: "page",
},
// {
// name: "迎新",
// icon: "/static/common/img/homepage/icon_迎新.png",
// icon2: "/static/common/img/homepage/icon_迎新_gray.png",
// url: "",
// type: "http",
// },
{
name: "就业帮助",
icon: "/static/common/img/homepage/icon_就业帮助.png",
icon2: "/static/common/img/homepage/icon_就业帮助_gray.png",
url: "",
type: "page",
},
{
name: "活动报名",
icon: "/static/common/img/homepage/icon_活动报名.png",
icon2: "/static/common/img/homepage/icon_活动报名_gray.png",
url: "",
type: "page",
},
{
name: "报修",
icon: "/static/common/img/homepage/icon_报修.png",
icon2: "/static/common/img/homepage/icon_报修_gray.png",
url: "",
type: "http",
},
{
name: "勤工俭学",
icon: "/static/common/img/homepage/icon_勤工俭学.png",
icon2: "/static/common/img/homepage/icon_勤工俭学_gray.png",
url: "",
type: "page",
},
{
name: "办事指南",
icon: "/static/common/img/homepage/icon_办事指南.png",
icon2: "/static/common/img/homepage/icon_办事指南_gray.png",
url: "",
type: "page",
},
{
name: "图书馆",
icon: "/static/common/img/homepage/icon_图书借阅.png",
icon2: "/static/common/img/homepage/icon_图书借阅_gray.png",
url: "",
type: "page",
},
{
name: "查询档案",
icon: "/static/common/img/homepage/icon_查询档案.png",
icon2: "/static/common/img/homepage/icon_查询档案_gray.png",
url: "",
type: "page",
},
{
name: "选课",
icon: "/static/common/img/homepage/icon_选课.png",
icon2: "/static/common/img/homepage/icon_选课_gray.png",
url: "",
type: "page",
},
{
name: "DL",
icon: "/static/common/img/homepage/icon_DL.png",
icon2: "/static/common/img/homepage/icon_DL_gray.png",
url: "",
type: "page",
},
{
name: "校园跑",
icon: "/static/common/img/homepage/icon_校园跑.png",
icon2: "/static/common/img/homepage/icon_校园跑_gray.png",
url: "",
type: "page",
},
// {},
];
// 毕业生敬请期待
export const functionListing3 = [
{
name: "校友名片",
icon: "/static/common/img/homepage/icon_校友名片.png",
icon2: "/static/common/img/homepage/icon_校友名片_gray.png",
url: "",
type: "page",
},
{
name: "校友活动",
icon: "/static/common/img/homepage/icon_校友活动.png",
icon2: "/static/common/img/homepage/icon_校友活动_gray.png",
url: "",
type: "page",
},
{
name: "电子校友卡",
icon: "/static/common/img/homepage/icon_电子校友卡.png",
icon2: "/static/common/img/homepage/icon_电子校友卡_gray.png",
url: "",
type: "page",
},
{
name: "校友会组织",
icon: "/static/common/img/homepage/icon_校友会组织.png",
icon2: "/static/common/img/homepage/icon_校友会组织_gray.png",
url: "",
type: "page",
},
{
name: "助力母校",
icon: "/static/common/img/homepage/icon_助力母校.png",
icon2: "/static/common/img/homepage/icon_助力母校_gray.png",
url: "",
type: "page",
},
];

View File

@ -0,0 +1,85 @@
<template>
<!-- 首页-校园资讯组件 -->
<view class="campus-info-page">
<!-- 使用内容卡片组件 -->
<content-card
v-for="(card, index) in contentCards"
:key="index"
:cardData="card"
></content-card>
</view>
</template>
<script>
import ContentCard from "@/components/ContentCard.vue";
export default {
name: "CampusInfo",
components: {
ContentCard,
},
data() {
return {
//
contentCards: [
//
{
user: {
avatar: "/static/common/img/homepage/avatar3.png",
name: "calista33",
meta: "2小时前 北京大学",
},
content: "今日份走停停的小确幸。",
type: "image",
images: [
"/static/common/img/homepage/image-photo1.png",
"/static/common/img/homepage/image-photo2.png",
"/static/common/img/homepage/image-photo3.png",
],
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
//
{
user: {
avatar: "/static/common/img/homepage/avatar.png",
name: "Kohaku",
meta: "2小时前 北京大学",
},
content: "看看我拍的这个视频•",
type: "video",
cover: "/static/images/video-cover.png",
videoUrl: "https://example.com/video.mp4",
duration: 145, // 225
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
],
};
},
methods: {
goContentDetail(card) {
console.log(card);
this.$u.route({
url: "/pages/home/home/components/contentDetail/index",
// params: {
// card,
// },
});
},
},
};
</script>
<style lang="scss" scoped>
.campus-info-page {
padding: 32rpx 8rpx 0;
}
</style>

View File

@ -0,0 +1,668 @@
<template>
<view class="comment-section">
<!-- 评论统计 -->
<view class="comment-count">评论 {{ comments.length }}</view>
<!-- 评论列表 -->
<view class="comment-list">
<view
class="comment-item"
v-for="(comment, index) in comments"
:key="index"
>
<image
class="comment-avatar"
:src="comment.author.avatar"
mode="aspectFill"
></image>
<view class="comment-content">
<view class="comment-user">
<text class="comment-username">{{ comment.author.name }}</text>
<text class="comment-school">{{ comment.author.school }}</text>
<text class="comment-time">{{ comment.time }}</text>
</view>
<view class="comment-text">{{ comment.content }}</view>
<view class="comment-actions">
<view
class="reply-count"
v-if="comment.replyCount"
@click="handleViewReplies(comment)"
>
{{ comment.replyCount }}回复 >
</view>
<view class="like-btn" @click="handleLikeComment(index)">
<u-icon
name="heart"
:size="36"
:color="comment.isLiked ? '#ff5555' : '#999'"
></u-icon>
<text v-if="comment.likes">{{ comment.likes }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 底部操作栏 - 修改为上下两行布局 -->
<view class="footer-actions">
<!-- 上方输入框区域 -->
<view class="input-container">
<view class="comment-input" @click="handleShowCommentInput">
<text>高楼平地起评论全靠你...</text>
</view>
<view class="send-btn">
<!-- <u-icon name="arrow-right" :size="44" color="#4ca2ff"></u-icon> -->
<image
src="/static/common/img/homepage/icon-send.png"
mode="aspectFill"
style="width: 72rpx; height: 72rpx"
></image>
</view>
</view>
<!-- 下方操作按钮区域 -->
<view class="interaction-bar">
<view
class="action-item"
v-for="(item, index) in actionButtons"
:key="index"
@click="handleAction(item.action)"
>
<image
:src="item.icon"
mode="aspectFill"
style="width: 40rpx; height: 40rpx"
></image>
<text>{{ item.stat }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "CommentSection",
props: {
//
comments: {
type: Array,
default: () => [],
},
//
shareCount: {
type: Number,
default: 0,
},
//
commentCount: {
type: Number,
default: 0,
},
//
likeCount: {
type: Number,
default: 0,
},
//
favoriteCount: {
type: Number,
default: 0,
},
//
isLiked: {
type: Boolean,
default: false,
},
//
isFavorite: {
type: Boolean,
default: false,
},
// ID
postId: {
type: String,
default: "",
},
},
data() {
return {
// props
innerStats: {
shares: this.shareCount,
comments: this.commentCount,
likes: this.likeCount,
favorites: this.favoriteCount,
isLiked: this.isLiked,
isFavorite: this.isFavorite,
},
//
localComments: [],
//
actionButtons: [
{
icon: "/static/common/img/homepage/reply.png",
action: "forward",
stat: "102",
},
{
icon: "/static/common/img/homepage/comment.png",
action: "comment",
stat: "102",
},
{
icon: "/static/common/img/homepage/like.png",
action: "like",
stat: "212",
},
{
icon: "/static/common/img/homepage/star.png",
action: "favorite",
stat: "62",
},
],
};
},
watch: {
//
comments: {
immediate: true,
handler(newVal) {
this.localComments = JSON.parse(JSON.stringify(newVal));
},
},
shareCount(newVal) {
this.innerStats.shares = newVal;
},
commentCount(newVal) {
this.innerStats.comments = newVal;
},
likeCount(newVal) {
this.innerStats.likes = newVal;
},
favoriteCount(newVal) {
this.innerStats.favorites = newVal;
},
isLiked(newVal) {
this.innerStats.isLiked = newVal;
},
isFavorite(newVal) {
this.innerStats.isFavorite = newVal;
},
},
methods: {
//
handleViewReplies(comment) {
//
uni.navigateTo({
url: `/pages/comment/replies?commentId=${comment.id}&postId=${this.postId}`,
});
//
this.$emit("view-replies", comment);
},
//
handleLikeComment(index) {
//
const comment = this.localComments[index];
comment.isLiked = !comment.isLiked;
if (comment.isLiked) {
comment.likes++;
} else if (comment.likes > 0) {
comment.likes--;
}
// API
this.updateCommentLikeStatus(comment.id, comment.isLiked);
//
this.$emit("like-comment", { index, comment });
},
//
handleShowCommentInput() {
//
this.showCommentPopup();
//
this.$emit("show-comment-input");
},
//
handleSharePost() {
//
uni.showActionSheet({
itemList: ["分享到朋友圈", "分享给朋友", "复制链接", "收藏"],
success: (res) => {
const { tapIndex } = res;
let message = "";
switch (tapIndex) {
case 0:
message = "分享到朋友圈";
break;
case 1:
message = "分享给朋友";
break;
case 2:
uni.setClipboardData({
data: `https://yourapp.com/post/${this.postId}`,
success: () => {
message = "链接已复制";
},
});
break;
case 3:
this.handleFavoritePost();
return;
}
if (message) {
uni.showToast({
title: message,
icon: "none",
});
}
},
});
//
this.$emit("share");
},
//
handleCommentPost() {
//
this.handleShowCommentInput();
},
//
handleLikePost() {
//
this.innerStats.isLiked = !this.innerStats.isLiked;
if (this.innerStats.isLiked) {
this.innerStats.likes++;
} else if (this.innerStats.likes > 0) {
this.innerStats.likes--;
}
// API
this.updatePostLikeStatus(this.postId, this.innerStats.isLiked);
//
this.$emit("like", {
isLiked: this.innerStats.isLiked,
likeCount: this.innerStats.likes,
});
},
//
handleFavoritePost() {
//
this.innerStats.isFavorite = !this.innerStats.isFavorite;
if (this.innerStats.isFavorite) {
this.innerStats.favorites++;
} else if (this.innerStats.favorites > 0) {
this.innerStats.favorites--;
}
// API
this.updatePostFavoriteStatus(this.postId, this.innerStats.isFavorite);
//
this.$emit("favorite", {
isFavorite: this.innerStats.isFavorite,
favoriteCount: this.innerStats.favorites,
});
},
// ========== API ==========
//
updateCommentLikeStatus(commentId, isLiked) {
// API
console.log(`更新评论(${commentId})点赞状态: ${isLiked}`);
// API
/*
uni.request({
url: '/api/comment/like',
method: 'POST',
data: {
commentId,
action: isLiked ? 'like' : 'unlike'
},
success: (res) => {
console.log('评论点赞状态更新成功', res);
},
fail: (err) => {
console.error('评论点赞状态更新失败', err);
// UI
this.rollbackCommentLike(commentId);
}
});
*/
},
//
updatePostLikeStatus(postId, isLiked) {
// API
console.log(`更新帖子(${postId})点赞状态: ${isLiked}`);
// API
/*
uni.request({
url: '/api/post/like',
method: 'POST',
data: {
postId,
action: isLiked ? 'like' : 'unlike'
},
success: (res) => {
console.log('帖子点赞状态更新成功', res);
},
fail: (err) => {
console.error('帖子点赞状态更新失败', err);
// UI
this.rollbackPostLike();
}
});
*/
},
//
updatePostFavoriteStatus(postId, isFavorite) {
// API
console.log(`更新帖子(${postId})收藏状态: ${isFavorite}`);
// API
/*
uni.request({
url: '/api/post/favorite',
method: 'POST',
data: {
postId,
action: isFavorite ? 'favorite' : 'unfavorite'
},
success: (res) => {
console.log('帖子收藏状态更新成功', res);
},
fail: (err) => {
console.error('帖子收藏状态更新失败', err);
// UI
this.rollbackPostFavorite();
}
});
*/
},
//
showCommentPopup() {
//
uni.showModal({
// title: "",
editable: true,
placeholderText: "说点什么吧...",
success: (res) => {
if (res.confirm && res.content) {
//
this.submitComment(res.content);
}
},
});
},
//
submitComment(content) {
if (!content.trim()) return;
// API
console.log(`提交评论到帖子(${this.postId}): ${content}`);
//
const newComment = {
id: Date.now().toString(),
author: {
id: "current-user-id",
name: "我",
avatar: "/static/common/img/homepage/avatar.png",
school: "我的学校",
},
time: "刚刚",
content: content,
likes: 0,
isLiked: false,
replyCount: 0,
};
//
this.localComments.unshift(newComment);
//
this.innerStats.comments++;
//
this.$emit("comment-added", {
comment: newComment,
commentCount: this.innerStats.comments,
});
//
uni.showToast({
title: "评论发表成功",
icon: "success",
});
},
// 退APIUI
rollbackCommentLike(commentId) {
const index = this.localComments.findIndex((c) => c.id === commentId);
if (index > -1) {
const comment = this.localComments[index];
comment.isLiked = !comment.isLiked;
if (comment.isLiked) {
comment.likes++;
} else if (comment.likes > 0) {
comment.likes--;
}
}
},
rollbackPostLike() {
this.innerStats.isLiked = !this.innerStats.isLiked;
if (this.innerStats.isLiked) {
this.innerStats.likes++;
} else if (this.innerStats.likes > 0) {
this.innerStats.likes--;
}
},
rollbackPostFavorite() {
this.innerStats.isFavorite = !this.innerStats.isFavorite;
if (this.innerStats.isFavorite) {
this.innerStats.favorites++;
} else if (this.innerStats.favorites > 0) {
this.innerStats.favorites--;
}
},
//
handleAction(action) {
switch (action) {
case "forward":
this.handleForward();
break;
case "comment":
this.handleComment();
break;
case "like":
this.handleLike();
break;
case "favorite":
this.handleFavorite();
break;
}
},
},
};
</script>
<style lang="scss" scoped>
.comment-section {
margin-top: 30rpx;
//
.comment-count {
font-size: 32rpx;
color: rgba(0,0,0,0.9);
font-weight: bold;
padding: 30rpx 0 20rpx;
// border-bottom: 1px solid #f5f5f5;
}
//
.comment-list {
padding: 0;
.comment-item {
display: flex;
padding: 30rpx 0;
// border-bottom: 1px solid #f5f5f5;
.comment-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
background-color: #f8f8f8;
}
.comment-content {
flex: 1;
.comment-user {
margin-bottom: 12rpx;
.comment-username {
font-size: 32rpx;
color: #333;
font-weight: 500;
margin-right: 16rpx;
}
.comment-school {
font-size: 26rpx;
color: #999;
margin-right: 16rpx;
}
.comment-time {
font-size: 26rpx;
color: #999;
}
}
.comment-text {
font-size: 30rpx;
color: #333;
line-height: 1.6;
margin-bottom: 16rpx;
}
.comment-actions {
display: flex;
justify-content: space-between;
font-size: 26rpx;
color: #999;
.reply-count {
background-color: #f5f5f5;
// flex: 1;
padding: 10rpx 16rpx;
color: #666;
border-radius: 10rpx;
}
.like-btn {
display: flex;
align-items: center;
text {
margin-left: 6rpx;
}
}
}
}
}
}
// -
.footer-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #fff;
padding: 16rpx 30rpx;
display: flex;
flex-direction: column;
box-shadow: 0 -1rpx 6rpx rgba(0, 0, 0, 0.05);
z-index: 100;
//
.input-container {
display: flex;
align-items: center;
padding: 20rpx 0 10rpx;
.comment-input {
flex: 1;
height: 72rpx;
background-color: #f5f5f5;
border-radius: 36rpx;
padding: 0 30rpx;
display: flex;
align-items: center;
font-size: 28rpx;
color: #999;
}
.send-btn {
margin-left: 20rpx;
width: 72rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
}
}
//
.interaction-bar {
display: flex;
justify-content: space-between;
margin-top: 16rpx;
padding: 10rpx 20rpx;
.action-item {
display: flex;
align-items: center;
text {
font-size: 24rpx;
color: #999;
margin-left: 8rpx;
}
}
}
}
//
padding-bottom: 220rpx;
}
</style>

View File

@ -0,0 +1,337 @@
<template>
<view class="content-detail-page">
<u-navbar title="" :border-bottom="false" :is-back="true"></u-navbar>
<!-- 帖子内容区域 -->
<view class="post-container">
<!-- 用户信息 -->
<view class="user-info">
<image
class="avatar"
:src="post.author.avatar"
mode="aspectFill"
></image>
<view class="user-meta">
<view class="username">{{ post.author.name }}</view>
<view class="post-meta"
>{{ post.time }} {{ post.author.school }}</view
>
</view>
<view class="follow-btn" @click="followUser">
<text>+</text>
<text>关注</text>
</view>
</view>
<!-- 帖子文本内容 -->
<view class="post-content">
<text>{{ post.content }}</text>
</view>
<!-- 帖子话题标签 -->
<view class="post-tags" v-if="post.tags && post.tags.length">
<view
class="tag-item"
v-for="(tag, index) in post.tags"
:key="index"
@click="goToTopic(tag)"
>
#{{ tag }}
</view>
</view>
<!-- 帖子图片内容 -->
<view class="post-images" v-if="post.images && post.images.length">
<view
class="image-grid"
:class="getImageLayoutClass(post.images.length)"
>
<image
v-for="(img, index) in post.images"
:key="index"
:src="img"
mode="aspectFill"
@click="previewImage(index)"
class="post-image"
></image>
</view>
</view>
<!-- 使用评论区组件 - 简化后的接口 -->
<comment-section
:comments="post.comments"
:share-count="post.shares"
:comment-count="post.commentCount"
:like-count="post.likes"
:favorite-count="post.favorites"
:is-liked="post.isLiked"
:is-favorite="post.isFavorite"
:post-id="post.id"
@like="updateLikeStatus"
@favorite="updateFavoriteStatus"
@comment-added="handleCommentAdded"
></comment-section>
</view>
</view>
</template>
<script>
import CommentSection from './commentSection.vue';
export default {
name: "ContentDetail",
components: {
CommentSection
},
data() {
return {
post: {
id: "12345",
author: {
id: "1001",
name: "Kohaku",
avatar: "/static/common/img/homepage/avatar.png",
school: "北京大学",
isFollowed: false,
},
time: "2小时前",
content:
"美国对现行的全球化十分不满,从这次关税大战就可以看得出来,但是美国人就是不愿意代价自己,因为没有全球化的商品贸易体系,也就不会有美元如今的国际地位。\n美国本身加关税看近来是想保护本国产业但实际上牺牲了一个错位的他们想保持美元的国际地位又想把制造业搬回国内。\n这两件事其实完全矛盾的美元之所以值钱正是因为全球贸易都在用它结算如果美国自己把贸易门门关小美元的地位自然也会影响。\n现实情况是美国超市里很多东西都依赖进口华尔街的金融生意也需全球资金流动。\n现在美欢加关税短期内可能看不出问题但几个月后的压力会传到普通消费者。",
images: [
"/static/common/img/homepage/image-photo1.png",
"/static/common/img/homepage/image-photo2.png",
"/static/common/img/homepage/image-photo3.png",
],
tags: ["看到最文艺的话"],
commentCount: 102,
shares: 102,
likes: 212,
favorites: 62,
isLiked: false,
isFavorite: false,
comments: [
{
id: "10001",
author: {
id: "2001",
name: "Totoro",
avatar: "/static/common/img/homepage/avatar.png",
school: "北京大学",
},
time: "6小时前",
content:
"美国在全球贸易秩序上是想保护本国产业,但实际上牺牲了一个错位的,他们想维持美元的国际地位,又想把制造业搬回国内。",
likes: 12,
isLiked: false,
replyCount: 12,
},
{
id: "10002",
author: {
id: "2002",
name: "calista33",
avatar: "/static/common/img/homepage/avatar2.png",
school: "北京大学",
},
time: "6小时前",
content:
"现在美欢加关税,短期内可能看不出问题,但几个月后的压力会传到普通消费者。",
likes: 12,
isLiked: false,
replyCount: 12,
},
],
},
};
},
methods: {
//
getImageLayoutClass(count) {
if (count === 1) return "single-image";
if (count === 2) return "double-image";
if (count === 3) return "triple-image";
if (count === 4) return "four-image";
return "multi-image";
},
//
previewImage(index) {
uni.previewImage({
current: index,
urls: this.post.images,
});
},
//
followUser() {
this.post.author.isFollowed = !this.post.author.isFollowed;
uni.showToast({
title: this.post.author.isFollowed ? "已关注" : "已取消关注",
icon: "none",
});
},
//
goToTopic(tag) {
uni.navigateTo({
url: `/pages/home/home/components/topic/topicDetail?tag=${encodeURIComponent(
tag
)}`,
});
},
//
updateLikeStatus(data) {
this.post.isLiked = data.isLiked;
this.post.likes = data.likeCount;
},
updateFavoriteStatus(data) {
this.post.isFavorite = data.isFavorite;
this.post.favorites = data.favoriteCount;
},
handleCommentAdded(data) {
//
this.post.commentCount = data.commentCount;
}
},
onLoad(options) {
// ID
const postId = options.id;
if (postId) {
// API
console.log("获取帖子ID:", postId);
}
},
};
</script>
<style lang="scss" scoped>
.content-detail-page {
min-height: 100vh;
background-color: #f8f8f8;
padding-bottom: 120rpx; //
//
.post-container {
background-color: #fff;
padding: 30rpx;
//
.user-info {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
margin-right: 20rpx;
}
.user-meta {
flex: 1;
.username {
font-size: 32rpx;
font-weight: 500;
color: #333;
margin-bottom: 4rpx;
}
.post-meta {
font-size: 24rpx;
color: #999;
}
}
.follow-btn {
background-color: #00aaff;
color: #fff;
font-size: 28rpx;
padding: 8rpx 20rpx;
border-radius: 30rpx;
display: flex;
align-items: center;
text:first-child {
margin-right: 4rpx;
font-size: 32rpx;
line-height: 1;
}
}
}
//
.post-content {
font-size: 30rpx;
color: #333;
line-height: 1.6;
margin-bottom: 30rpx;
white-space: pre-line; //
}
//
.post-tags {
display: flex;
flex-wrap: wrap;
margin-bottom: 30rpx;
.tag-item {
color: #00aaff;
font-size: 28rpx;
margin-right: 20rpx;
margin-bottom: 10rpx;
}
}
//
.post-images {
margin-bottom: a30rpx;
.image-grid {
display: flex;
flex-wrap: wrap;
.post-image {
border-radius: 12rpx;
background-color: #f5f5f5;
}
&.single-image {
.post-image {
width: 100%;
max-height: 500rpx;
}
}
&.double-image {
.post-image {
width: 49%;
height: 300rpx;
margin-right: 2%;
&:nth-child(2n) {
margin-right: 0;
}
}
}
&.triple-image {
.post-image {
width: 32%;
height: 240rpx;
margin-right: 2%;
&:nth-child(3n) {
margin-right: 0;
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,3 @@
<template>
<div>回复</div>
</template>

View File

@ -0,0 +1,206 @@
<template>
<!-- 首页-本校组件 -->
<view class="our-school-page">
<!-- 校园活动 -->
<view class="school-activity-section">
<view class="section-header">
<text>校园活动</text>
<text class="more">查看更多</text>
</view>
<!-- 校园活动列表 -->
<scroll-view scroll-x class="school-activity-list">
<view
class="school-activity-item"
v-for="(user, index) in schoolActivityList"
:key="index"
>
<view class="avatar-wrapper">
<image :src="user.avatar" class="avatar"></image>
</view>
<view class="info-wrapper">
<text class="name">{{ user.name }}</text>
<text class="desc">{{ user.desc }}</text>
</view>
</view>
</scroll-view>
</view>
<!-- 校园动态 -->
<view class="school-dynamic-section">
<view class="section-header"> 校园动态 </view>
</view>
<!-- 使用内容卡片组件 -->
<content-card
v-for="(card, index) in contentCards"
:key="index"
:cardData="card"
></content-card>
</view>
</template>
<script>
import ContentCard from "@/components/ContentCard.vue";
export default {
name: "OurSchool",
components: {
ContentCard,
},
data() {
return {
schoolActivityList: [
{
name: "2025届校园运动会12",
avatar: "/static/common/img/homepage/image-photo2.png",
desc: "浙江大学校运动场4月28日-30日将举行盛大的运动会请同学们积极报名参加积极报名积极报名",
},
{
name: "2025届校园运动会",
avatar: "/static/common/img/homepage/image-photo1.png",
desc: "浙江大学校运动场4月28日-30日将举行盛大的运动会请同学们积极报名参加",
},
],
//
contentCards: [
//
{
user: {
avatar: "/static/common/img/homepage/avatar3.png",
name: "calista33",
meta: "2小时前 北京大学",
},
content: "今日份走停停的小确幸。",
type: "image",
images: [
"/static/common/img/homepage/image-photo1.png",
"/static/common/img/homepage/image-photo2.png",
"/static/common/img/homepage/image-photo3.png",
],
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
//
{
user: {
avatar: "/static/common/img/homepage/avatar.png",
name: "Kohaku",
meta: "2小时前 北京大学",
},
content: "看看我拍的这个视频•",
type: "video",
cover: "/static/images/video-cover.png",
videoUrl: "https://example.com/video.mp4",
duration: 145, // 225
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
],
};
},
};
</script>
<style lang="scss" scoped>
.our-school-page {
padding: 8rpx 8rpx 0;
.school-activity-section {
margin-bottom: 24rpx;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin: 30rpx 0;
text {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.more {
font-size: 24rpx;
color: #999;
font-weight: normal;
}
}
.school-activity-list {
white-space: nowrap;
.school-activity-item {
display: inline-flex;
align-items: center;
width: 512rpx;
height: 232rpx;
margin-right: 20rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
.avatar-wrapper {
width: 184rpx;
height: 184rpx;
margin-right: 24rpx;
.avatar {
width: 100%;
height: 100%;
}
}
.info-wrapper {
width: 256rpx;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
.name {
font-size: 28rpx;
color: #1f2232;
font-weight: bold;
margin-bottom: 16rpx;
overflow: hidden; /* 隐藏溢出内容 */
text-overflow: ellipsis; /* 溢出显示省略号 */
white-space: nowrap; /* 文本不换行 */
max-width: 100%;
}
.desc {
font-size: 24rpx;
line-height: 32rpx;
color: rgba(0, 0, 0, 0.6);
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
white-space: wrap;
-webkit-line-clamp: 4; /* 显示2行 */
-webkit-box-orient: vertical;
word-break: break-all; /* 允许在任意字符间断行 */
}
}
}
}
}
.school-dynamic-section {
.section-header {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin: 30rpx 0;
}
}
}
</style>

View File

@ -0,0 +1,244 @@
<template>
<view class="all-services-page">
<u-navbar title="全部服务" :border-bottom="false"></u-navbar>
<!-- 校园服务区域 -->
<view class="service-section">
<view class="section-title">校园服务</view>
<view class="service-grid">
<view
class="service-item"
v-for="(item, index) in campusServices"
:key="index"
@click="navigateToService(item)"
>
<view class="icon-box">
<image :src="item.url?item.icon:item.icon2" mode="aspectFit" class="icon-image"></image>
<!-- <view v-if="!item.url" class="mark-box"></view> -->
</view>
<text class="service-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 校友服务区域 -->
<view class="service-section">
<view class="section-title">校友服务</view>
<view class="service-grid">
<view
class="service-item"
v-for="(item, index) in alumniServices"
:key="index"
@click="navigateToService(item)"
>
<view class="icon-box">
<image :src="item.url?item.icon:item.icon2" mode="aspectFit" class="icon-image"></image>
<!-- <view v-if="!item.url" class="mark-box"></view> -->
</view>
<text class="service-name">{{ item.name }}</text>
</view>
</view>
</view>
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
functionListing2,
functionListing3,
getSchoolConfig,
} from "../../../data";
export default {
name: "AllServices",
data() {
return {
//
campusServices: JSON.parse(JSON.stringify(functionListing2)),
//
alumniServices: functionListing3,
};
},
watch: {
vuex_schoolName: {
handler(newVal) {
this.updateSchoolConfigs(newVal);
},
immediate: true,
},
},
methods: {
//
updateSchoolConfigs(schoolName) {
//
const schoolConfig = getSchoolConfig(schoolName);
//
if (Object.keys(schoolConfig).length > 0) {
//
Object.values(schoolConfig).forEach((config) => {
// index
if (
typeof config.index === "number" &&
config.index >= 0 &&
config.index < this.campusServices.length
) {
this.$set(this.campusServices, config.index, config);
}
});
}
},
//
navigateToService(service) {
if (service.url == "") {
console.log(this);
// return this.$tips("","warning");
return this.$refs.uToast.show({
title: "暂未开放",
type: "warning",
});
}
if (service.type == "http") {
// 使web-view
const itemData = encodeURIComponent(JSON.stringify(service));
this.$u.route({
url: `/pages/webview/index?data=${itemData}`,
});
} else {
//
if ([0,2].includes(this.vuex_user.userType)) {
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
}
//
if ([1].includes(this.vuex_user.userType)) {
//
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
}
//
this.$u.route({
url: service.url,
});
}
},
},
};
</script>
<style lang="scss" scoped>
.all-services-page {
min-height: 100vh;
background-color: #f8f8f8;
padding: 30rpx;
//
.service-section {
margin-bottom: 40rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
//
.service-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
//
.service-item {
width: 20%;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 40rpx;
//
.icon-box {
width: 92rpx;
height: 92rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
position: relative;
//
.icon-image {
width: 92rpx;
height: 92rpx;
}
.mark-box {
width: 92rpx;
height: 92rpx;
background: rgba(0, 0, 0, 0.2);
border-radius: 36rpx;
position: absolute;
top: 0;
left: 0;
}
}
//
.service-name {
font-size: 24rpx;
color: rgba(0, 0, 0, 0.9);
text-align: center;
}
}
}
}
}
</style>

View File

@ -0,0 +1,346 @@
<template>
<view class="all-services-page">
<u-navbar title="全部服务" :border-bottom="false"></u-navbar>
<!-- 校园服务区域 -->
<view class="service-section">
<view class="section-title">{{
isStudent ? "校园服务" : "校友服务"
}}</view>
<view class="service-grid">
<view
class="service-item"
v-for="(item, index) in availableServices"
:key="index"
@click="navigateToService(item)"
>
<view class="icon-box">
<image
:src="item.url ? item.icon : item.icon2"
mode="aspectFit"
class="icon-image"
></image>
</view>
<text class="service-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 校友服务区域 -->
<view class="service-section">
<view class="section-title">敬请期待</view>
<view class="service-grid">
<view
class="service-item"
v-for="(item, index) in waitingServices"
:key="index"
@click="navigateToService(item)"
>
<view class="icon-box">
<image
:src="item.url ? item.icon : item.icon2"
mode="aspectFit"
class="icon-image"
></image>
</view>
<text class="service-name">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 模态框 -->
<u-modal
ref="uModal"
v-model="modalShow"
:content="modalContent"
:show-cancel-button="true"
@cancel="modalCancel"
@confirm="modalConfirm"
:async-close="true"
></u-modal>
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
functionListing2,
functionListing3,
getSchoolConfig,
NANCHANG_CONFIG,
} from "../../../data";
export default {
name: "AllServices",
data() {
return {
modalShow: false,
modalContent: "即将跳转第三方页面,是否继续跳转",
currentUrl: null,
//
availableServices: JSON.parse(JSON.stringify(functionListing2)),
//
waitingServices: [],
};
},
computed: {
// 0 2
isStudent() {
return this.vuex_user.userType == 0 ? true : false;
},
},
watch: {
vuex_schoolName: {
handler(newVal) {
if (newVal) {
this.updateSchoolConfigs(newVal);
} else {
//
this.getEducation();
}
},
immediate: true,
},
},
methods: {
//
updateSchoolConfigs(schoolName) {
//
if (schoolName.includes("南昌理工")) {
//
const configType = this.isStudent ? "在校生" : "毕业生";
// URL
this.availableServices = NANCHANG_CONFIG[configType].filter(
(service) => service.url
);
this.waitingServices = NANCHANG_CONFIG[configType].filter(
(service) => !service.url
);
return;
}
//
const schoolConfig = getSchoolConfig(schoolName);
//
const servicesCopy = [...this.availableServices];
//
if (Object.keys(schoolConfig).length > 0) {
Object.values(schoolConfig).forEach((config) => {
if (
typeof config.index === "number" &&
config.index >= 0 &&
config.index < servicesCopy.length
) {
this.$set(servicesCopy, config.index, config);
}
});
}
// URL
const filteredServices = servicesCopy.filter((service) => service.url);
const unfilteredServices = servicesCopy.filter((service) => !service.url);
//
this.availableServices = filteredServices;
this.waitingServices = unfilteredServices;
//
if (!this.isStudent) {
this.waitingServices = [...unfilteredServices, ...functionListing3];
}
},
//
navigateToService(service) {
if (service.url == "") {
console.log(this);
// return this.$tips("","warning");
return this.$refs.uToast.show({
title: "暂未开放",
type: "warning",
});
}
if (service.type == "http") {
this.currentUrl = service.url;
this.modalShow = true;
return;
// 使web-view
const itemData = encodeURIComponent(JSON.stringify(service));
this.$u.route({
url: `/pages/webview/index?data=${itemData}`,
});
} else {
//
if ([0, 2].includes(this.vuex_user.userType)) {
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
}
//
if ([1].includes(this.vuex_user.userType)) {
//
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
}
//
this.$u.route({
url: service.url,
});
}
},
modalCancel() {
this.modalShow = false;
},
modalConfirm() {
this.modalShow = false;
//
uni.showLoading({
title: "正在跳转...",
mask: true, //
});
//
window.location.href = this.currentUrl;
},
getEducation() {
const data = {
userId: this.vuex_user.id,
};
this.$u.apiList.MyPage(data).then((res) => {
//
const schoolName =
res.edcationList.length > 0
? res.edcationList[0].schoolName || res.edcationList[0].school
: "";
this.$u.vuex("vuex_schoolName", schoolName);
});
},
},
};
</script>
<style lang="scss" scoped>
.all-services-page {
min-height: 100vh;
background-color: #f8f8f8;
padding: 30rpx;
//
.service-section {
margin-bottom: 40rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
//
.service-grid {
display: flex;
flex-wrap: wrap;
// justify-content: space-between;
justify-content: flex-start;
//
.service-item {
width: 20%;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 40rpx;
//
.icon-box {
width: 92rpx;
height: 92rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
position: relative;
//
.icon-image {
width: 92rpx;
height: 92rpx;
}
.mark-box {
width: 92rpx;
height: 92rpx;
background: rgba(0, 0, 0, 0.2);
border-radius: 36rpx;
position: absolute;
top: 0;
left: 0;
}
}
//
.service-name {
font-size: 24rpx;
color: rgba(0, 0, 0, 0.9);
text-align: center;
}
}
}
}
}
</style>

View File

@ -0,0 +1,885 @@
<template>
<!-- 首页-推荐组件 -->
<view class="recommend-page">
<u-top-tips ref="uTips" style="top: 0"></u-top-tips>
<!-- Banner图 -->
<view class="banner">
<image
src="/static/common/img/homepage/banner.jpg"
mode="widthFix"
></image>
</view>
<!-- 功能图标区 -->
<view class="function-icons">
<view class="function-list-wrapper" :class="{ teacher_class: isTeacher }">
<view
class="function-item"
v-for="(item, index) in isTeacher
? functionListTeacher
: functionList"
:key="index"
@click="handleFunctionClick(item)"
>
<view class="icon-box">
<image
:src="item.url ? item.icon : item.icon2"
mode="widthFix"
style="width: 92rpx; height: 92rpx"
></image>
</view>
<text>{{ item.name }}</text>
</view>
</view>
<!-- 指示点 -->
<!-- <view class="indicator">
<view class="dot active"></view>
<view class="dot"></view>
<view class="dot"></view>
</view> -->
</view>
<!-- 为你推荐 -->
<view class="recommend-section">
<view class="section-header">
<text>为你推荐</text>
<text class="more" @click="toAlumniPage">查看更多</text>
</view>
<!-- 推荐人列表 -->
<scroll-view
scroll-x
class="recommend-users"
v-if="recommendUsers.length !== 0"
>
<view
class="user-item"
v-for="(user, index) in recommendUsers"
:key="index"
@click="toUserDetail(user.userId)"
>
<!-- <image
:src="$u.http.config.imgUrl + user.imageUrl"
class="avatar"
></image> -->
<u-avatar
:src="$u.http.config.imgUrl + user.imageUrl"
class="avatar"
></u-avatar>
<text class="name">{{ user.name }}</text>
<!-- <text class="desc">{{ user.workFieldName }}</text> -->
<!-- <button
class="follow-btn"
:class="{ followed: user.isFollowed }"
@click.stop="handleFollow(user.userId)"
>
{{ user.isFollowed ? "已关注" : "关注" }}
</button> -->
<view
class="follow-btn"
:class="{ followed: user.isFollowed }"
@click.stop="handleFollow(user.userId)"
>
<image
v-if="!user.isFollowed"
src="/static/common/img/homepage/icon-follow.png"
mode="scaleToFill"
style="width: 28rpx; height: 28rpx; margin-right: 6rpx"
/>
<span>{{ user.isFollowed ? "已关注" : "关注" }}</span>
</view>
<!-- <image
class="close-btn"
src="/static/common/img/homepage/icon-close-circle.png"
mode="widthFix"
style="width: 28rpx; height: 28rpx"
></image> -->
</view>
</scroll-view>
<no-data v-else></no-data>
</view>
<!-- 校园资讯 横板展示三条 -->
<view class="campus-info-section">
<view class="section-header">
<text>校园资讯</text>
<text class="more" @click="toAlumnusPage">查看更多</text>
</view>
<!-- 校园资讯 -->
<scroll-view
scroll-x
class="school-activity-list"
v-if="schoolActivityList.length !== 0"
>
<view
class="school-activity-item"
v-for="(item, index) in schoolActivityList"
:key="index"
@click="toSchoolActivityDetail(item)"
>
<view class="avatar-wrapper">
<!-- $u.http.config.imgUrl + item.imageUrl || -->
<!-- 图片无法正常展示先用默认图片 -->
<image
:src="'/static/common/img/homepage/activity-default.png'"
class="avatar"
></image>
</view>
<view class="info-wrapper">
<text class="name">{{ item.title }}</text>
<text class="desc">{{ item.content }}</text>
</view>
</view>
</scroll-view>
<!-- <no-data v-else></no-data> -->
<!-- -->
<information
@onStar="onStar"
@clickImg="clickImg"
:list="helpList"
type="1"
:bottom="bottomState"
:borderNoPadding="true"
:noShowEmpty="true"
>
</information>
</view>
<!-- 模态框 -->
<u-modal
ref="uModal"
v-model="modalShow"
:content="modalContent"
:show-cancel-button="true"
@cancel="modalCancel"
@confirm="modalConfirm"
:async-close="true"
></u-modal>
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
functionListing,
getAIAssistantConfig,
getOldStudentConfig,
TEACHER_CONFIG,
NANCHANG_CONFIG,
getSchoolConfig,
functionListing2,
} from "../../../data";
//
import ContentCard from "@/components/ContentCard.vue";
import information from "@/components/Information.vue";
import NoData from "@/components/NoData.vue";
import { computed } from "vue";
export default {
name: "Recommend",
components: {
ContentCard,
NoData,
information,
},
data() {
return {
modalShow: false,
modalContent: "即将跳转第三方页面,是否继续跳转",
currentUrl: null,
functionList: JSON.parse(JSON.stringify(functionListing)), //
functionList2: JSON.parse(JSON.stringify(functionListing2)), //
functionListTeacher: TEACHER_CONFIG, //
recommendUsers: [
/* {
name: "李雪",
avatar: "/static/common/img/homepage/avatar.png",
desc: "对二次元我似乎都关注了Ta",
isFollowed: false,
}, */
],
schoolActivityList: [
/* {
title: "2025届校园运动会12",
imageUrl: "/static/common/img/homepage/activity-default.png",
content:
"浙江大学校运动场4月28日-30日将举行盛大的运动会请同学们积极报名参加积极报名积极报名",
}, */
],
currentRow: {},
flag: null,
route: null,
type: "0",
id: null,
nolink: false,
bottomState: false,
helpList: [],
total2: 0,
};
},
computed: {
//
isTeacher() {
return this.vuex_user.userType == 1 ? true : false;
},
// 0 2
isStudent() {
return this.vuex_user.userType == 0 ? true : false;
},
},
watch: {
vuex_schoolName: {
handler(newVal) {
// schoolNameAI
if (newVal) {
this.updateAIConfig(newVal);
}
},
immediate: true,
},
},
methods: {
// AI
updateAIConfig(schoolName) {
//
if (this.vuex_user.userType !== 1) {
const lastItem = this.functionList[4]; // 5()
//
if (schoolName.includes("南昌理工")) {
//
const configType = this.isStudent ? "在校生" : "毕业生";
// URL
const filteredServices = NANCHANG_CONFIG[configType].filter(
(service) => service.url
);
// 45
this.functionList = [...filteredServices.slice(0, 4), lastItem];
return;
}
//
const schoolConfig = getSchoolConfig(schoolName);
//
const functionList2Copy = [...this.functionList2];
//
if (Object.keys(schoolConfig).length > 0) {
//
Object.values(schoolConfig).forEach((config) => {
if (
typeof config.index === "number" &&
config.index >= 0 &&
config.index < functionList2Copy.length
) {
this.$set(functionList2Copy, config.index, config);
}
});
}
// URL
const filteredServices = functionList2Copy.filter(
(service) => service.url
);
// 45
this.functionList = [...filteredServices.slice(0, 4), lastItem];
return;
}
//
if (schoolName.includes("南昌理工")) {
this.functionListTeacher = NANCHANG_CONFIG["教师"];
return;
}
//
const schoolConfig = getSchoolConfig(schoolName);
//
const functionList3Copy = [...this.functionList2];
if (Object.keys(schoolConfig).length > 0) {
//
Object.values(schoolConfig).forEach((config) => {
if (
typeof config.index === "number" &&
config.index >= 0 &&
config.index < functionList3Copy.length
) {
this.$set(functionList3Copy, config.index, config);
}
});
}
this.functionListTeacher = functionList3Copy.slice(0, 4);
},
//
handleFunctionClick(item) {
console.log("点击功能图标", item);
if (item.name === "全部服务") {
this.$u.route({
url: "/pages/home/home/components/recommend/allServices",
});
return;
}
if (item.url == "") {
// this.$tips("", "warning");
this.$refs.uToast.show({
title: "暂未开放",
type: "warning",
});
return;
}
if (item.type == "http") {
// 使web-view
// this.$u.route({
// url: `/pages/webview/index?url=${encodeURIComponent(item)}`,
// });
this.currentUrl = item.url;
this.modalShow = true;
return;
const itemData = encodeURIComponent(JSON.stringify(item));
this.$u.route({
url: `/pages/webview/index?data=${itemData}`,
});
} else {
//
if ([0, 2].includes(this.vuex_user.userType)) {
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行教育经历认证",
type: "warning",
});
}
}
//
if ([1].includes(this.vuex_user.userType)) {
//
if (!this.vuex_education.length) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
const findRow = this.vuex_education.find(
(x) => x.isSelected === true
);
if (!findRow) {
return this.$refs.uToast.show({
title: "请先绑定学校",
type: "warning",
});
}
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "请先进行任职学校认证",
type: "warning",
});
}
}
//
this.$u.route({
url: item.url,
});
}
},
modalCancel() {
this.modalShow = false;
},
modalConfirm() {
this.modalShow = false;
//
uni.showLoading({
title: "正在跳转...",
mask: true, //
});
//
window.location.href = this.currentUrl;
},
//
refreshAll() {
this.getAlumnSearch();
this.getSchoolActivity();
this.gethelpList();
},
//
getAlumnSearch() {
this.$u.api.getAlumnSearch().then((res) => {
this.recommendUsers = res;
});
},
//
getSchoolActivity() {
this.$u.api
.GetSchoolList({
PageIndex: 1,
PageSize: 3,
})
.then((res) => {
this.schoolActivityList = res.items;
});
},
//
toUserDetail(id) {
this.$u.route({
url: "/pages/AlumniCircle/userDetail/userDetail?id=" + id,
});
},
//
handleFollow(id) {
const data = {
userId: this.vuex_user.id,
carewId: id,
};
this.$u.apiList.InsertOrDelFollow(data).then((res) => {
if (res.succeed) {
this.$refs.uToast.show({
title: "已关注!",
type: "success",
});
}
this.getAlumnSearch();
});
},
//
toAlumniPage() {
this.$u.route({
url: "/pages/AlumniCircle/Alumni/Alumni",
});
},
//
toAlumnusPage() {
uni.switchTab({
url: "/pages/AlumniCircle/alumnus/alumnus",
});
},
//
toSchoolActivityDetail(item) {
this.currentRow = item;
uni.$off("echoList");
uni.$on("echoList", (result) => {
// console.log('echoList----')
//
if (result.type === "star") {
console.log("%c%s", "color:red", "收藏回显");
console.log(result, "result");
this.currentRow.isCllect = result.data.isCllect;
console.log(result.isCllect, "result.isCllect");
if (result.data.isCllect === true) {
this.currentRow.collectCount++;
}
if (result.data.isCllect === false) {
this.currentRow.collectCount && this.currentRow.collectCount--;
}
}
//
if (result.type === "evaluate") {
console.log("%c%s", "color:red", "评价回显");
console.log(result, "result");
this.currentRow.commentCount = result.data.commentCount;
}
});
// return
if (this.nolink) {
return;
}
if (item.isDelete) {
return;
}
item.flag = this.flag;
item.route = this.route;
item.mytype = this.type;
item.myschoolId = this.id;
if (this.type == 3) {
item.mytype = item.type;
}
this.$u.route({
url: "/pages/AlumniCircle/ArticleDetails/ArticleDetails",
params: {
data: JSON.stringify(item),
},
});
},
//
gethelpList() {
const data = {
PageIndex: 1,
PageSize: 10,
IsForward: true, // true
Keyword: "全部",
};
this.helpList = [];
this.$u.api.GetHelpList(data).then((res) => {
this.total2 = res.total;
if (this.helpList.length >= this.total2) {
this.bottomState = true;
return;
}
if (this.total2 == res.items.length) {
this.bottomState = true;
}
this.helpList.push(...res.items);
});
},
//
async onStar(val) {
console.log("收藏--");
//
const req = {
userId: this.vuex_user.id,
};
const res = await this.$u.apiList.MyPage(req);
console.log(JSON.parse(JSON.stringify(res)), "res");
const edcationList = res.edcationList;
if (!edcationList.length) {
return this.$refs.uToast.show({
title: "认证后可进行收藏操作",
type: "none",
});
}
const findRow = edcationList.find((x) => x.isSelected === true);
if ([0, 2].includes(findRow.certifyStatus)) {
return this.$refs.uToast.show({
title: "认证后可进行收藏操作",
type: "none",
});
}
const data = {
id: val.id,
type: val.type,
};
this.$u.apiList
.LikeCollect(data)
.then((res) => {
if (val.isCllect) {
if (val.collectCount > 0) {
val.isCllect = false;
val.collectCount--;
this.$refs.uToast.show({
title: "取消收藏成功",
type: "success",
});
}
} else {
val.isCllect = true;
val.collectCount++;
this.$refs.uToast.show({
title: "收藏成功",
type: "success",
});
}
})
.catch((err) => {
this.$refs.uToast.show({
title: "收藏失败",
type: "error",
});
});
},
//
clickImg(item) {
this.isonShow = false;
item = this.$u.http.config.imgUrl + item;
var images = [];
images.push(item);
uni.previewImage({
// => ['']
current: 0,
urls: images,
});
},
},
};
</script>
<style lang="scss" scoped>
.recommend-page {
.banner {
width: 100%;
height: 300rpx; // 356rpx
border-radius: 16rpx;
overflow: hidden;
margin-bottom: 24rpx;
image {
width: 100%;
}
}
.function-icons {
// height: 248rpx;
background: #ffffff;
border-radius: 24rpx;
padding: 32rpx;
.function-list-wrapper {
display: flex;
justify-content: space-between;
// margin-bottom: 32rpx;
}
.teacher_class {
padding: 0 24rpx;
}
.function-item {
display: flex;
flex-direction: column;
align-items: center;
text {
font-size: 24rpx;
color: #333;
}
}
}
.indicator {
display: flex;
justify-content: center;
// margin: 20rpx 0;
.dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background-color: #ddd;
margin: 0 8rpx;
&.active {
background-color: #2979ff;
width: 20rpx;
border-radius: 6rpx;
}
}
}
.recommend-section {
margin-bottom: 24rpx;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin: 30rpx 0;
text {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.more {
font-size: 24rpx;
color: #999;
font-weight: normal;
}
}
.recommend-users {
white-space: nowrap;
.user-item {
display: inline-flex;
flex-direction: column;
align-items: center;
width: 280rpx;
// height: 356rpx;
height: 290rpx;
margin-right: 20rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
position: relative;
.close-btn {
position: absolute;
right: 16rpx;
top: 16rpx;
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
margin-bottom: 16rpx;
}
.name {
font-size: 28rpx;
color: #333;
display: block;
margin: 10rpx 0 20rpx;
}
.desc {
height: 70rpx;
margin: 10rpx 0 16rpx;
font-size: 24rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
white-space: wrap;
-webkit-line-clamp: 2;
/* 显示2行 */
-webkit-box-orient: vertical;
word-break: break-all;
/* 允许在任意字符间断行 */
}
.follow-btn {
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
width: 230rpx;
height: 56rpx;
background: linear-gradient(
to bottom right,
#3cb5fb 0%,
#06e1fa 100%
);
border-radius: 28rpx;
color: #fff;
}
.followed {
color: rgba(0, 0, 0, 0.6);
// border: none;
background: #f6f8f9;
}
}
}
}
.campus-info-section {
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin: 30rpx 0;
text {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.more {
font-size: 24rpx;
color: #999;
font-weight: normal;
}
}
.school-activity-list {
white-space: nowrap;
.school-activity-item {
display: inline-flex;
align-items: center;
width: 512rpx;
height: 232rpx;
margin-right: 20rpx;
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx;
.avatar-wrapper {
width: 184rpx;
height: 184rpx;
margin-right: 24rpx;
.avatar {
width: 100%;
height: 100%;
}
}
.info-wrapper {
width: 256rpx;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
.name {
font-size: 28rpx;
color: #1f2232;
font-weight: bold;
margin-bottom: 16rpx;
overflow: hidden;
/* 隐藏溢出内容 */
text-overflow: ellipsis;
/* 溢出显示省略号 */
white-space: nowrap;
/* 文本不换行 */
max-width: 100%;
}
.desc {
font-size: 24rpx;
line-height: 32rpx;
color: rgba(0, 0, 0, 0.6);
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
white-space: wrap;
-webkit-line-clamp: 4;
/* 显示2行 */
-webkit-box-orient: vertical;
word-break: break-all;
/* 允许在任意字符间断行 */
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,254 @@
<template>
<view class="more-friends-page">
<u-navbar title="更多推荐好友" :border-bottom="false"></u-navbar>
<!-- 搜索框 -->
<view class="search-container">
<view class="search-box">
<u-icon name="search" size="40rpx" color="#999"></u-icon>
<input type="text" placeholder="搜索校友" v-model="searchKeyword" />
</view>
</view>
<!-- 推荐好友列表 -->
<view class="friends-list">
<view
class="friend-item"
v-for="(friend, index) in filteredFriends"
:key="index"
>
<!-- 头像 -->
<image class="avatar" :src="friend.avatar" mode="aspectFill"></image>
<!-- 用户信息 -->
<view class="user-info">
<text class="username">{{ friend.name }}</text>
<text class="school">{{ friend.school }}</text>
</view>
<!-- 关注按钮 -->
<view
class="follow-btn"
:class="{ followed: friend.isFollowed }"
@click="toggleFollow(index)"
>
{{ friend.isFollowed ? "已关注" : "关注" }}
</view>
<!-- 移除按钮 -->
<view class="remove-btn" @click="removeUser(index)">
<u-icon name="close" size="32rpx" color="#666"></u-icon>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "MoreFriends",
data() {
return {
searchKeyword: "",
recommendFriends: [
{
name: "小年轻",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar.png",
isFollowed: true,
},
{
name: "小年轻",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar2.png",
isFollowed: true,
},
{
name: "Alice_琛璃",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar3.png",
isFollowed: true,
},
{
name: "Alice_琛璃",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar.png",
isFollowed: true,
},
{
name: "Alice_琛璃",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar3.png",
isFollowed: false,
},
{
name: "别墨暝",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar2.png",
isFollowed: false,
},
{
name: "小六",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar.png",
isFollowed: false,
},
{
name: "小年轻",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar3.png",
isFollowed: false,
},
{
name: "别墨暝",
school: "浙江大学",
avatar: "/static/common/img/homepage/avatar2.png",
isFollowed: false,
},
],
};
},
computed: {
//
filteredFriends() {
if (!this.searchKeyword) {
return this.recommendFriends;
}
return this.recommendFriends.filter(
(friend) =>
friend.name
.toLowerCase()
.includes(this.searchKeyword.toLowerCase()) ||
friend.school.toLowerCase().includes(this.searchKeyword.toLowerCase())
);
},
},
methods: {
//
toggleFollow(index) {
this.recommendFriends[index].isFollowed =
!this.recommendFriends[index].isFollowed;
// /API
const friend = this.recommendFriends[index];
const action = friend.isFollowed ? "关注" : "取消关注";
uni.showToast({
title: `${action}成功`,
icon: "none",
});
},
//
removeUser(index) {
uni.showModal({
// title: "",
content: "确定不再推荐此用户吗?",
success: (res) => {
if (res.confirm) {
this.recommendFriends.splice(index, 1);
uni.showToast({
title: "已移除此推荐",
icon: "none",
});
}
},
});
},
},
};
</script>
<style lang="scss" scoped>
.more-friends-page {
min-height: 100vh;
background-color: #fff;
padding-bottom: 30rpx;
//
.search-container {
padding: 20rpx 30rpx;
.search-box {
background-color: #f5f5f5;
border-radius: 36rpx;
padding: 16rpx 30rpx;
display: flex;
align-items: center;
input {
flex: 1;
margin-left: 16rpx;
font-size: 28rpx;
color: #333;
}
}
}
//
.friends-list {
.friend-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
// border-bottom: 1px solid #f5f5f5;
//
.avatar {
width: 88rpx;
height: 88rpx;
border-radius: 50%;
margin-right: 24rpx;
}
//
.user-info {
display: flex;
align-items: center;
flex: 1;
.username {
font-size: 28rpx;
font-weight: bold;
color: rgba(0, 0, 0, 0.9);
display: block;
margin-bottom: 8rpx;
margin-right: 24rpx;
}
.school {
font-size: 24rpx;
color: #3cb5fb;
background-color: rgba(41, 151, 255, 0.1);
padding: 4rpx 12rpx;
border-radius: 200rpx;
}
}
//
.follow-btn {
width: 120rpx;
height: 64rpx;
line-height: 64rpx;
text-align: center;
font-size: 28rpx;
border-radius: 36rpx;
margin-right: 24rpx;
color: #3cb5fb;
border: 1rpx solid #3cb5fb;
&.followed {
color: rgba(0, 0, 0, 0.2);
border: 1rpx solid rgba(0, 0, 0, 0.2);
}
}
//
.remove-btn {
padding: 10rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,346 @@
<template>
<view class="search-page">
<!-- 头部搜索区域 -->
<view class="search-header">
<!-- 返回按钮 -->
<view class="back-btn" @click="goBack">
<image
src="/static/common/img/homepage/icon-back.png"
mode="widthFix"
style="width: 48rpx; height: 48rpx"
></image>
</view>
<!-- 搜索输入框 -->
<view class="search-input">
<u-icon name="search" size="36rpx" color="#999"></u-icon>
<input
type="text"
v-model="searchValue"
placeholder="搜索"
confirm-type="search"
@confirm="handleSearch"
focus
clearable
/>
<u-icon
v-if="searchValue"
name="close"
size="36rpx"
color="#999"
@click="clearSearch"
></u-icon>
</view>
<!-- 右侧功能图标 -->
<!-- <view class="action-btns">
<u-icon name="more-dot-fill" size="44rpx" color="#333"></u-icon>
<u-icon name="plus-circle" size="44rpx" color="#333" class="ml-20"></u-icon>
</view> -->
</view>
<!-- 历史记录区域 -->
<view class="search-history">
<view class="history-header">
<text class="section-title">历史记录</text>
<!-- <u-icon
name="trash"
size="40rpx"
color="#999"
></u-icon> -->
<image
src="/static/common/img/homepage/icon-delete.png"
mode="widthFix"
style="width: 48rpx; height: 48rpx"
@click="clearHistory"
></image>
</view>
<!-- 历史标签列表 -->
<view class="history-tags">
<view
class="tag-item"
v-for="(tag, index) in historyTags"
:key="index"
@click="searchByTag(tag)"
>
{{ tag }}
</view>
<view class="tag-item more" @click="toggleMoreTags">
<u-icon name="arrow-down" size="28rpx" color="#333"></u-icon>
</view>
</view>
</view>
<!-- 猜你想搜区域 -->
<view class="search-suggestion">
<view class="suggestion-header">
<text class="section-title">猜你想搜</text>
<!-- <u-icon name="reload" size="36rpx" color="#999"></u-icon> -->
<image
src="/static/common/img/homepage/icon-refresh.png"
mode="widthFix"
style="width: 48rpx; height: 48rpx"
@click="refreshSuggestions"
></image>
</view>
<!-- 推荐搜索列表 -->
<view class="suggestion-list">
<view
class="suggestion-item"
v-for="(item, index) in suggestions"
:key="index"
@click="searchByTag(item)"
>
{{ item }}
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "SearchPage",
data() {
return {
searchValue: "",
historyTags: [
"时尚",
"游戏",
"南小翼",
"返校预约",
"查询档案",
"查询档案",
"校友卡",
],
suggestions: [
"友问答租属小京跳舞",
"哪吒cos自创",
"真人机甲对战",
"马克摩音乐完整版",
"跑步心率最高多少",
"友问答租属小京跳舞",
],
};
},
methods: {
//
goBack() {
uni.navigateBack();
},
//
handleSearch() {
if (!this.searchValue.trim()) return;
//
if (!this.historyTags.includes(this.searchValue)) {
this.historyTags.unshift(this.searchValue);
// 10
if (this.historyTags.length > 10) {
this.historyTags = this.historyTags.slice(0, 10);
}
//
uni.setStorageSync("searchHistory", JSON.stringify(this.historyTags));
}
//
this.doSearch(this.searchValue);
},
//
clearSearch() {
this.searchValue = "";
},
//
clearHistory() {
uni.showModal({
// title: "",
content: "确定清空搜索历史?",
success: (res) => {
if (res.confirm) {
this.historyTags = [];
uni.removeStorageSync("searchHistory");
uni.showToast({
title: "已清空历史记录",
icon: "none",
});
}
},
});
},
// 使
searchByTag(tag) {
this.searchValue = tag;
this.handleSearch();
},
//
toggleMoreTags() {
//
uni.showToast({
title: "展开更多标签",
icon: "none",
});
},
//
refreshSuggestions() {
//
uni.showToast({
title: "已刷新推荐",
icon: "none",
});
//
this.suggestions = this.suggestions.sort(() => Math.random() - 0.5);
},
//
doSearch(keyword) {
console.log("搜索:", keyword);
//
uni.showToast({
title: `搜索: ${keyword}`,
icon: "none",
});
},
},
onLoad() {
//
const history = uni.getStorageSync("searchHistory");
if (history) {
try {
this.historyTags = JSON.parse(history);
} catch (e) {
console.error("解析历史记录失败:", e);
}
}
},
};
</script>
<style lang="scss" scoped>
.search-page {
min-height: 100vh;
background-color: #ffffff;
padding: 0 24rpx;
//
.search-header {
display: flex;
align-items: center;
padding: 20rpx 0;
.back-btn {
margin-right: 24rpx;
}
.search-input {
width: 380rpx;
height: 72rpx;
background-color: #f0f0f0;
border-radius: 36rpx;
display: flex;
align-items: center;
padding: 0 20rpx;
input {
flex: 1;
height: 100%;
font-size: 28rpx;
margin: 0 16rpx;
}
}
.action-btns {
display: flex;
margin-left: 20rpx;
.ml-20 {
margin-left: 20rpx;
}
}
}
//
.search-history {
margin-top: 30rpx;
.history-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.history-tags {
display: flex;
flex-wrap: wrap;
.tag-item {
height: 64rpx;
padding: 0 30rpx;
background-color: #fff;
border-radius: 32rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #333;
margin-right: 20rpx;
margin-bottom: 20rpx;
border: 2rpx solid rgba(0, 0, 0, 0.1);
&.more {
padding: 0;
width: 64rpx;
}
}
}
}
//
.search-suggestion {
margin-top: 40rpx;
.suggestion-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
}
.suggestion-list {
display: flex;
flex-wrap: wrap;
.suggestion-item {
width: 50%;
padding: 10rpx 0;
font-size: 28rpx;
color: #333;
}
}
}
}
</style>

View File

@ -0,0 +1,310 @@
<template>
<!-- 首页-话题组件 -->
<view class="topic-page">
<!-- 顶部分类标签 -->
<scroll-view scroll-x class="category-tabs" show-scrollbar="false">
<view
v-for="(item, index) in categories"
:key="index"
class="tab-item"
:class="{ active: activeTab === index }"
@click="switchTab(item,index)"
:style="{ backgroundImage: `url(${item.image})` }"
>
<view class="tab-overlay"></view>
<text>{{ item.name }}</text>
<text class="sub-text">{{ item.subtitle }}</text>
</view>
</scroll-view>
<!-- 热门话题区域 -->
<view class="hot-topics-container">
<view class="section-title">热门话题</view>
<view class="hot-topics">
<!-- 使用循环渲染热门话题项目 -->
<view
class="topic-item"
v-for="(item, index) in hotTopics"
:key="index"
>
<view class="tag-text">#</view>
<view>
<view class="topic-tag">
<text class="tag-title">{{ item.title }}</text>
<text
v-if="item.tag"
class="tag-hot"
:class="{ orange: item.tag === '新' }"
>{{ item.tag }}</text
>
</view>
<view class="topic-desc">{{ item.description }}</view>
</view>
</view>
</view>
</view>
<!-- 关注的话题区域 -->
<view class="followed-topics-container">
<view class="section-title">关注的话题</view>
<view class="followed-topics">
<!-- 使用循环渲染关注话题项目 -->
<view
class="followed-topic-item"
v-for="(item, index) in followedTopics"
:key="index"
>
<image
class="topic-image"
:src="item.image"
mode="aspectFill"
></image>
<view class="topic-content">
<view class="topic-title">{{ item.title }}</view>
<view class="topic-subtitle">{{ item.subtitle }}</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "Topic",
data() {
return {
activeTab: 0,
categories: [
{
name: "广场",
subtitle: "全部话题",
image: "/static/common/img/homepage/image-photo1.png",
},
{
name: "游戏",
subtitle: "一起开黑",
image: "/static/common/img/homepage/image-photo2.png",
},
{
name: "学习",
subtitle: "天天向上",
image: "/static/common/img/homepage/image-photo1.png",
},
{
name: "社交",
subtitle: "校园交友",
image: "/static/common/img/homepage/image-photo2.png",
},
],
hotTopics: [
{ title: "准大学生你好", description: "开学季来了", tag: "热" },
{ title: "准大学生你好", description: "开学季来了", tag: "热" },
{ title: "军训晒黑了吗", description: "各大高校谁最黑", tag: "热" },
{ title: "军训晒黑了吗", description: "各大高校谁最黑", tag: "新" },
{ title: "防晒霜推荐", description: "我是最靓的仔" },
{ title: "防晒霜推荐", description: "我是最靓的仔" },
],
followedTopics: [
{
image: "/static/common/img/homepage/image-photo1.png",
title: "看到最文艺的话",
subtitle: "生活中常见的文艺文字...",
},
{
image: "/static/common/img/homepage/image-photo2.png",
title: "用来装通的冷知识",
subtitle: "不知道的冷知识,还怎么装...",
},
],
};
},
methods: {
switchTab(item,index) {
this.activeTab = index;
console.log(item, index);
if(index == 0){
this.$u.route({
url: "/pages/home/home/components/topic/topicSquare",
});
}
},
},
};
</script>
<style lang="scss" scoped>
.topic-page {
padding: 24rpx 8rpx 0;
//
.category-tabs {
display: flex;
white-space: nowrap;
margin: 20rpx 0;
.tab-item {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
border-radius: 18rpx;
padding-left: 32rpx;
margin-right: 20rpx;
width: 200rpx;
height: 160rpx;
position: relative;
background-size: cover;
background-position: center;
overflow: hidden;
//
.tab-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(230, 247, 252, 0.55); //
z-index: 1;
}
&.active .tab-overlay {
background-color: rgba(0, 194, 255, 0.85); //
}
text {
font-size: 32rpx;
color: #333;
// font-weight: 600;
position: relative; //
z-index: 2;
}
.sub-text {
font-size: 24rpx;
color: #666;
margin-top: 10rpx;
position: relative; //
z-index: 2;
}
&.active {
text,
.sub-text {
color: #fff;
}
}
}
}
//
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
height: 100rpx;
line-height: 100rpx;
}
.hot-topics-container {
background-color: #fff;
padding: 0 24rpx 24rpx 32rpx;
border-radius: 24rpx;
//
.hot-topics {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.topic-item {
width: 49%;
margin-bottom: 24rpx;
display: flex;
.tag-text {
color: #00c2ff;
font-weight: bold;
margin-right: 12rpx;
}
.topic-tag {
display: flex;
align-items: center;
.tag-title {
font-size: 32rpx;
color: #1f2232;
font-weight: 500;
}
.tag-hot {
font-size: 22rpx;
color: #fff;
background-color: #ff4d4f;
border-radius: 8rpx;
padding: 2rpx 8rpx;
margin-left: 12rpx;
&.orange {
background-color: #ff9500;
}
}
}
.topic-desc {
font-size: 24rpx;
color: rgba(0, 0, 0, 0.6);
margin-top: 12rpx;
}
}
}
}
//
.followed-topics-container {
background-color: #fff;
padding: 0 24rpx 24rpx 32rpx;
border-radius: 24rpx;
margin-top: 24rpx;
.followed-topics {
.followed-topic-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1px solid #f6f8f9;
.topic-image {
width: 100rpx;
height: 100rpx;
border-radius: 12rpx;
margin-right: 20rpx;
}
.topic-content {
flex: 1;
.topic-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
margin-bottom: 10rpx;
}
.topic-subtitle {
font-size: 24rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,300 @@
<template>
<view class="topic-detail-page">
<u-navbar
title=""
:border-bottom="false"
back-icon-color="#fff"
:background="{ background: 'transparent' }"
></u-navbar>
<!-- 话题头部信息 -->
<view class="topic-header">
<!-- 话题标题和描述 -->
<view class="topic-info">
<!-- 话题缩略图 -->
<image
class="topic-thumbnail"
src="/static/common/img/homepage/image-photo1.png"
mode="aspectFill"
></image>
<view class="topic-info-content">
<view class="topic-title">
<text class="hash">#</text>看到最文艺的话
</view>
<view class="topic-description">
生活中经常看到的文艺的文字记录下来摒组品体其中的每一个字眼生活中经常看到的文艺的文字记录下来
</view>
</view>
</view>
<view class="topic-stats-container">
<!-- 话题统计 -->
<view class="topic-stats">
<text class="stat-item">233267关注</text>
<text class="stat-item">25216动态</text>
</view>
<!-- 关注按钮 -->
<view class="follow-btn">
<u-icon name="plus" size="22rpx" color="#fff"></u-icon>
</view>
</view>
</view>
<!-- 内容分类标签 -->
<view class="nav-container">
<view
v-for="(item, index) in tabs"
:key="index"
class="nav-item"
:class="{ active: activeTab === index }"
@click="switchTab(index)"
>
{{ item }}
<view v-if="activeTab === index" class="active-line"></view>
</view>
</view>
<!-- 话题内容列表 -->
<view class="topic-content">
<!-- 这里可以放置话题内容列表组件 -->
<content-card
v-for="(card, index) in contentCards"
:key="index"
:cardData="card"
></content-card>
</view>
</view>
</template>
<script>
import ContentCard from "@/components/ContentCard.vue";
export default {
name: "TopicDetail",
components: {
ContentCard,
},
data() {
return {
topic: {
id: "1",
title: "看到最文艺的话",
description:
"生活中经常看到的文艺的文字,记录下来,摒组品体其中的每一个字眼,",
followers: 233267,
posts: 25216,
isFollowed: false,
thumbnail: "/static/common/img/homepage/image-photo1.png",
},
activeTab: 0,
tabs: ["推荐", "最新"],
//
contentCards: [
//
{
user: {
avatar: "/static/common/img/homepage/avatar3.png",
name: "calista33",
meta: "2小时前 北京大学",
},
content: "今日份走停停的小确幸。",
type: "image",
images: [
"/static/common/img/homepage/image-photo1.png",
"/static/common/img/homepage/image-photo2.png",
"/static/common/img/homepage/image-photo3.png",
],
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
//
{
user: {
avatar: "/static/common/img/homepage/avatar.png",
name: "Kohaku",
meta: "2小时前 北京大学",
},
content: "看看我拍的这个视频•",
type: "video",
cover: "/static/images/video-cover.png",
videoUrl: "https://example.com/video.mp4",
duration: 145, // 225
stats: {
forward: 102,
comment: 102,
like: 212,
favorite: 62,
},
},
],
};
},
methods: {
switchTab(index) {
this.activeTab = index;
},
toggleFollow() {
this.topic.isFollowed = !this.topic.isFollowed;
// /API
uni.showToast({
title: this.topic.isFollowed ? "已关注" : "已取消关注",
icon: "none",
});
},
},
};
</script>
<style lang="scss" scoped>
.topic-detail-page {
width: 100%;
min-height: 100vh;
background: url("/static/common/img/homepage/image-topic-bg.png") no-repeat
top center;
background-size: 100% 592rpx;
//
.topic-header {
padding: 40rpx;
display: flex;
flex-direction: column;
//
.topic-info {
// flex: 1;
display: flex;
// align-items: center;
color: #fff;
margin-bottom: 24rpx;
//
.topic-thumbnail {
width: 140rpx;
height: 140rpx;
border-radius: 16rpx;
overflow: hidden;
margin-right: 24rpx;
}
.topic-info-content {
width: calc(100% - 180rpx);
.topic-title {
font-size: 32rpx;
font-weight: bold;
margin-bottom: 16rpx;
.hash {
font-weight: normal;
margin-right: 4rpx;
}
}
.topic-description {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
line-height: 1.5;
display: -webkit-box;
white-space: wrap;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
.topic-stats-container {
height: 80rpx;
display: flex;
align-items: center;
justify-content: space-between;
.topic-stats {
font-size: 24rpx;
color: #ffffff;
.stat-item {
margin-right: 30rpx;
}
}
//
.follow-btn {
width: 120rpx;
height: 56rpx;
line-height: 56rpx;
text-align: center;
font-size: 24rpx;
color: #fff;
background: linear-gradient(178deg, #3cb5fb 0%, #06e1fa 100%);
border-radius: 30rpx;
}
}
}
//
.nav-container {
width: 100%;
height: 80rpx;
line-height: 80rpx;
border-radius: 30rpx 30rpx 0 0;
background-color: #fff;
padding: 0 20rpx;
display: inline-flex;
}
.nav-item {
display: inline-block;
width: auto;
min-width: 120rpx;
padding: 0 20rpx;
text-align: center;
font-size: 32rpx;
color: #666;
position: relative;
z-index: 20;
transition: all 0.3s ease; /* 添加过渡效果 */
transform-origin: center bottom; /* 设置变换原点在底部中心 */
&.active {
color: #333;
font-weight: bold;
}
.active-line {
position: absolute;
left: 50%; /* 将左边距设为50% */
transform: translateX(-50%); /* 向左偏移自身宽度的50%,实现水平居中 */
bottom: 25rpx;
width: 60rpx;
height: 12rpx;
background: linear-gradient(
116deg,
rgba(60, 181, 251, 0) 0%,
#28c6fb 45%,
#06e1fa 100%
);
border-radius: 2rpx;
z-index: -1;
}
}
//
.topic-content {
background-color: #f6f8f9;
height: 830rpx;
overflow-y: auto;
padding: 24rpx;
}
}
</style>

View File

@ -0,0 +1,345 @@
<template>
<view class="topic-square-page">
<u-navbar title="话题广场" :border-bottom="false"></u-navbar>
<!-- 搜索框 -->
<view class="search-container">
<view class="search-box">
<u-icon name="search" size="40rpx" color="#999"></u-icon>
<input
type="text"
placeholder="搜索要查找的话题"
v-model="searchKeyword"
/>
</view>
<view class="search-add-btn">
<u-icon name="plus" size="40rpx" color="#333"></u-icon>
</view>
</view>
<!-- 类别导航 -->
<scroll-view
scroll-x
class="category-nav"
:show-scrollbar="false"
:enhanced="true"
:paging-enabled="false"
>
<view class="nav-container">
<view
v-for="(item, index) in categories"
:key="index"
class="nav-item"
:class="{ active: activeCategory === index }"
@click="switchCategory(index)"
>
{{ item }}
<view v-if="activeCategory === index" class="active-line"></view>
</view>
</view>
</scroll-view>
<!-- 话题列表 -->
<view class="topic-list">
<view
class="topic-item"
v-for="(item, index) in filteredTopics"
:key="index"
@click="goToTopicDetail(item)"
>
<!-- 话题图片 -->
<image class="topic-image" :src="item.image" mode="aspectFill"></image>
<!-- 话题内容 -->
<view class="topic-content">
<view class="topic-title">{{ item.title }}</view>
<view class="topic-desc">{{ item.description }}</view>
</view>
<!-- 关注按钮 -->
<view
class="follow-btn"
:class="{ followed: item.isFollowed }"
@click="toggleFollow(index)"
>
<view v-if="item.isFollowed">已关注</view>
<view v-else
><u-icon name="plus" size="22rpx" color="#fff"></u-icon> </view
>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: "TopicSquare",
data() {
return {
searchKeyword: "",
activeCategory: 0,
categories: [
"全部",
"学校",
"社团",
"学习",
"游戏",
"恋爱",
"生活",
"其他",
],
topics: [
{
title: "看到最文艺的话",
description: "生活中常见的文艺文字...",
image: "/static/common/img/homepage/image-photo1.png",
isFollowed: true,
category: 0,
},
{
title: "看到最文艺的话",
description: "生活中常见的文艺文字...",
image: "/static/common/img/homepage/image-photo2.png",
isFollowed: true,
category: 1,
},
{
title: "用来装通的冷知识",
description: "不知道的冷知识,还怎么装...",
image: "/static/common/img/homepage/image-photo3.png",
isFollowed: true,
category: 2,
},
{
title: "看到最文艺的话",
description: "生活中常见的文艺文字...",
image: "/static/common/img/homepage/image-photo1.png",
isFollowed: false,
category: 3,
},
{
title: "用来装通的冷知识",
description: "不知道的冷知识,还怎么装...",
image: "/static/common/img/homepage/image-photo2.png",
isFollowed: false,
category: 4,
},
{
title: "看到最文艺的话",
description: "生活中常见的文艺文字...",
image: "/static/common/img/homepage/image-photo3.png",
isFollowed: false,
category: 0,
},
{
title: "看到最文艺的话",
description: "生活中常见的文艺文字...",
image: "/static/common/img/homepage/image-photo2.png",
isFollowed: false,
category: 1,
},
],
};
},
computed: {
filteredTopics() {
//
let result = this.topics;
if (this.activeCategory !== 0) {
result = result.filter(
(topic) => topic.category === this.activeCategory
);
}
//
if (this.searchKeyword.trim()) {
const keyword = this.searchKeyword.toLowerCase();
result = result.filter(
(topic) =>
topic.title.toLowerCase().includes(keyword) ||
topic.description.toLowerCase().includes(keyword)
);
}
return result;
},
},
methods: {
//
switchCategory(index) {
this.activeCategory = index;
},
//
toggleFollow(index) {
const topicIndex = this.topics.findIndex(
(topic) => topic === this.filteredTopics[index]
);
if (topicIndex !== -1) {
this.topics[topicIndex].isFollowed =
!this.topics[topicIndex].isFollowed;
// /API
uni.showToast({
title: this.topics[topicIndex].isFollowed ? "已关注" : "已取消关注",
icon: "none",
});
}
},
//
goToTopicDetail(item) {
this.$u.route({
url: `/pages/home/home/components/topic/topicDetail`,
// url: `/pages/home/home/components/topic/topicDetail?topicId=${item.id}`,
});
},
},
};
</script>
<style lang="scss" scoped>
.topic-square-page {
min-height: 100vh;
background-color: #fff;
//
.search-container {
padding: 20rpx 30rpx;
display: flex;
align-items: center;
.search-box {
flex: 1;
background-color: #f5f5f5;
border-radius: 36rpx;
padding: 16rpx 30rpx;
display: flex;
align-items: center;
input {
flex: 1;
margin-left: 16rpx;
font-size: 28rpx;
color: #333;
}
}
.search-add-btn {
background-color: #f5f5f5;
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
display: flex;
align-items: center;
justify-content: center;
margin-left: 20rpx;
}
}
//
.category-nav {
white-space: nowrap;
margin: 20rpx 0;
.nav-container {
padding: 0 20rpx;
display: inline-flex;
}
.nav-item {
display: inline-block;
width: auto;
min-width: 120rpx;
padding: 0 20rpx;
text-align: center;
font-size: 32rpx;
color: #666;
position: relative;
z-index: 20;
transition: all 0.3s ease; /* 添加过渡效果 */
transform-origin: center bottom; /* 设置变换原点在底部中心 */
&.active {
color: #333;
font-weight: bold;
}
.active-line {
position: absolute;
left: 50%; /* 将左边距设为50% */
transform: translateX(-50%); /* 向左偏移自身宽度的50%,实现水平居中 */
bottom: 4rpx;
width: 60rpx;
height: 12rpx;
background: linear-gradient(
116deg,
rgba(60, 181, 251, 0) 0%,
#28c6fb 45%,
#06e1fa 100%
);
border-radius: 2rpx;
z-index: -1;
}
}
}
//
.topic-list {
padding: 20rpx 36rpx;
.topic-item {
display: flex;
align-items: center;
padding: 30rpx 0;
background-color: #fff;
border-radius: 12rpx;
border-bottom: 1rpx solid #f6f8f9;
.topic-image {
width: 100rpx;
height: 100rpx;
border-radius: 12rpx;
margin-right: 20rpx;
}
.topic-content {
flex: 1;
.topic-title {
font-size: 32rpx;
color: #1f2232;
// font-weight: bold;
margin-bottom: 8rpx;
}
.topic-desc {
font-size: 24rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.follow-btn {
width: 104rpx;
height: 56rpx;
line-height: 56rpx;
text-align: center;
font-size: 24rpx;
color: #fff;
background: linear-gradient(178deg, #3cb5fb 0%, #06e1fa 100%);
border-radius: 30rpx;
&.followed {
color: rgba(0, 0, 0, 0.9);
background: #fff;
border: 1rpx solid rgba(0, 0, 0, 0.15);
}
}
}
}
}
</style>

243
pages/home/home/home.vue Normal file
View File

@ -0,0 +1,243 @@
<template>
<view class="home-page">
<!-- 顶部搜索栏 5/20 隐藏 -->
<view class="home-search" @click="goSearch">
<u-search
placeholder="搜索"
search-icon="search"
:show-action="false"
bg-color="#fff"
>
</u-search>
</view>
<!-- 顶部导航栏 5/20 隐藏 -->
<!-- <view class="nav-tabs">
<view
v-for="(item, index) in tabList"
:key="index"
class="tab"
:class="{ active: currentTab === index }"
@click="switchTab(index)"
>
{{ item }}
<view v-if="currentTab === index" class="active-line"></view>
</view>
</view> -->
<!-- 推荐组件 -->
<recommend v-if="currentTab === 0" ref="recommendComp"></recommend>
<!-- 本校组件 -->
<our-school
v-if="false && currentTab === 1"
ref="ourSchoolComp"
></our-school>
<!-- 校园资讯组件 -->
<campus-info
v-if="false && currentTab === 2"
ref="campusInfoComp"
></campus-info>
<!-- 话题组件 -->
<topic v-if="false && currentTab === 3" ref="topicComp"></topic>
<!-- 空盒子 -->
<view class="empty-box"></view>
<u-tabbar
:list="vuex_tabbar"
:class="{ phone: vuex_iPhone }"
:active-color="vuex_tabbar_config.activeColor"
:inactive-color="vuex_tabbar_config.inactiveColor"
></u-tabbar>
</view>
</template>
<script>
import Recommend from "./components/recommend/index.vue";
import OurSchool from "./components/ourSchool/index.vue";
import CampusInfo from "./components/campusInfo/index.vue";
import Topic from "./components/topic/index.vue";
export default {
components: {
Recommend,
OurSchool,
CampusInfo,
Topic,
},
data() {
return {
currentTab: 0,
tabList: ["推荐", "本校", "校园资讯", "话题"],
//
tabBackgrounds: [
"linear-gradient(180deg, #b6e4ff 0%, #f6f8f9 45%, #f6f8f9 100%)", //
"linear-gradient( 180deg, #c2e8fe 0%, #F6F8F9 15%, #F6F8F9 45%, #F6F8F9 100%)", //
],
// tabref
tabConfig: [
{ ref: "recommendComp", refreshMethod: "refreshAll" },
{ ref: "ourSchoolComp", refreshMethod: "refreshAll" },
{ ref: "campusInfoComp", refreshMethod: "refreshAll" },
{ ref: "topicComp", refreshMethod: "refreshAll" },
],
EdcationList: [], //
schoolName: "", //
};
},
onLoad(e) {},
onShow() {
// tab
this.refreshCurrentTab();
//
this.getEducation();
},
computed: {
//
pageStyle() {
return {
background:
this.currentTab === 0
? this.tabBackgrounds[0]
: this.tabBackgrounds[1],
};
},
},
methods: {
// 5/20
// switchTab(index) {
// this.currentTab = index;
// // tab
// this.refreshCurrentTab();
// },
// 5/20
// 2/28
goSearch() {
// console.log("goSearch");
// this.$u.route({
// url: "/pages/home/home/components/searchPage/index",
// });
if (this.vuex_user.isAttestationXY || true) {
this.$u.route({
url: "/pages/main/search/search",
params: {
type: "home",
},
});
} else {
this.$refs.uToast.show({
title: "认证后才能进行搜索哦",
url: "/pages/my/ShoolList/ShoolList",
});
}
},
// tab
refreshCurrentTab() {
this.$nextTick(() => {
const config = this.tabConfig[this.currentTab];
if (
this.$refs[config.ref] &&
typeof this.$refs[config.ref][config.refreshMethod] === "function"
) {
this.$refs[config.ref][config.refreshMethod]();
}
});
},
getEducation() {
const data = {
userId: this.vuex_user.id,
};
this.$u.apiList.MyPage(data).then((res) => {
//
this.schoolName =
res.edcationList.length > 0
? res.edcationList[0].schoolName || res.edcationList[0].school
: "";
//
this.EdcationList = res.edcationList || [];
this.$u.vuex("vuex_schoolName", this.schoolName);
this.$u.vuex("vuex_education", this.EdcationList);
});
},
},
};
</script>
<style scoped lang="scss">
.home-page {
width: 100%;
height: 100%;
padding: 24rpx 24rpx;
background: linear-gradient(180deg, #b6e4ff 0%, #f6f8f9 45%, #f6f8f9 100%);
transition: background 0.3 ease; //
.home-search {
width: 100%;
display: flex;
align-items: center;
// justify-content: space-between;
// padding: 24rpx 0;
margin-bottom: 24rpx;
// .top-icons {
// display: flex;
// align-items: center;
// .ml-15 {
// margin-left: 15rpx;
// }
// }
}
.nav-tabs {
display: flex;
justify-content: space-between;
margin: 20rpx 0;
padding: 0 20rpx;
.tab {
font-size: 32rpx;
color: #666;
position: relative;
z-index: 20;
transition: all 0.3s ease; /* 添加过渡效果 */
transform-origin: center bottom; /* 设置变换原点在底部中心 */
&.active {
// font-size: 36rpx;
transform: scale(1.125); /* 36/32 = 1.125用scale替代font-size变化 */
color: #333;
font-weight: bold;
}
.active-line {
position: absolute;
left: 0;
bottom: 4rpx;
width: 100%;
height: 12rpx;
background: linear-gradient(
116deg,
rgba(60, 181, 251, 0) 0%,
#28c6fb 45%,
#06e1fa 100%
);
border-radius: 2rpx;
z-index: -1;
}
}
}
.empty-box {
height: 60rpx;
}
}
</style>

View File

@ -0,0 +1,425 @@
<template>
<view class="flex-col page">
<!-- <image src="/static/common/img/16530269846087107196.png" class="image"/> -->
<u-navbar title="重置密码"></u-navbar>
<view class="flex-col group" v-if="state === 1">
<text class="text">重置密码</text>
<view class="flex-col group_7">
<view class="flex-col">
<!-- <text class="text_1">手机号</text> -->
<view class="text-wrapper flex-row view">
<u-input
v-model="phone"
:disabled="disabled"
placeholder="请输入手机号"
type="text"
/>
</view>
</view>
<view class="flex-col group_6">
<!-- <text class="text_1">短信验证码</text> -->
<view class="text-wrapper flex-row view" style="padding: 0">
<u-input
v-model="code"
placeholder="请输入短信验证码"
type="text"
/>
<u-button
:disabled="!(send == '发送验证码')"
class="custom-style"
style="background: transparent"
@click="sendCode"
>{{ send }}
</u-button>
</view>
</view>
</view>
<!-- <navigator class="text_6" url="/pages/login/login/login">登录</navigator> -->
<u-button
class="flex-col items-center text-wrapper_1"
shape="circle"
type="primary"
@click="login"
>
<text class="text_7">重置密码</text>
</u-button>
</view>
<view class="flex-col group" v-if="state === 2">
<text class="text">遇见身边的校友</text>
<view class="flex-col group_7">
<view class="flex-col">
<u-input
v-model="passWord"
class="view text-wrapper"
placeholder="请输入新密码"
type="password"
/>
</view>
<view class="flex-col group_6">
<u-input
v-model="passWordTwo"
class="view text-wrapper"
placeholder="请确认新密码"
type="password"
/>
</view>
</view>
<view class="tips">
<image src="/static/common/img/infoCircle.png"></image>
提示密码长度应该大于5必须包含字母数字特殊字符且不能包含中文!
</view>
<u-button
class="flex-col items-center text-wrapper_1"
shape="circle"
throttle-time="1000"
type="primary"
@click="login"
>
<text class="text_7">立即重置</text>
</u-button>
<u-button
class="flex-col items-center text-wrapper_1"
shape="circle"
style=" margin-top: 10px"
type="primary"
@click="state = 1"
>
<text class="text_7">返回</text>
</u-button>
</view>
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
<u-toast ref="uToast"/>
</view>
</template>
<script>
import md5 from "js-md5";
import {aesEncrypt} from "@/utils/encrypt.js";
export default {
data() {
return {
show: false,
phone: "",
passWord: "",
code: "",
passWordTwo: "",
agreement: false,
disabled: false,
send: "发送验证码",
state: 1,
};
},
onLoad(e) {
},
methods: {
//
tips(title, type, time) {
this.$refs.uToast.show({
title: title ? title : "",
type: type ? type : "success",
duration: time ? time + "" : "1500",
});
},
//
sendCode() {
var reg = new RegExp("^[1][3,4,5,6,7,8,9][0-9]{9}$", "g"); //
if (this.phone === "" || !reg.test(this.phone)) {
// this.$tips("", "error");
this.$refs.uToast.show({
title: '请输入正确的手机号码',
type: 'error',
})
return;
}
const timestamp = Date.now();
const base64Key = btoa('xiaoyout!#@12345');
const signStr = this.phone + timestamp + base64Key;
const sign = md5(signStr);
this.$u.apiList
.GetAppValidateCode({
phone: this.phone,
t: timestamp.toString(),
sign: sign,
type: 2,
})
.then((res) => {
//
// let result =this.userName.replace(this.userName.substring(3,7),"****")
// this.userName = result
this.disabled = true;
// this.$tips("");
this.$refs.uToast.show({
title: '发送成功',
type: 'success',
})
var second = 60;
this.send = second + "秒后重试";
var time = setInterval(() => {
this.send = second + "秒后重试";
second--;
if (second <= 0) {
this.disabled = false;
this.send = "发送验证码";
clearInterval(time);
}
}, 1000);
})
.catch((err) => {
// this.$tips(err.error, "error");
this.$refs.uToast.show({
title: err.error,
type: 'error',
})
});
},
login() {
if (this.state == 1) {
if (this.phone === "") {
return this.tips("请输入手机号", "error");
}
if (this.code === "") {
return this.tips("请输入验证码", "error");
}
this.$u.apiList.ForgotPasswordValidate({
phone: this.phone,
code: this.code,
}).then((res) => {
console.info("🚀 ~ file:ForgetPassword method: line:189 -----", res)
this.state = 2;
}).catch((err) => {
this.tips(err.error, "error");
});
return
}
if (this.state == 2) {
if (this.passWord === "") {
return this.tips("请输入新密码", "error");
}
let reg = /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[\W_]).{5,}$/;
if (!reg.test(this.passWord)) {
/* return this.$tips(
"密码必须包含字母、数字、特殊字符,且不能包含中文!",
"error"
); */
return this.$refs.uToast.show({
title: "密码必须包含字母、数字、特殊字符,且不能包含中文!",
type: 'error',
})
}
if (this.passWordTwo === "") {
return this.tips("请确认新密码", "error");
}
if (this.passWord != this.passWordTwo) {
return this.tips("请检查两次密码是否一致", "error");
}
}
const req = {
phone: this.phone,
code: this.code,
newPassWord: aesEncrypt(this.passWord),
};
console.log(req, "res-");
// return
this.$u.apiList
.ForgotPassword(req)
.then((res) => {
console.log(res, "res---");
uni.showToast({
title: "重置成功",
duration: 2000,
});
setTimeout(() => {
uni.navigateTo({
url: "/",
});
}, 2000);
})
.catch((err) => {
console.log(err, "err---");
// this.$tips(err.error, "error");
this.$refs.uToast.show({
title: err.error,
type: 'error',
})
});
},
},
};
</script>
<style scoped lang="scss">
.custom-style {
color: #3cb5fb !important;
padding: 0 !important;
height: 70rpx !important;
line-height: 60rpx !important;
}
.custom-style::after {
border: none;
}
.page {
padding-bottom: 0.015rem;
background-color: rgb(255, 255, 255);
overflow-y: auto;
width: 100%;
overflow-x: hidden;
height: 100%;
.image {
flex-shrink: 0;
align-self: flex-start;
width: 102%;
}
.group {
padding: 1.0rem 0.29rem;
.text {
align-self: left;
// color: rgb(46, 155, 255);
color: #000;
font-size: 0.22rem;
font-family: PingFang;
line-height: 0.17rem;
font-weight: 600;
}
.group_7 {
margin-top: 0.29rem;
.text-wrapper {
border: solid 2rpx #dcdfe6;
border-radius: 100rpx;
background: #f6f8fa;
}
.group_6 {
margin-top: 0.2rem;
}
.text_1 {
margin-left: 0.01rem;
align-self: flex-start;
color: rgb(51, 51, 51);
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
.view {
display: flex;
align-items: center;
margin-top: 20rpx;
padding: 20rpx 50rpx !important;
}
}
.text_6 {
width: 100%;
text-align: right;
margin-left: 0.01rem;
margin-top: 0.2rem;
align-self: flex-start;
color: #1F2232;
font-size: 0.13rem;
font-family: PingFang;
line-height: 0.13rem;
}
.text-wrapper_1 {
margin: 50rpx 0rpx 40rpx;
padding: 50rpx 0 50rpx;
// background-image: linear-gradient(90deg, rgb(135, 230, 254) 0%, rgb(91, 192, 254) 52%, rgb(46, 155, 255) 100%);
background: #3cb4fb;
box-shadow: 0px 6rpx 9rpx rgba(38, 122, 199, 0.34);
border-radius: 100rpx;
.text_7 {
color: rgb(255, 255, 255);
font-size: 32rpx;
font-family: PingFang;
line-height: 32rpx;
}
}
.group_1 {
margin-top: 0.12rem;
.text_8 {
color: rgb(102, 102, 102);
font-size: 24rpx;
font-family: PingFang;
line-height: 0.13rem;
}
.text_9 {
margin-left: 0.035rem;
color: rgb(25, 140, 255);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
}
.group_2 {
margin-top: 0.36rem;
justify-content: center;
.section_1 {
flex-shrink: 0;
width: 0.17rem;
}
.group_3 {
margin-left: 0.11rem;
height: 0.18rem;
line-height: 0.18rem;
font-size: 0;
.text_10 {
color: rgb(153, 153, 153);
font-size: 0.11rem;
font-family: PingFang;
}
.text_11 {
color: rgb(25, 140, 255);
font-size: 0.11rem;
font-family: PingFang;
}
.text_12 {
color: rgb(102, 102, 102);
font-size: 0.11rem;
font-family: PingFang;
}
.text_13 {
color: rgb(25, 140, 255);
font-size: 0.11rem;
font-family: PingFang;
}
}
}
}
}
.tips {
font-size: 24rpx;
color: #EF3920;
display: flex;
margin-top: 20rpx;
image {
width: 32rpx;
height: 32rpx;
margin-right: 10rpx;
margin-top: 5rpx;
}
}
</style>

View File

@ -0,0 +1,177 @@
<template>
<view class="authentication-page">
<u-navbar title="身份认证"> </u-navbar>
<view class="title">请填写您的真实信息</view>
<view class="form-container">
<view class="input-item">
<text>姓名</text>
<input
v-model="name"
maxlength="20"
type="text"
placeholder="请输入"
placeholder-class="placeholder"
/>
</view>
<view class="input-item">
<text>身份证号</text>
<input
v-model="idCard"
maxlength="18"
type="text"
placeholder="请输入"
placeholder-class="placeholder"
/>
</view>
</view>
<view class="btn-container">
<button class="next-btn" @click="handleNext">下一步</button>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import test from "@/uview-ui/libs/function/test.js";
export default {
data() {
return {
name: "",
idCard: "",
};
},
methods: {
handleNext() {
// APItoken
this.getTokenFromBackend();
if (!this.name) {
return this.$refs.uToast.show({
title: "请输入姓名",
type: "warning",
});
}
if (!this.idCard) {
return this.$refs.uToast.show({
title: "请输入身份证号",
type: "warning",
});
}
//
if (!test.idCard(this.idCard)) {
return this.$refs.uToast.show({
title: "请输入正确的身份证号码",
type: "warning",
});
}
//
// console.log("", this.name, this.idCard);
},
// token
getTokenFromBackend() {
this.$u.api.getAPIToken().then((res) => {
const token = res.verifyToken
//
this.redirectToBaiduVerification(token);
});
},
redirectToBaiduVerification(token) {
//
const currentDomain = window.location.origin;
// URL
// const callbackUrl = encodeURIComponent(`${currentDomain}/success.html`);
const callbackUrl = "/pages/login/recognitionResult/recognitionResult";
// URL
const verifyUrl = `https://brain.baidu.com/face/print/verify/verify?token=${token}&successUrl=${callbackUrl}&failedUrl=${callbackUrl}`;
const verifyObj = {
url: verifyUrl,
name:'身份认证'
};
// uni-app
this.$u.route({
url: `/pages/webview/index?data=${encodeURIComponent(
JSON.stringify(verifyObj)
)}`,
});
},
},
};
</script>
<style lang="scss">
.authentication-page {
padding: 0 30rpx;
.title {
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 32rpx;
color: rgba(0, 0, 0, 0.9);
line-height: 52rpx;
text-align: left;
margin-top: 30rpx;
margin-bottom: 40rpx;
}
.form-container {
background-color: #ffffff;
border-radius: 16rpx;
padding: 0 30rpx;
margin-bottom: 60rpx;
.input-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 30rpx 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:last-child {
border-bottom: none;
}
text {
font-size: 28rpx;
color: rgba(0, 0, 0, 0.9);
}
input {
flex: 1;
text-align: right;
font-size: 28rpx;
}
.placeholder {
color: rgba(0, 0, 0, 0.3);
}
}
}
.btn-container {
.next-btn {
background-color: #45b5ff;
color: #ffffff;
height: 90rpx;
line-height: 90rpx;
border-radius: 45rpx;
font-size: 32rpx;
font-weight: 500;
border: none;
}
}
}
</style>

View File

@ -0,0 +1,338 @@
<template>
<view class="flex-col page">
<!-- <image src="/static/common/img/16530269846087107196.png" class="image" /> -->
<u-navbar title="确认密码"></u-navbar>
<view class="flex-col group">
<text class="text">确认密码后登录</text>
<view class="flex-col group_7">
<view class="flex-col">
<view class="flex-row" style="padding: 0">
<u-input type="password" v-model="user.passWord" placeholder="请输入密码" class="view text-wrapper"/>
</view>
</view>
<view class="flex-col group_6">
<u-input type="password" v-model="isPassWord" placeholder="请确认密码" class="view text-wrapper" />
</view>
<view class="tips">
<image src="/static/common/img/infoCircle.png"></image> 提示密码长度应该大于5必须包含字母数字特殊字符且不能包含中文!
</view>
</view>
<u-button class="flex-col items-center text-wrapper_1" throttle-time="1000" type="primary" shape="circle"
@click="login"><text class="text_7">确定</text></u-button>
<!-- 此次接入人脸验证 登录 ==> 确定 -->
</view>
<u-toast ref="uToast" />
<u-top-tips ref="uTips" :navbar-height="0"></u-top-tips>
</view>
</template>
<script>
import {aesEncrypt} from '@/utils/encrypt.js'
import md5 from "js-md5";
export default {
data() {
return {
show: false,
userName: "",
isPassWord: "",
agreement: false,
user: {
phone: '',
passWord: '',
code:''
}
};
},
onLoad(e) {
if (e.phone) {
this.user.phone = e.phone
this.user.code = e.code
} else {
uni.navigateTo({
url: "../register/register",
});
}
},
methods: {
login() {
if (this.user.passWord === "") {
return this.$refs.uToast.show({
title: '请输入密码',
type: 'error',
})
}
if (this.user.passWord.length < 5) {
// return this.$tips("5", "error");
return this.$refs.uToast.show({
title: '您的密码长度应该大于5',
type: 'error',
})
}
if (this.isPassWord === "") {
return this.$refs.uToast.show({
title: '请确认密码',
type: 'error',
})
// return this.$tips("", "error");
}
if (this.isPassWord !== this.user.passWord) {
return this.$refs.uToast.show({
title: '请确认两次密码是否一致',
type: 'error',
})
// return this.$tips("", "error");
}
uni.showLoading({
title: "注册中",
});
const req = {...this.user}
req.passWord = aesEncrypt(this.user.passWord)
// 13
const timestamp = Date.now();
//
const base64Key = btoa('xiaoyout!#@12345');
const signStr = this.user.phone + timestamp + base64Key;
const sign = md5(signStr);
req.timeStamp = timestamp.toString();
req.sign = sign;
console.log(req,'req')
// return
this.$u.api.RegisterUser(req).then((res) => {
const newReq = {...this.user}
newReq.passWord = aesEncrypt(this.user.passWord)
this.$u.api.LoginApp(newReq).then((ress) => {
uni.hideLoading();
//
this.$u.vuex('vuex_user', ress.user)
this.$u.vuex('vuex_token', ress.token)
this.$refs.uToast.show({
title: '注册成功',
type: 'success',
})
// uni.navigateTo({
// url: "../perfect/perfect",
// });
setTimeout(()=>{
//
this.toBaiduApi();
return
uni.navigateTo({
url: "/pages/login/roleSelection",
});
},300)
}).catch((e) => {
uni.hideLoading();
});
}).catch((e) => {
uni.hideLoading();
// this.$tips( e.error, 'error')
this.$refs.uToast.show({
title: e.error,
type: 'error',
})
});
},
//
toBaiduApi(){
this.$u.api.getAPIToken().then((res) => {
const token = res.result.verify_token;
//
this.redirectToBaiduVerification(token);
});
},
redirectToBaiduVerification(token) {
//
const currentDomain = window.location.origin;
// URL - 使uni-app
// URLverify_resultverify_info
const successUrl = encodeURIComponent(
`${currentDomain}/#/pages/login/recognitionResult/recognitionResult?token=${token}`
);
const failedUrl = encodeURIComponent(
`${currentDomain}/#/pages/login/recognitionResult/recognitionFailed?token=${token}`
);
// URL
const verifyUrl = `https://brain.baidu.com/face/print/verify/verify?token=${token}&successUrl=${successUrl}&failedUrl=${failedUrl}`;
console.log("跳转到百度人脸核验页面:", verifyUrl);
//
window.location.href = verifyUrl;
return;
},
},
};
</script>
<style scoped lang="scss">
.custom-style {
color: #606266;
}
.custom-style::after {
border: none;
}
.page {
padding-bottom: 0.015rem;
background-color: rgb(255, 255, 255);
overflow-y: auto;
width: 100%;
overflow-x: hidden;
height: 100%;
.image {
flex-shrink: 0;
align-self: flex-start;
width: 102%;
}
.group {
padding: 0.15rem 0.29rem;
.text {
font-family: PingFang;
font-weight: bold;
font-size: 48rpx;
color: #000000;
margin-top: 200rpx;
}
.group_7 {
margin-top: 0.29rem;
.text-wrapper {
border: solid 2rpx #dcdfe6;
border-radius: 100rpx;
background: #f6f8fa;
}
.group_6 {
margin-top: 0.2rem;
}
.text_1 {
margin-left: 0.01rem;
align-self: flex-start;
color: rgb(51, 51, 51);
font-size: 0.15rem;
font-family: PingFang;
line-height: 0.14rem;
}
.view {
margin-top: 20rpx;
padding: 20rpx 50rpx !important;
}
}
.text_6 {
margin-left: 0.01rem;
margin-top: 0.13rem;
align-self: flex-start;
color: rgb(25, 140, 255);
font-size: 0.13rem;
font-family: PingFang;
line-height: 0.13rem;
}
.text-wrapper_1 {
margin: 0.35rem 0rem 0;
padding: 20rpx 50rpx;
height: 108rpx;
/* background-image: linear-gradient(90deg,
rgb(135, 230, 254) 0%,
rgb(91, 192, 254) 52%,
rgb(46, 155, 255) 100%);
box-shadow: 0px 0.03rem 0.09rem rgba(38, 122, 199, 0.34); */
background: #3cb5fb;
border-radius: 0.23rem;
.text_7 {
color: rgb(255, 255, 255);
font-size: 0.16rem;
font-family: PingFang;
line-height: 0.15rem;
}
}
.group_1 {
margin-top: 0.12rem;
.text_8 {
color: rgb(102, 102, 102);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
.text_9 {
margin-left: 0.035rem;
color: rgb(25, 140, 255);
font-size: 0.14rem;
font-family: PingFang;
line-height: 0.13rem;
}
}
.group_2 {
margin-top: 0.36rem;
justify-content: center;
.section_1 {
flex-shrink: 0;
width: 0.17rem;
}
.group_3 {
margin-left: 0.11rem;
height: 0.18rem;
line-height: 0.18rem;
font-size: 0;
.text_10 {
color: rgb(153, 153, 153);
font-size: 0.11rem;
font-family: PingFang;
}
.text_11 {
color: rgb(25, 140, 255);
font-size: 0.11rem;
font-family: PingFang;
}
.text_12 {
color: rgb(102, 102, 102);
font-size: 0.11rem;
font-family: PingFang;
}
.text_13 {
color: rgb(25, 140, 255);
font-size: 0.11rem;
font-family: PingFang;
}
}
}
}
.tips{
font-size: 24rpx;
color: #EF3920;
display: flex;
margin-top: 20rpx;
image{
width: 32rpx;
height: 32rpx;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

532
pages/login/login/login.vue Normal file
View File

@ -0,0 +1,532 @@
<template>
<view class="flex-col page">
<!-- <image src="/static/common/img/loginBg.png" class="image" /> -->
<view class="img-box">
</view>
<view class="login-box">
<view class="tab-list">
<view v-for="tab in tabList" :key="tab.id" class="tab-item"
:class="activeTab === tab.id ? 'tab-selected' : 'not-selected'" @click="onTab(tab.id)">
<text class="tab-text">{{tab.label}}</text>
</view>
</view>
<view class="flex-col group">
<text class="text"></text>
<view class="flex-col group_7">
<view class="flex-col">
<!-- <text class="text_1">手机号</text> -->
<!-- @input="changeInput($event)" -->
<!-- <u-input type="number" v-model="userName" placeholder="请输入手机号" class="view text-wrapper" /> -->
<u-input type="number" v-model="userName" placeholder="请输入手机号" class="view text-wrapper" maxlength="11"/>
</view>
<view class="error-tips" v-if="errorPhone"><image class="error-img" src="/static/common/img/infoCircle.png"></image> 请输入正确手机号</view>
<view style="height: 0;width: 0;border: 0;padding: 0;margin: 0;overflow: hidden;">
<u-input placeholder='' />
</view>
<view class="flex-col group_6">
<!-- <text class="text_1">密码</text> -->
<u-input type="password" v-model="passWord" placeholder="请输入密码" class="view text-wrapper" />
</view>
<!-- 密码必须包含字母数字特殊字符且不能包含中文 -->
<view class="error-tips" v-if="errorPwd"><image class="error-img" src="/static/common/img/infoCircle.png"></image> {{errormsg}}</view>
</view>
<navigator class="text_6" style="width: 100%; text-align: right;" url="/pages/login/ForgetPassword/ForgetPassword">忘记密码</navigator>
<u-button class="flex-col items-center text-wrapper_1" throttle-time='1000' type="primary" shape="circle"
@click="login"><text class="text_7">登录</text></u-button>
<view class="justify-center group_1">
<text class="text_8">还没有账号</text>
<navigator class="text_9" url="/pages/login/register/register">立即注册</navigator>
</view>
<!-- <view class="flex-row group_2">
<u-checkbox-group class="section_1" :size='34'>
<u-checkbox v-model="agreement"> </u-checkbox>
</u-checkbox-group>
<view class="group_3">
<text class="text_10">已阅读并同意</text>
<text class="text_11">用户服务协议</text>
<text class="text_12"></text>
<text class="text_13">用户隐私保护政策</text>
</view>
</view> -->
</view>
</view>
<u-top-tips ref="uTips" :navbar-height='0'></u-top-tips>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
toBaiduApi
} from '@/utils/faceVerify.js'
import {
aesEncrypt
} from '@/utils/encrypt.js'
export default {
data() {
return {
show: false,
userName: "",
passWord: "",
agreement: true,
tabList: [{
id: 1,
label: '密码登录'
},
{
id: 2,
label: '验证码登录'
}
],
activeTab: 1,
errorPhone: false,
errorPwd: false,
errormsg: "",
};
},
onLoad(e) {},
onHide(){
this.userName= ""
this.passWord= ""
},
onShow() {
this.userName= ""
this.passWord= ""
setTimeout(() => {
const lifeData = uni.getStorageSync('lifeData');
if (lifeData.vuex_user && lifeData.vuex_token) {
this.$u.api.getUser().then(res => {
// if(!this.vuex_user.isCard){
// uni.navigateTo({
// url: '/pages/Face/index/index'
// });
// return
// }
uni.switchTab({
url: '../../main/index/index'
});
})
}
}, 200)
},
methods: {
changeInput(e){
setTimeout(() => {
this.userName = e.target.value
}, 0);
},
onTab(id) {
if(id == 1){
this.activeTab = id
}else{
/* uni.showToast({
title: '暂未开放',
icon: 'none'
}) */
this.$refs.uToast.show({
title: '暂未开放',
type: "warning",
});
}
},
login() {
// this.$u.vuex("vuex_msgList", '');
// this.$u.vuex('vuex_user', '')
// this.$u.vuex('vuex_token', '')
// uni.clearStorage();
if (!/^1[3-9]\d{9}$/.test(this.userName)) {
//
this.errorPhone = true;
// return this.$tips("", "error");
return;
} else {
this.errorPhone = false;
}
// 1q2w3e
// if (!/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&.])[A-Za-z\d@$!%*?&.]{5,}$/.test(this.passWord)) {
/* if (this.passWord.length < 6) {
// 6
this.errorPwd = true;
// return this.$tips("", "error");
return;
} else {
this.errorPwd = false;
} */
/* if (!this.agreement) {
return this.$tips("请同意用户服务协议及用户隐私保护政策", "error");
} */
if (this.passWord.length===0) {
this.errorPwd = true;
this.errormsg = "请输入密码";
console.log("请输入密码");
return
}else if (this.passWord.length>0&&this.passWord.length < 6) {
this.errorPwd = true;
this.errormsg = "密码长度不能少于6位";
console.log("密码长度不能少于6位");
return
}else{
this.errorPwd = false;
this.errormsg = "";
}
uni.showLoading({
title: "登录中",
});
//
let data = {
phone: this.userName,
password: aesEncrypt(this.passWord),
}
this.$u.api.LoginApp(data).then((res) => {
uni.hideLoading();
if (!res.succeed && !res.token) {
/* uni.showToast({
title: res.error,
duration: 2000,
icon: 'none'
}); */
// this.$tips(res.error, "error");
this.$refs.uToast.show({
title: err.error,
type: "error",
});
return
}
// this.$tips("", "success")
this.$refs.uToast.show({
title: "登录成功",
type: "success",
});
/* uni.showToast({
title: "登录成功",
duration: 2000,
}); */
//
this.$u.vuex('vuex_user', res.user)
this.$u.vuex('vuex_token', res.token)
this.$u.vuex('vuex_glyType', res.glyType)
// if(!res.user.isCard){
// uni.navigateTo({
// url: '/pages/Face/index/index'
// });
// return
// }
if (res.user.isFill) {
uni.switchTab({
url: '/pages/home/home/home'
});
} else {
// uni.navigateTo({
// // url: "../perfect/perfect",
// url: "../roleSelection",
// });
//
toBaiduApi(this);
return
//
uni.navigateTo({
url: "/pages/login/roleSelection?source=login",
});
}
}).catch(err => {
// this.$tips(err.error, "error");
this.$refs.uToast.show({
title: err.error,
type: "error",
});
/* uni.showToast({
title: err.error,
icon: 'none'
}) */
})
},
},
};
</script>
<style scoped lang="scss">
.page {
padding-bottom: 30rpx;
background-color: rgb(255, 255, 255);
overflow-y: auto;
width: 100%;
overflow-x: hidden;
height: 100%;
background: url(/static/common/img/loginBg.png);
background-size: contain;
background-repeat: no-repeat;
background-position: top;
.img-box {
height: 420rpx;
}
.image {
flex-shrink: 0;
align-self: flex-start;
width: 102%;
}
.group {
background: #fff;
padding: 20rpx 25rpx;
width: calc(100% - 50rpx);
margin: 0 auto;
border-radius: 30rpx;
.text {
align-self: center;
color: rgb(46, 155, 255);
font-size: 32rpx;
font-family: PingFang;
line-height: 32rpx;
}
.group_7 {
margin-top: 40rpx;
.text-wrapper {
border: solid 2rpx #dcdfe6;
border-radius: 100rpx;
background: #f6f8fa;
}
.group_6 {
margin-top: 30rpx;
}
.text_1 {
margin-left: 10rpx;
align-self: flex-start;
color: rgb(51, 51, 51);
font-size: 32rpx;
font-family: PingFang;
line-height: 30rpx;
}
.view {
margin-top: 20rpx;
padding: 20rpx 50rpx !important;
}
}
.text_6 {
margin-left: 5rpx;
margin-top: 50rpx;
align-self: flex-start;
// color: rgb(25, 140, 255);
color:#1F2232;
font-size: 28rpx;
font-family: PingFang;
line-height: 28rpx;
}
.text-wrapper_1 {
margin: 50rpx 0rpx 40rpx;
padding: 50rpx 0 50rpx;
// background-image: linear-gradient(90deg, rgb(135, 230, 254) 0%, rgb(91, 192, 254) 52%, rgb(46, 155, 255) 100%);
background: #3cb4fb;
box-shadow: 0px 6rpx 9rpx rgba(38, 122, 199, 0.34);
border-radius: 100rpx;
.text_7 {
color: rgb(255, 255, 255);
font-size: 32rpx;
font-family: PingFang;
line-height: 30rpx;
}
}
.group_1 {
margin-top: 24rpx;
.text_8 {
color: #8697AC;
font-size: 30rpx;
font-family: PingFang;
line-height: 26rpx;
}
.text_9 {
margin-left: 0.035rem;
color: #2E9CFE;
font-size: 30rpx;
font-family: PingFang;
line-height: 26rpx;
}
}
.group_2 {
margin-top: 40rpx;
justify-content: center;
.section_1 {
flex-shrink: 0;
width: 34rpx;
}
.group_3 {
margin-left: 24rpx;
height: 24rpx;
font-size: 0;
.text_10 {
color: rgb(153, 153, 153);
font-size: 24rpx;
font-family: PingFang;
}
.text_11 {
color: rgb(25, 140, 255);
font-size: 24rpx;
font-family: PingFang;
}
.text_12 {
color: rgb(102, 102, 102);
font-size: 24rpx;
font-family: PingFang;
}
.text_13 {
color: rgb(25, 140, 255);
font-size: 24rpx;
font-family: PingFang;
}
}
}
}
}
.login-box{
background: #fff;
width: calc(100% - 50rpx);
margin: 0 auto;
border-radius: 30rpx;
// height: calc(100% - 350rpx);
overflow: hidden;
padding-bottom:100rpx;
}
$tab-height: 52px;
$active-color: #fff;
$default-color: #90ecf1;
$primary-color: #666;
.tab-list {
display: flex;
position: relative;
z-index: 2;
border-radius: 30rpx 30rpx 0 0;
background-color: $default-color;
overflow: hidden; //
.tab-item {
flex: 1;
height: $tab-height;
display: flex;
justify-content: center;
align-items: center;
font-size: 30rpx;
// opacity: 0.65; //
font-weight: 600;
position: relative;
}
.tab-selected {
color:#3cb5fb;
opacity: 1;
background: #ffffff;
border-radius: 24rpx 24rpx 0 0;
box-shadow: 48rpx 80rpx 0 $active-color, -34rpx 90rpx 0 0 $active-color; //
.tab-text::after{
content: '';
position: absolute;
left: 160rpx;
bottom: 10rpx;
width: 32rpx;
height: 8rpx;
background: #3CB5FB;
border-radius: 20rpx;
}
}
.tab-selected::before {
content: '';
position: absolute;
left: -12rpx;
bottom: 0;
width: 24rpx;
height: $tab-height;
border-top-left-radius: 48rpx;
background-color: $active-color;
transform: skewX(-15deg); //
}
.tab-selected::after {
content: '';
position: absolute;
right: -12rpx;
bottom: 0;
width: 24rpx;
height: $tab-height;
border-top-right-radius: 24rpx;
background-color: $active-color;
transform: skewX(15deg); //
}
.not-selected {
color: $primary-color;
}
.not-selected::before {
content: '';
position: absolute;
left: 12rpx;
bottom: 0;
width: 24rpx;
height: $tab-height;
background: $default-color;
border-bottom-left-radius: 24rpx;
transform: skewX(15deg); //
}
.not-selected::after {
content: '';
position: absolute;
right: 12rpx;
bottom: 0;
width: 24rpx;
height: $tab-height;
background: $default-color;
border-bottom-right-radius: 24rpx;
transform: skewX(-15deg); //
z-index: -1;
}
}
.error-tips{
font-size: 24rpx;
color: #EF3920;
display: flex;
text-align: center;
margin-top: 10rpx;
// padding-left: 30rpx;
.error-img{
width: 32rpx;
height: 32rpx;
margin-right: 5rpx;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More