├── .gitignore ├── AppScope ├── app.json5 └── resources │ └── base │ ├── element │ └── string.json │ └── media │ └── app_icon.png ├── README.md ├── build-profile.json5 ├── entry ├── .gitignore ├── build-profile.json5 ├── hvigorfile.ts ├── oh-package-lock.json5 ├── oh-package.json5 └── src │ ├── main │ ├── ets │ │ ├── api │ │ │ └── index.ts │ │ ├── common │ │ │ ├── config.ts │ │ │ ├── constant.ts │ │ │ └── enum.ts │ │ ├── components │ │ │ ├── AvaterComponent.ets │ │ │ ├── BottomDialogComponent.ets │ │ │ ├── CategoryComponent.ets │ │ │ ├── CommentComponent.ets │ │ │ ├── GlobalLoading.ets │ │ │ ├── HomeComponent.ets │ │ │ ├── MovieComponent.ets │ │ │ ├── MovieListComponent.ets │ │ │ ├── MyComponent.ets │ │ │ ├── NavigatorTitleComponent.ets │ │ │ ├── OptionDialogComponent.ets │ │ │ ├── SearchComponent.ets │ │ │ ├── SwiperComponent.ets │ │ │ ├── TVComponent.ets │ │ │ └── TitleComponent.ets │ │ ├── controller │ │ │ ├── CommentController.ets │ │ │ └── LoadingController.ets │ │ ├── entryability │ │ │ └── EntryAbility.ts │ │ ├── interface │ │ │ └── Index.ts │ │ ├── pages │ │ │ ├── ForgetPasswordPage.ets │ │ │ ├── IndexPage.ets │ │ │ ├── LaunchPage.ets │ │ │ ├── LoginPage.ets │ │ │ ├── MovieDetailPage.ets │ │ │ ├── MoviePlayPage.ets │ │ │ ├── MovieSearchPage.ets │ │ │ ├── MovieUserPage.ets │ │ │ ├── RegisterPage.ets │ │ │ ├── ResetPasswordPage.ets │ │ │ ├── UpdatePasswordPage.ets │ │ │ └── UserPage.ets │ │ ├── service │ │ │ └── Index.ets │ │ ├── theme │ │ │ ├── color.ts │ │ │ └── size.ts │ │ └── utils │ │ │ ├── HttpUtil.ets │ │ │ ├── Lyric.ts │ │ │ ├── PreferenceModel.ets │ │ │ └── common.ets │ ├── module.json5 │ └── resources │ │ ├── base │ │ ├── element │ │ │ ├── color.json │ │ │ └── string.json │ │ ├── media │ │ │ ├── default_avater.png │ │ │ ├── default_cover.jpg │ │ │ ├── icon.png │ │ │ ├── icon_add.png │ │ │ ├── icon_app.png │ │ │ ├── icon_arrow.png │ │ │ ├── icon_avater.png │ │ │ ├── icon_back.png │ │ │ ├── icon_classify.png │ │ │ ├── icon_clear.png │ │ │ ├── icon_close.png │ │ │ ├── icon_collection.png │ │ │ ├── icon_collection_active.png │ │ │ ├── icon_comment.png │ │ │ ├── icon_comment_white.png │ │ │ ├── icon_delete.png │ │ │ ├── icon_detail_play.png │ │ │ ├── icon_down.png │ │ │ ├── icon_edit.png │ │ │ ├── icon_empty_star.png │ │ │ ├── icon_favorite.png │ │ │ ├── icon_full_star.png │ │ │ ├── icon_half_star.png │ │ │ ├── icon_history.png │ │ │ ├── icon_home.png │ │ │ ├── icon_home_active.png │ │ │ ├── icon_hot.png │ │ │ ├── icon_like.png │ │ │ ├── icon_like_active.png │ │ │ ├── icon_like_white.png │ │ │ ├── icon_logo.png │ │ │ ├── icon_menu_add.png │ │ │ ├── icon_menu_board.png │ │ │ ├── icon_menu_collect.png │ │ │ ├── icon_menu_history.png │ │ │ ├── icon_menu_like.png │ │ │ ├── icon_movie.png │ │ │ ├── icon_movie_active.png │ │ │ ├── icon_music.png │ │ │ ├── icon_music_add.png │ │ │ ├── icon_music_circle.png │ │ │ ├── icon_music_circle_active.png │ │ │ ├── icon_music_classics.png │ │ │ ├── icon_music_classify.png │ │ │ ├── icon_music_collect.png │ │ │ ├── icon_music_comments.png │ │ │ ├── icon_music_default_cover.png │ │ │ ├── icon_music_down.png │ │ │ ├── icon_music_like.png │ │ │ ├── icon_music_loop.png │ │ │ ├── icon_music_menu.png │ │ │ ├── icon_music_next.png │ │ │ ├── icon_music_order.png │ │ │ ├── icon_music_play.png │ │ │ ├── icon_music_play_menu.png │ │ │ ├── icon_music_play_white.png │ │ │ ├── icon_music_playing.png │ │ │ ├── icon_music_playing_grey.png │ │ │ ├── icon_music_prev.png │ │ │ ├── icon_music_random.png │ │ │ ├── icon_music_rank.png │ │ │ ├── icon_music_singer.png │ │ │ ├── icon_music_white_menu.png │ │ │ ├── icon_no1.png │ │ │ ├── icon_no2.png │ │ │ ├── icon_no3.png │ │ │ ├── icon_password.png │ │ │ ├── icon_permission.png │ │ │ ├── icon_play.png │ │ │ ├── icon_play_record.png │ │ │ ├── icon_recomment.png │ │ │ ├── icon_recomment_active.png │ │ │ ├── icon_record.png │ │ │ ├── icon_search.png │ │ │ ├── icon_share.png │ │ │ ├── icon_share_music.png │ │ │ ├── icon_song_default.png │ │ │ ├── icon_talk.png │ │ │ ├── icon_top.png │ │ │ ├── icon_tv.png │ │ │ ├── icon_tv_active.png │ │ │ ├── icon_user.png │ │ │ └── icon_user_active.png │ │ └── profile │ │ │ └── main_pages.json │ │ ├── en_US │ │ └── element │ │ │ └── string.json │ │ └── zh_CN │ │ └── element │ │ └── string.json │ └── ohosTest │ ├── ets │ ├── TestAbility │ │ ├── TestAbility.ets │ │ └── pages │ │ │ └── index.ets │ ├── TestRunner │ │ └── OpenHarmonyTestRunner.ts │ └── test │ │ ├── Ability.test.ets │ │ └── List.test.ets │ ├── module.json5 │ └── resources │ └── base │ ├── element │ ├── color.json │ └── string.json │ ├── media │ └── icon.png │ └── profile │ └── test_pages.json ├── hvigor ├── hvigor-config.json5 └── hvigor-wrapper.js ├── hvigorfile.ts ├── hvigorw ├── hvigorw.bat ├── oh-package-lock.json5 ├── oh-package.json5 ├── 一键提交到gitee.bat ├── 一键提交到github.bat ├── 外网映射正常访问提示.png ├── 实际效果预览.png ├── 新版电影APP整体预览图.jpg ├── 更改用户信息1.png ├── 更改用户信息2.png ├── 更改用户信息3.png ├── 更改用户信息4.png ├── 用户信息.png ├── 电影app整体预览.jpg ├── 电影app整体预览2.jpg ├── 电影预览1.png ├── 电影预览10.png ├── 电影预览11.png ├── 电影预览13.jpg ├── 电影预览14.jpg ├── 电影预览16.png ├── 电影预览2.png ├── 电影预览3.png ├── 电影预览4.png ├── 电影预览6.png ├── 电影预览7.png ├── 电影预览8.png └── 登录.png /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /local.properties 4 | /.idea 5 | **/build 6 | /.hvigor 7 | .cxx 8 | /.clangd 9 | /.clang-format 10 | /.clang-tidy 11 | **/.test -------------------------------------------------------------------------------- /AppScope/app.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "bundleName": "com.huawei.myapplication", 4 | "vendor": "example", 5 | "versionCode": 1000000, 6 | "versionName": "1.0.0", 7 | "icon": "$media:app_icon", 8 | "label": "$string:app_name" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AppScope/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "app_name", 5 | "value": "MyApplication" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /AppScope/resources/base/media/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/AppScope/resources/base/media/app_icon.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # harmony-movie-music-app-ui 2 | 3 | 开发者:吴怨吴悔 4 | 5 | =============================界面预览(如果无法预览,请查看项目根目录png文件)========================== 6 | 7 | ![app首页](./新版电影APP整体预览图.jpg) 8 | ![app首页](登录.png) 9 | ![app首页](用户信息.png) 10 | ![app首页](更改用户信息1.png) 11 | ![app首页](更改用户信息2.png) 12 | ![app首页](更改用户信息3.png) 13 | ![app首页](更改用户信息4.png) 14 | ![app首页](电影预览1.png) 15 | ![app首页](电影预览2.png) 16 | ![app首页](电影预览3.png) 17 | ![app首页](电影预览4.png) 18 | ![app首页](电影预览6.png) 19 | ![app首页](电影预览7.png) 20 | ![app首页](电影预览8.png) 21 | ![app首页](电影预览10.png) 22 | ![app首页](电影预览11.png) 23 | ![app首页](电影预览13.jpg) 24 | ![app首页](电影预览14.jpg) 25 | ![app首页](电影预览16.png) 26 | 27 | =============================界面预览(如果无法预览,请查看项目根目录png文件)========================== 28 | 29 | 使用arkts api9搭建的电影项目,有flutter、react-native、java、微信小程序、uniapp多个版本 30 | 31 | 电影数据来自于python爬虫程序,爬取第三方电影和音乐网站数据 32 | 33 | 34 | 后端接口项目和sql语句: 35 | https://github.com/wuyuanwuhui99/springboot-app-service 36 | https://gitee.com/wuyuanwuhui99/springboot-app-service 37 | 38 | 39 | flutter电影项目参见: 40 | github地址:https://github.com/wuyuanwuhui99/flutter-movie-app-ui 41 | gitee地址:https://hub.nuaa.cf/wuyuanwuhui99/flutter-movie-app-ui 42 | 43 | flutter音乐项目参见: 44 | github地址:https://github.com/wuyuanwuhui99/flutter-music-app-ui 45 | gitee地址:https://hub.nuaa.cf/wuyuanwuhui99/flutter-music-app-ui 46 | 47 | react native电影参见: 48 | github地址:https://github.com/wuyuanwuhui99/react-native-app-ui 49 | 50 | java安卓原生电影参见: 51 | 通用地址:https://github.com/wuyuanwuhui99/android-java-movie-app-ui 52 | gitee地址:https://hub.nuaa.cf/wuyuanwuhui99/android-java-movie-app-ui 53 | 54 | uniapp电影参见: 55 | github地址:https://github.com/wuyuanwuhui99/uniapp-vite-vue3-ts-movie-app-ui 56 | gitee地址:https://gitee/wuyuanwuhui99/uniapp-vite-vue3-ts-movie-app-ui 57 | 58 | uniapp音乐项目参见: 59 | github地址:https://github.com/wuyuanwuhui99/uniapp-vite-vue3-ts-music-app-ui 60 | gitee地址:https://gitee/wuyuanwuhui99/uniapp-vite-vue3-ts-music-app-ui 61 | 62 | 微信小程序版本参见: 63 | 通用地址:https://github.com/wuyuanwuhui99/weixin-movie-app-ui、 64 | 国内镜像地址:https://hub.nuaa.cf/wuyuanwuhui99/weixin-movie-app-ui 65 | 66 | harmony鸿蒙电影参见: 67 | github地址:https://github.com/wuyuanwuhui99/Harmony_movie_app_ui 68 | gitee地址:https://hub.nuaa.cf/wuyuanwuhui99/Harmony_movie_app_ui 69 | 70 | harmony鸿蒙音乐项目参见: 71 | github地址:https://github.com/wuyuanwuhui99/harmony_music_app_ui 72 | gitee地址:https://hub.nuaa.cf/wuyuanwuhui99/harmony_music_app_ui 73 | 74 | vue在线音乐项目: 75 | 通用地址:https://github.com/wuyuanwuhui99/vue-music-app-ui 76 | 国内镜像地址:https://hub.nuaa.cf/wuyuanwuhui99/vue-music-app-ui 77 | 78 | 在线音乐后端项目: 79 | 通用地址:https://github.com/wuyuanwuhui99/koa2-music-app-service 80 | 国内镜像地址:https://hub.nuaa.cf/wuyuanwuhui99/koa2-music-app-service 81 | 82 | vue3+ts明日头条项目: 83 | 通用地址:https://github.com/wuyuanwuhui99/vue3-ts-toutiao-app-ui 84 | 国内镜像地址:https://hub.nuaa.cf/wuyuanwuhui99/vue3-ts-toutiao-app-ui 85 | 86 | 接口和数据请在本地电脑中,暂时没有购买和部署服务器,仅限本地调试,如有需要调试请联系本人启动外网映射 87 | 88 | 本地调试请把 http://192.168.0.5:5001 改成 http://254a2y1767.qicp.vip 89 | 该地址是映射到本人电脑的地址,需要本人电脑开机才能访问,一般在工作日晚上八点半之后或者周末白天会开机 90 | 如需了解是否已开机,请用浏览器直接打开该地址:http://254a2y1767.qicp.vip,如出现以下提示,则正常使用 91 | ![外网映射正常访问提示](外网映射正常访问提示.png) 92 | 93 | 本站所有视频和图片均来自互联网收集而来,版权归原创者所有,本网站只提供web页面服务,并不提供资源存储,也不参与录制、上传 若本站收录的节目无意侵犯了贵司版权,请联系 94 | 95 | 联系方式:(微信)wuwenqiang_99、(邮箱)275018723@qq.com 96 | -------------------------------------------------------------------------------- /build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "app": { 3 | "signingConfigs": [], 4 | "compileSdkVersion": 9, 5 | "compatibleSdkVersion": 9, 6 | "products": [ 7 | { 8 | "name": "default", 9 | "signingConfig": "default", 10 | } 11 | ] 12 | }, 13 | "modules": [ 14 | { 15 | "name": "entry", 16 | "srcPath": "./entry", 17 | "targets": [ 18 | { 19 | "name": "default", 20 | "applyToProducts": [ 21 | "default" 22 | ] 23 | } 24 | ] 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /entry/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /oh_modules 3 | /.preview 4 | /build 5 | /.cxx 6 | /.test -------------------------------------------------------------------------------- /entry/build-profile.json5: -------------------------------------------------------------------------------- 1 | { 2 | "apiType": 'stageMode', 3 | "buildOption": { 4 | }, 5 | "targets": [ 6 | { 7 | "name": "default", 8 | "runtimeOS": "HarmonyOS" 9 | }, 10 | { 11 | "name": "ohosTest", 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /entry/hvigorfile.ts: -------------------------------------------------------------------------------- 1 | // Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. 2 | export { hapTasks } from '@ohos/hvigor-ohos-plugin'; 3 | -------------------------------------------------------------------------------- /entry/oh-package-lock.json5: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", 4 | "specifiers": { 5 | "@ohos/crypto-js@2.0.0": "@ohos/crypto-js@2.0.0" 6 | }, 7 | "packages": { 8 | "@ohos/crypto-js@2.0.0": { 9 | "resolved": "https://repo.harmonyos.com/ohpm/@ohos/crypto-js/-/crypto-js-2.0.0.har", 10 | "integrity": "sha512-SAPr0jdRS45kidxIqtSeBj4Eo7LMGSFRE+y8XxDNEDuqEvIA7Yv+2tEkFuFtcgxF7tATfHV16cazRC7/muocCQ==" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /entry/oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "entry", 3 | "version": "1.0.0", 4 | "description": "Please describe the basic information.", 5 | "main": "", 6 | "author": "", 7 | "license": "", 8 | "dependencies": { 9 | "@ohos/crypto-js": "2.0.0" 10 | }, 11 | "deviceConfig": { 12 | "default": { 13 | "network": { 14 | "cleartextTraffic": true 15 | } 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /entry/src/main/ets/api/index.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | login: '/service/user/login', //登录 3 | getUserData: '/service/user-getway/getUserData', // 获取用户信息 4 | updateUser: '/service/user-getway/updateUser',//更新用户信息 5 | register: '/service/user/register',//注册 6 | vertifyUser: '/service/user/vertifyUser',// 校验账号是否存在 7 | getBackPasswordByEmail: '/service/user/getBackPasswordByEmail',// 找回密码 8 | resetPassword: '/service/user/resetPassword',// 重置密码 9 | updateAvater:'/service/user-getway/updateAvater',//更新头像 10 | updatePassword: '/service/user-getway/updatePassword',//更新密码 11 | getCategoryList: '/service/movie/getCategoryList', //获取分类影片 12 | getKeyWord: '/service/movie/getKeyWord', //按照classify查询搜索栏的关键词 13 | getAllCategoryByClassify: '/service/movie/getAllCategoryByClassify', //按classify大类查询所有catory小类 14 | getAllCategoryListByPageName: '/service/movie/getAllCategoryListByPageName', //按页面获取要展示的category小类 15 | getUserMsg: '/service/movie-getway/getUserMsg', //获取用户四个指标信息,使用天数,关注,观看记录,浏览记录 16 | getSearchResult: '/service/movie/search', //搜索 17 | getStar: '/service/movie/getStar/', //获取演员 18 | getMovieUrl: '/service/movie/getMovieUrl', //获取演员 19 | getViewRecord: '/service/movie-getway/getViewRecord', //获取浏览记录 20 | saveViewRecord: '/service/movie-getway/saveViewRecord', //浏览历史 21 | getPlayRecord: '/service/movie-getway/getPlayRecord', //获取观看记录 22 | savePlayRecord: '/service/movie-getway/savePlayRecord', //播放记录 23 | getFavorite: '/service/movie-getway/getFavorite', //获取收藏电影 24 | saveFavorite: '/service/movie-getway/saveFavorite', //添加收藏 25 | deleteFavorite: '/service/movie-getway/deleteFavorite', //删除收藏 26 | getYourLikes: '/service/movie/getYourLikes',//猜你想看 27 | getRecommend: '/service/movie/getRecommend',//获取推荐 28 | isFavorite: '/service/movie-getway/isFavorite',//查询是否已经收藏 29 | getCommentCount:'/service/social/getCommentCount',//获取评论总数 30 | getTopCommentList:'/service/social/getTopCommentList',//获取一级评论 31 | getReplyCommentList:'/service/social/getReplyCommentList',//获取一级评论 32 | insertComment:'/service/social-getway/insertComment',//新增评论 33 | } -------------------------------------------------------------------------------- /entry/src/main/ets/common/config.ts: -------------------------------------------------------------------------------- 1 | export const LIKE_INNER_EVENT = {// 点赞和取消点赞事件派发和监听 2 | eventId: 1 3 | } 4 | 5 | export const PermissionMap = {// 权限映射 6 | 0: '私密', 7 | 1: '公开' 8 | } 9 | 10 | export const PermissionValueMap = {// 权限映射 11 | '私密': 0, 12 | '公开': 1 13 | } -------------------------------------------------------------------------------- /entry/src/main/ets/common/constant.ts: -------------------------------------------------------------------------------- 1 | // export const HOST:string = 'http://254a2y1767.qicp.vip';// 外网映射地址,一般只有晚上才开机,开机之后才能使用,如需调试请联系 2 | export const HOST: string = 'http://169.254.174.23:5001'; // 内网地址 3 | export const USER_DATA: string = 'USER_DATA';//用户信息 4 | export const DEVICE_INFO: string = 'DEVICE_INFO';// 设备信息 5 | export const MUSIC_PLAYER: string = 'MUSIC_PLAYER';// 音乐播放器 6 | export const MUSIC_MODEL: string = 'MUSIC_MODEL';// 音乐实例对象 7 | export const MUSIC_STORAGE: string = 'MUSIC_STORAGE';// 音乐仓库 8 | export const MUSIC_SEARCH: string = 'MUSIC_SEARCH';// 音乐搜查 9 | export const FAVORITE_MUSIC: string = 'FAVORITE_MUSIC';// 收藏音乐 10 | export const PAGE_SIZE:number = 20;// 收藏音乐 11 | export const MAX_PAGE_SIZE:number = 500;// 每页最大数量 -------------------------------------------------------------------------------- /entry/src/main/ets/common/enum.ts: -------------------------------------------------------------------------------- 1 | export const enum SocialEnum { // 社交类型 2 | MUSIC = "MUSIC", 3 | MUSIC_CIRCLE = "MUSIC_CIRCLE", 4 | MOVIE = "MOVIE", 5 | MOVIE_CIRCLE = "MOVIE_CIRCLE" 6 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/AvaterComponent.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import { UserDataInterface } from '../interface/Index' 3 | import { HOST,USER_DATA } from '../common/constant'; 4 | 5 | @Component 6 | export default struct AvaterComponent { 7 | @StorageLink(USER_DATA) userData: UserDataInterface = null; 8 | @Prop dimensions: number; 9 | 10 | build() { 11 | Image(this.userData?.avater ? HOST + this.userData.avater : $r('app.media.default_avater')) 12 | .height(this.dimensions) 13 | .width(this.dimensions) 14 | .borderRadius(this.dimensions).onClick(() => { 15 | router.pushUrl({ 16 | url: 'pages/MovieUserPage', // 目标url 17 | }, router.RouterMode.Standard, (err) => { 18 | if (err) { 19 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 20 | } 21 | }); 22 | }) 23 | } 24 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/BottomDialogComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | 4 | @CustomDialog 5 | export default struct BottomDialogComponent { 6 | @Prop dialogHeight: string; 7 | @BuilderParam builder : () => void; 8 | // 使用父组件@Builder装饰的方法初始化子组件@BuilderParam 9 | controller: CustomDialogController 10 | 11 | // 弹窗中的内容描述 12 | build() { 13 | Column(){ 14 | this.builder() 15 | } 16 | .borderRadius({topLeft:size.blockBorderRaduis,topRight:size.blockBorderRaduis}) 17 | .height(this.dialogHeight) 18 | .width('100%') 19 | .backgroundColor(colors.blockColor) 20 | } 21 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/CategoryComponent.ets: -------------------------------------------------------------------------------- 1 | import TitleComponent from './TitleComponent'; 2 | import * as colors from '../theme/color'; 3 | import * as size from '../theme/size'; 4 | import { ClassifyInterface,MovieInterface } from '../interface/Index'; 5 | import {getCategoryListService} from '../service/Index'; 6 | import MovieListComponent from './MovieListComponent'; 7 | @Component 8 | export default struct CategoryComponent{ 9 | @Prop classifyItemStr:string;// Prop不能传递object对象 10 | @State classifyItem:ClassifyInterface = null; 11 | @State movieList:Array = []; 12 | 13 | aboutToAppear(){ 14 | // 把字符串转成对象 15 | this.classifyItem = JSON.parse(this.classifyItemStr) as ClassifyInterface; 16 | this.useCategoryList(); 17 | } 18 | 19 | useCategoryList(){ 20 | getCategoryListService(this.classifyItem).then((res)=>{ 21 | this.movieList = res.data; 22 | }) 23 | } 24 | 25 | build(){ 26 | Column(){ 27 | TitleComponent({title:this.classifyItem.category,showMarginBottom:true}) 28 | if(this.movieList.length > 0){// 必须加判断,否则后更新的数据不会触发MovieListComponent组件重新渲染 29 | MovieListComponent({gravity:'horizontal',movieList:$movieList}) 30 | } 31 | }.backgroundColor(colors.blockColor) 32 | .borderRadius(size.blockBorderRaduis) 33 | .padding(size.pagePadding) 34 | .width('100%') 35 | .margin({top:size.pagePadding}) 36 | } 37 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/CommentComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { getTopCommentListService, insertCommentService } from '../service/Index'; 4 | import { HOST } from '../common/constant'; 5 | import { CommentInterface } from '../interface/Index'; 6 | import { formatTime } from '../utils/common'; 7 | import BottomDialogComponent from './BottomDialogComponent'; 8 | import CommentController from '../controller/CommentController'; 9 | 10 | // 传入buildCommentList方法必须是一个对象形式,否则无法实现响应式 11 | interface CommentParamsInterface { 12 | commentList: Array 13 | } 14 | 15 | @Component 16 | export default struct CommentComponent { 17 | @Prop relationId: number; 18 | @Prop commentListStr: string; // 评论数组字符串 19 | @Prop type: string; 20 | @State commentTotal: number = 0; 21 | @State commentList: Array = []; 22 | @State text: string = ''; // 评论框文字 23 | @State firstComment: CommentInterface = null; 24 | @State replyComment: CommentInterface = null; 25 | @State replyIndex: number = -1; 26 | @State focusableInput: boolean = false; 27 | private loading: boolean = false; 28 | private scroller: Scroller = new Scroller() 29 | private dialogController: CustomDialogController; 30 | public controller: CommentController = null; 31 | 32 | aboutToAppear() { 33 | if (this.controller) { 34 | this.controller.attach(this); //绑定控制器 35 | } 36 | /** 37 | * @author: wuwenqiang 38 | * @description: 获取评论列表 39 | * @date: 2024-05-25 21:36 40 | */ 41 | if (this.commentListStr) { 42 | this.commentList = JSON.parse(this.commentListStr) as Array; 43 | } else { 44 | getTopCommentListService(this.relationId, this.type, 1, 20).then(res => { 45 | this.commentList = res.data; 46 | this.commentTotal = res.total; 47 | }); 48 | } 49 | } 50 | 51 | /** 52 | * @author: wuwenqiang 53 | * @description: 打开评论框弹窗 54 | * @date: 2024-05-26 14:26 55 | */ 56 | openInputDialog(): void { 57 | if (!this.dialogController) { 58 | this.dialogController = new CustomDialogController({ 59 | customStyle: true, 60 | builder: BottomDialogComponent({ 61 | dialogHeight: 'auto', 62 | builder: this.buildCommentInput.bind(this) 63 | }), 64 | alignment: DialogAlignment.Bottom, 65 | }) 66 | } 67 | this.dialogController.open() 68 | } 69 | 70 | /** 71 | * @author: wuwenqiang 72 | * @description: 创建评论框 73 | * @date: 2024-05-26 14:26 74 | */ 75 | @Builder buildCommentInput() { 76 | Column() { 77 | Row() { 78 | TextInput({ 79 | text: this.text, 80 | placeholder: this.replyComment ? `回复${this.replyComment.username}` : (this.firstComment ? `回复${this.firstComment.username}` : '评论') 81 | }).defaultFocus(true) 82 | .layoutWeight(1) 83 | .focusable(this.focusableInput) 84 | .height(size.inputHeight) 85 | .onChange((value) => { 86 | this.text = value; 87 | }) 88 | .onClick(() => { 89 | this.focusableInput = true 90 | }) 91 | Button('发送', { type: ButtonType.Capsule, stateEffect: true }) 92 | .backgroundColor(colors.lineBackgroundColor) 93 | .width(size.btnWidth) 94 | .enabled(Boolean(this.text)) 95 | .height(size.inputHeight) 96 | .margin({ left: size.pagePadding }) 97 | .onClick(() => { 98 | if (this.loading) return; 99 | this.loading = true; 100 | const commentItem: CommentInterface = { 101 | id: 0, //主键 102 | content: this.text, //评论内容 103 | parentId: this.replyComment?.id, //父节点id 104 | topId: this.firstComment?.id, //顶级节点id 105 | type: this.type, // 类型 106 | relationId: this.relationId, //影片id 107 | createTime: "", //创建时间 108 | updateTime: "", //更新时间 109 | replyCount: 0, //回复数量 110 | userId: "", //用户id 111 | username: "", //用户名 112 | avater: "", //用户头像 113 | replyUserId: "", //被回复者id 114 | replyUserName: "", //被回复者名称 115 | showCommentCount: "", //显示的回复数量 116 | replyPageNum: 0, 117 | replyList: [] 118 | } 119 | // 发送评论 120 | insertCommentService(commentItem).then((res) => { 121 | if (this.firstComment) { // 二级评论,相当于回复 122 | // 必须重新解构,然后再赋值,否则添加回复不生效 123 | const commentItem = { ...this.commentList[this.replyIndex] }; 124 | commentItem.replyList === null && (commentItem.replyList = []); 125 | commentItem.replyList.push(res.data); // 添加回复列表 126 | this.commentList.splice(this.replyIndex, 1, commentItem); // 替换掉原数据里面的那一条数据 127 | } else { // 一级评论 128 | this.commentList.push(res.data); 129 | } 130 | // 重新赋值,改变对象的内存地址,否则添加回复不生效 131 | this.dialogController?.close(); 132 | this.replyComment = this.firstComment = null; 133 | this.text = ''; 134 | this.focusableInput = false; 135 | }).finally(() => { 136 | this.loading = false; 137 | }); 138 | }) 139 | }.backgroundColor(colors.blockColor).padding(size.pagePadding) 140 | } 141 | .width('100%') 142 | } 143 | 144 | /** 145 | * @author: wuwenqiang 146 | * @description: 点击弹出评论框 147 | * @date: 2024-05-26 14:26 148 | */ 149 | useReply(item: CommentInterface, index: number) { 150 | if (this.commentListStr) { 151 | this.openInputDialog(); 152 | } 153 | this.focusableInput = true; 154 | this.replyIndex = index; 155 | if (item.topId) { 156 | this.replyComment = item; // 二级评论,即回复的内容 157 | this.firstComment = this.commentList.find(aItem => aItem.id === item.topId) 158 | } else { 159 | this.replyComment = this.firstComment = item; // 点击的是一级评论 160 | } 161 | } 162 | 163 | /** 164 | * @author: wuwenqiang 165 | * @description: 创建评论列表,参数必须用对象或者接口形式传递,否则参数变化了,视图不更新 166 | * @date: 2024-05-25 16:30 167 | */ 168 | @Builder buildCommentList(commentParams: CommentParamsInterface) { 169 | Column({ space: size.pagePadding }) { 170 | ForEach(commentParams.commentList, (aItem: CommentInterface, aIndex: number) => { 171 | Row() { 172 | Image(aItem.avater ? HOST + aItem.avater : $r('app.media.default_avater')) 173 | .width(aItem.topId ? size.smallAvaterSize : size.middleAvaterSize) 174 | .height(aItem.topId ? size.smallAvaterSize : size.middleAvaterSize) 175 | .borderRadius(aItem.topId ? size.smallAvaterSize : size.middleAvaterSize) 176 | Column() { 177 | Text(aItem.topId ? `${aItem.username}▶${aItem.replyUserName}` : aItem.username) 178 | .fontColor(colors.disableTextColor).margin({ bottom: size.miniPadding }) 179 | Text(aItem.content).margin({ bottom: size.miniPadding }) 180 | Text(formatTime(aItem.createTime)).fontColor(colors.disableTextColor) 181 | if (aItem.replyList?.length > 0) { 182 | Blank().height(size.pagePadding) 183 | // 参数必须用对象或者接口形式传递,否则参数变化了,视图不更新 184 | this.buildCommentList({ commentList: aItem.replyList }) 185 | } 186 | }.layoutWeight(1) 187 | .alignItems(HorizontalAlign.Start) 188 | .margin({ left: size.pagePadding }) 189 | .onClick(this.useReply.bind(this, aItem, aIndex)) 190 | } 191 | .justifyContent(FlexAlign.Start) 192 | .alignItems(VerticalAlign.Top) 193 | .width('100%') 194 | }) 195 | } 196 | } 197 | 198 | build() { 199 | if(this.commentListStr){ 200 | Column(){ 201 | if(this.commentList.length > 0){ 202 | Blank().height(size.pagePadding) 203 | } 204 | this.buildCommentList({ commentList: this.commentList }) 205 | } 206 | }else{ 207 | Column() { 208 | Text(`${this.commentTotal}条评论`) 209 | .padding(size.pagePadding) 210 | .textAlign(TextAlign.Center) 211 | .border({ 212 | width: { bottom: 1 }, 213 | color: { bottom: colors.borderColor }, 214 | style: { bottom: BorderStyle.Solid } 215 | }).width('100%') 216 | 217 | Scroll(this.scroller) { 218 | if (this.commentList.length > 0) { 219 | // 必须用对象的方式传递,否则this.commentList发生变化之后,视图不会更新 220 | this.buildCommentList({ commentList: this.commentList }) 221 | } else{ 222 | Text('暂无评论') 223 | .width('100%') 224 | .height('100%') 225 | .textAlign(TextAlign.Center) 226 | .alignSelf(ItemAlign.Center) 227 | } 228 | } 229 | .scrollable(ScrollDirection.Vertical) 230 | .layoutWeight(1) 231 | .align(Alignment.Top) 232 | .padding(size.pagePadding) 233 | 234 | if (!this.commentListStr) { 235 | Divider().height(1).color(colors.borderColor) 236 | this.buildCommentInput() 237 | } 238 | }.width('100%').height('100%') 239 | } 240 | } 241 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/GlobalLoading.ets: -------------------------------------------------------------------------------- 1 | // 自定义Loading组件 2 | import * as colors from '../theme/color'; 3 | import LoadingController from '../controller/LoadingController'; 4 | @Component 5 | export default struct GlobalLoading { 6 | @State private message: string = '加载中...' 7 | @State private isShow: boolean = false 8 | public controller: LoadingController = null; 9 | 10 | aboutToAppear(){ 11 | if (this.controller) { 12 | this.controller.attach(this); //绑定控制器 13 | } 14 | } 15 | 16 | 17 | // 显示/隐藏方法 18 | public showLoading(message?: string) { 19 | this.isShow = true 20 | if (message) this.message = message 21 | } 22 | 23 | public hideLoading() { 24 | this.isShow = false 25 | } 26 | 27 | build() { 28 | Stack({ alignContent: Alignment.Center }) { 29 | if (this.isShow) { 30 | // 半透明遮罩层 31 | Column() { 32 | LoadingProgress() 33 | .width(80) 34 | .height(80) 35 | .color(colors.disableTextColor) // 修改动画颜色[5]() 36 | Text(this.message) 37 | .margin({ top: 20 }) 38 | } 39 | .justifyContent(FlexAlign.Center) 40 | .alignItems(HorizontalAlign.Center) 41 | .backgroundColor(0x00FFFFFF) 42 | .width('100%') 43 | .height('100%') 44 | .zIndex(999) 45 | } 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/HomeComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { ClassifyInterface } from '../interface/Index' 4 | import SwiperComponent from './SwiperComponent'; 5 | import { getAllCategoryListByPageNameService } from '../service/Index'; 6 | import CategoryComponent from './CategoryComponent'; 7 | import SearchComponent from './SearchComponent'; 8 | 9 | @Entry 10 | @Component 11 | export default struct HomeComponent { 12 | @State allCategoryList: Array = []; 13 | @State currentCategoryList: Array = []; 14 | @State isScrollEnd: boolean = false; 15 | private scroller: Scroller = new Scroller() 16 | 17 | @Styles blockStyle(){ 18 | .backgroundColor(colors.blockColor) 19 | .borderRadius(size.blockBorderRaduis) 20 | .padding(size.pagePadding) 21 | .width('100%') 22 | .margin({ top: size.pagePadding }) 23 | } 24 | 25 | @Styles classifyItemStyle(){ 26 | .width(size.bigIconSize) 27 | .height(size.bigIconSize) 28 | .margin({ bottom: size.smallPadding }) 29 | } 30 | 31 | aboutToAppear() { 32 | this.useAllCategoryListByPageName() 33 | } 34 | 35 | useAllCategoryListByPageName() { 36 | getAllCategoryListByPageNameService('首页').then((res) => { 37 | this.allCategoryList = res.data; 38 | this.currentCategoryList = this.allCategoryList.slice(0, 2) 39 | }) 40 | } 41 | 42 | build() { 43 | Column() { 44 | Scroll(this.scroller) { 45 | Column() { 46 | SearchComponent({ classify: '电影' }) 47 | SwiperComponent({ classify: '电影' }).margin({ top: size.pagePadding }) 48 | Row() { 49 | Column() { 50 | Image($r('app.media.icon_hot')).classifyItemStyle() 51 | Text('热门').fontSize(size.normalFontSize) 52 | } 53 | .flexGrow(1) 54 | .justifyContent(FlexAlign.Center) 55 | .alignItems(HorizontalAlign.Center) 56 | 57 | Column() { 58 | Image($r('app.media.icon_play')).classifyItemStyle() 59 | Text('预告').fontSize(size.normalFontSize) 60 | } 61 | .flexGrow(1) 62 | .justifyContent(FlexAlign.Center) 63 | .alignItems(HorizontalAlign.Center) 64 | 65 | Column() { 66 | Image($r('app.media.icon_top')).classifyItemStyle() 67 | Text('最新').fontSize(size.normalFontSize) 68 | } 69 | .flexGrow(1) 70 | .justifyContent(FlexAlign.Center) 71 | .alignItems(HorizontalAlign.Center) 72 | 73 | Column() { 74 | Image($r('app.media.icon_classify')).classifyItemStyle() 75 | Text('分类').fontSize(size.normalFontSize) 76 | } 77 | .flexGrow(1) 78 | .justifyContent(FlexAlign.Center) 79 | .alignItems(HorizontalAlign.Center) 80 | }.blockStyle() 81 | 82 | ForEach(this.currentCategoryList, (item: ClassifyInterface) => { 83 | CategoryComponent({ classifyItemStr: JSON.stringify(item) }) 84 | }) 85 | Row() { 86 | Text(this.isScrollEnd ? '已经到底了...' : '正在加载更多...') 87 | }.padding({ top: size.pagePadding,bottom:size.pagePadding }) 88 | } 89 | } 90 | .scrollable(ScrollDirection.Vertical) 91 | .onScrollEdge((side: Edge) => { 92 | if (!this.isScrollEnd) { 93 | const length: number = this.currentCategoryList.length 94 | this.currentCategoryList.push(...this.allCategoryList.slice(length, length + 2)) 95 | if (this.currentCategoryList.length === this.allCategoryList.length) { 96 | this.isScrollEnd = true 97 | } 98 | } 99 | }) // 滚动方向纵向 100 | } 101 | .width('100%') 102 | .height('100%') 103 | .backgroundColor(colors.pageBackgroundColor) 104 | .padding({ left: size.pagePadding, right: size.pagePadding,}) 105 | } 106 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/MovieComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { ClassifyInterface } from '../interface/Index' 4 | import SwiperComponent from './SwiperComponent'; 5 | import { getAllCategoryListByPageNameService } from '../service/Index'; 6 | import CategoryComponent from './CategoryComponent'; 7 | import SearchComponent from './SearchComponent'; 8 | 9 | @Entry 10 | @Component 11 | export default struct MovieComponent{ 12 | @State allCategoryList: Array = []; 13 | @State currentCategoryList: Array = []; 14 | @State isScrollEnd: boolean = false; 15 | scroller: Scroller = new Scroller() 16 | 17 | aboutToAppear() { 18 | this.useAllCategoryListByPageName() 19 | } 20 | 21 | useAllCategoryListByPageName() { 22 | getAllCategoryListByPageNameService('电影').then((res) => { 23 | this.allCategoryList = res.data; 24 | this.currentCategoryList = this.allCategoryList.slice(0, 2) 25 | }) 26 | } 27 | 28 | build() { 29 | Column() { 30 | Scroll(this.scroller) { 31 | Column(){ 32 | SearchComponent({ classify: '电影' }) 33 | SwiperComponent({ classify: '电影' }).margin({ top: size.pagePadding }) 34 | ForEach(this.currentCategoryList, (item: ClassifyInterface) => { 35 | CategoryComponent({ classifyItemStr: JSON.stringify(item) }) 36 | }) 37 | Row() { 38 | Text(this.isScrollEnd ? '已经到底了...' : '正在加载更多...') 39 | }.padding({ top: size.pagePadding,bottom:size.pagePadding }) 40 | } 41 | }.scrollable(ScrollDirection.Vertical) 42 | .onScrollEdge((side: Edge) => { 43 | if (!this.isScrollEnd) { 44 | const length: number = this.currentCategoryList.length 45 | this.currentCategoryList.push(...this.allCategoryList.slice(length, length + 2)) 46 | if (this.currentCategoryList.length === this.allCategoryList.length) { 47 | this.isScrollEnd = true 48 | } 49 | } 50 | }) 51 | } 52 | .width('100%') 53 | .height('100%') 54 | .backgroundColor(colors.pageBackgroundColor) 55 | .padding({ left: size.pagePadding, right: size.pagePadding,}) 56 | } 57 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/MovieListComponent.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import { HOST } from '../common/constant'; 3 | import { MovieInterface } from '../interface' 4 | import * as size from '../theme/size'; 5 | 6 | @Component 7 | export default struct MovieListComponent { 8 | @Prop gravity: string; // 排列方向,vertical | horizontal 9 | @Link movieList: Array; 10 | @State movieListGroup: Array> = []; 11 | 12 | aboutToAppear(){ 13 | this.movieList.forEach((item,index)=>{ 14 | if(index % 3 === 0){ 15 | this.movieListGroup.push([item]) 16 | }else{ 17 | this.movieListGroup[this.movieListGroup.length - 1].push(item); 18 | } 19 | }) 20 | } 21 | 22 | build() { 23 | if (this.gravity === 'horizontal') { 24 | Scroll() { 25 | Row() { 26 | ForEach(this.movieList, (item: MovieInterface, index: number) => { 27 | MovieItemComponent({ movieItemStr: JSON.stringify(item),gravity:'horizontal' }) 28 | }) 29 | } 30 | }.width('100%').scrollable(this.gravity === 'horizontal' ? ScrollDirection.Horizontal : ScrollDirection.Vertical) 31 | } else { 32 | Grid() { 33 | ForEach(this.movieList, (item: MovieInterface, index: number) => { 34 | GridItem() { 35 | MovieItemComponent({ movieItemStr: JSON.stringify(item),gravity:'vertical' }) 36 | } 37 | }) 38 | }.columnsTemplate('1fr 1fr 1fr') 39 | .height('100%') 40 | .columnsGap(size.pagePadding) 41 | .rowsGap(size.pagePadding) 42 | .scrollBar(BarState.Off) 43 | } 44 | } 45 | } 46 | 47 | @Component 48 | struct MovieItemComponent { 49 | @Prop movieItemStr: string; 50 | @State movieItem: MovieInterface = null; 51 | @Prop gravity: string; // 排列方向,vertical | horizontal 52 | 53 | aboutToAppear() { 54 | this.movieItem = JSON.parse(this.movieItemStr) as MovieInterface; 55 | } 56 | 57 | build() { 58 | Column() { 59 | Image(HOST + this.movieItem.localImg) 60 | .width(this.gravity === 'horizontal' ? size.movieWidth: '100%') 61 | .height(this.gravity === 'horizontal' ? size.movieHeight: 'auto') 62 | .borderRadius(size.blockBorderRaduis) 63 | .margin({ bottom: size.smallPadding }) 64 | Text(this.movieItem.movieName) 65 | .maxLines(1) 66 | .textAlign(TextAlign.Center) 67 | .width(this.gravity === 'horizontal' ? size.movieWidth: '100%') 68 | .textOverflow({overflow: TextOverflow.Ellipsis}) 69 | .fontSize(size.normalFontSize) 70 | } 71 | .margin({ right: size.smallPadding }) 72 | .alignItems(HorizontalAlign.Center) 73 | .width(this.gravity === 'horizontal' ? size.movieWidth: '100%') 74 | .onClick(() => { 75 | router.pushUrl({ 76 | url: 'pages/MovieDetailPage', // 目标url 77 | params: { 78 | movieItem: this.movieItem 79 | } 80 | }, router.RouterMode.Standard, (err) => { 81 | if (err) { 82 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 83 | } 84 | }); 85 | }) 86 | } 87 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/MyComponent.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import * as colors from '../theme/color'; 3 | import * as size from '../theme/size'; 4 | import AvaterComponent from './AvaterComponent'; 5 | import { UserDataInterface, UserMsgInterface, MovieInterface } from '../interface/Index'; 6 | import { USER_DATA, HOST} from '../common/constant'; 7 | import { 8 | getUserMsgService, 9 | getPlayRecordMovieListService, 10 | getMyViewsMovieListService, 11 | getMyFavoriteMovieListService 12 | } from '../service/Index' 13 | 14 | @Entry 15 | @Component 16 | export default struct MyComponent { 17 | scroller: Scroller = new Scroller() 18 | @State bigAvaterSize: number = size.bigAvaterSize; 19 | @State userMsg: UserMsgInterface = null; 20 | @StorageLink(USER_DATA) userData: UserDataInterface = null; 21 | @State showPlayRecordMovieList: boolean = true; // 展示我的观看记录 22 | @State playRecordMovieList: Array = []; // 观看记录列表 23 | 24 | @State showMyFavoriteList: boolean = false; // 显示我的收藏列表 25 | @State myFavoriteList: Array = []; // 我的收藏列表 26 | 27 | @State showMyViewList: boolean = false; // 显示我浏览过的电影 28 | @State myViewList: Array = []; // 显示我浏览过的电影 29 | 30 | @State loading: boolean = false; 31 | 32 | @Styles blockStyle(){ 33 | .backgroundColor(colors.blockColor) 34 | .borderRadius(size.blockBorderRaduis) 35 | .padding(size.pagePadding) 36 | .width('100%') 37 | .margin({ top: size.pagePadding }) 38 | } 39 | 40 | @Styles classifyIconStyle(){ 41 | .width(size.middlIconSize) 42 | .height(size.middlIconSize) 43 | .margin({ right: size.smallPadding }) 44 | } 45 | 46 | @Styles arrowIconStyle(){ 47 | .width(size.smallIconSize) 48 | .height(size.smallIconSize) 49 | } 50 | 51 | aboutToAppear() { 52 | this.useUserMsgService() 53 | this.usePlayRecord() 54 | } 55 | 56 | /** 57 | * @description: 获取用户使用天数、访问记录数量等 58 | * @date: 2023-12-10 10:20 59 | * @author wuwenqiang 60 | */ 61 | useUserMsgService() { 62 | getUserMsgService().then(res => { 63 | this.userMsg = res.data 64 | }) 65 | } 66 | 67 | /** 68 | * @description: 获取用户观看记录 69 | * @date: 2023-12-13 21:47 70 | * @author wuwenqiang 71 | */ 72 | usePlayRecord() { 73 | getPlayRecordMovieListService(1,20).then(res => { 74 | this.playRecordMovieList = res.data; 75 | }) 76 | } 77 | 78 | build() { 79 | Column() { 80 | Scroll(this.scroller) { 81 | Column() { 82 | Row() { 83 | AvaterComponent({ dimensions: this.bigAvaterSize }) 84 | Column() { 85 | Text(this.userData?.username || '') 86 | .fontSize(size.bigFontSize) 87 | .fontWeight(FontWeight.Bolder) 88 | .margin({ bottom: size.smallPadding }) 89 | Text(this.userData?.sign || '').fontColor(colors.disableTextColor) 90 | } 91 | .alignItems(HorizontalAlign.Start) 92 | .margin({ left: size.pagePadding }) 93 | .layoutWeight(1) 94 | Image($r('app.media.icon_edit')) 95 | .height(size.bigIconSize) 96 | .width(size.bigIconSize) 97 | .onClick(() => router.pushUrl({ url: 'pages/MovieUserPage'})) 98 | }.blockStyle().width('100%').align(Alignment.Center) 99 | 100 | Row() { 101 | Column() { 102 | Text(this.userMsg?.userAge.toString()).fontSize(size.bigFontSize).fontWeight(FontWeight.Bolder) 103 | Text('使用天数').fontColor(colors.disableTextColor).margin({ top: size.smallPadding }) 104 | }.flexGrow(1) 105 | 106 | Column() { 107 | Text(this.userMsg?.favoriteCount.toString()).fontSize(size.bigFontSize).fontWeight(FontWeight.Bolder) 108 | Text('收藏').fontColor(colors.disableTextColor).margin({ top: size.smallPadding }) 109 | }.flexGrow(1) 110 | 111 | Column() { 112 | Text(this.userMsg?.playRecordCount.toString()).fontSize(size.bigFontSize).fontWeight(FontWeight.Bolder) 113 | Text('观看记录').fontColor(colors.disableTextColor).margin({ top: size.smallPadding }) 114 | }.flexGrow(1) 115 | 116 | Column() { 117 | Text(this.userMsg?.viewRecordCount.toString()).fontSize(size.bigFontSize).fontWeight(FontWeight.Bolder) 118 | Text('浏览记录').fontColor(colors.disableTextColor).margin({ top: size.smallPadding }) 119 | }.flexGrow(1) 120 | }.blockStyle() 121 | 122 | Column() { 123 | Row() { 124 | Image($r('app.media.icon_play_record')).classifyIconStyle() 125 | Text('观看记录').flexGrow(1) 126 | Image($r('app.media.icon_arrow')) 127 | .arrowIconStyle() 128 | .opacity(size.opacity) 129 | .rotate({ angle: this.showPlayRecordMovieList ? 90 : 0 }) 130 | } 131 | .margin({ 132 | bottom: this.playRecordMovieList?.length > 0 ? size.pagePadding : 0 133 | }) 134 | .width('100%') 135 | .onClick(() => { 136 | this.showPlayRecordMovieList = !this.showPlayRecordMovieList; 137 | if (this.showPlayRecordMovieList) { 138 | getMyViewsMovieListService(1, 20).then(res => this.playRecordMovieList = res.data) 139 | } 140 | }) 141 | 142 | if (this.playRecordMovieList?.length > 0) { 143 | Scroll() { 144 | Row() { 145 | ForEach(this.playRecordMovieList, (item: MovieInterface) => { 146 | Column() { 147 | Image(HOST + item.localImg) 148 | .width(size.movieWidth) 149 | .height(size.movieHeight) 150 | .borderRadius(size.blockBorderRaduis) 151 | .margin({ bottom: size.smallPadding }) 152 | Text(item.movieName).fontSize(size.normalFontSize) 153 | } 154 | .margin({ right: size.smallPadding }) 155 | .alignItems(HorizontalAlign.Center) 156 | .width(size.movieWidth) 157 | }) 158 | } 159 | }.width('100%').scrollable(ScrollDirection.Horizontal) 160 | } 161 | }.blockStyle().alignItems(HorizontalAlign.Start) 162 | 163 | Column() { 164 | Row() { 165 | Image($r('app.media.icon_collection')).classifyIconStyle() 166 | Text('我的收藏').flexGrow(1) 167 | Image($r('app.media.icon_arrow')) 168 | .opacity(size.opacity) 169 | .arrowIconStyle() 170 | .rotate({ angle: this.showMyFavoriteList ? 90 : 0 }) 171 | }.width('100%') 172 | .onClick(() => { 173 | this.showMyFavoriteList = !this.showMyFavoriteList; 174 | if (this.showMyFavoriteList) { 175 | getMyFavoriteMovieListService(1, 20).then(res => this.myFavoriteList = res.data) 176 | } 177 | }) 178 | 179 | if (this.showMyFavoriteList && !this.loading && this.myFavoriteList.length > 0) { 180 | Scroll() { 181 | Row() { 182 | ForEach(this.myFavoriteList, (item: MovieInterface) => { 183 | Column() { 184 | Image(HOST + item.localImg) 185 | .width(size.movieWidth) 186 | .height(size.movieHeight) 187 | .borderRadius(size.blockBorderRaduis) 188 | .margin({ bottom: size.smallPadding }) 189 | Text(item.movieName).fontSize(size.normalFontSize) 190 | } 191 | .margin({ right: size.smallPadding }) 192 | .alignItems(HorizontalAlign.Center) 193 | .width(size.movieWidth) 194 | }) 195 | } 196 | }.width('100%').scrollable(ScrollDirection.Horizontal) 197 | } 198 | }.blockStyle().alignItems(HorizontalAlign.Start) 199 | 200 | Column() { 201 | Row() { 202 | Image($r('app.media.icon_record')).classifyIconStyle() 203 | Text('我浏览过的电影').flexGrow(1) 204 | Image($r('app.media.icon_arrow')).opacity(size.opacity).arrowIconStyle().rotate({ 205 | angle: this.showMyViewList ? 90 : 0 206 | }) 207 | }.width('100%') 208 | .onClick(() => { 209 | this.showMyViewList = !this.showMyViewList; 210 | if (this.showMyViewList) { 211 | getMyViewsMovieListService(1, 20).then(res => this.myViewList = res.data) 212 | } 213 | }) 214 | 215 | if (this.showMyViewList && !this.loading && this.myViewList.length > 0) { 216 | Scroll() { 217 | Row() { 218 | ForEach(this.myViewList, (item: MovieInterface) => { 219 | Column() { 220 | Image(HOST + item.localImg) 221 | .width(size.movieWidth) 222 | .height(size.movieHeight) 223 | .borderRadius(size.blockBorderRaduis) 224 | .margin({ bottom: size.smallPadding }) 225 | Text(item.movieName).fontSize(size.normalFontSize) 226 | } 227 | .margin({ right: size.smallPadding }) 228 | .alignItems(HorizontalAlign.Center) 229 | .width(size.movieWidth) 230 | }) 231 | } 232 | }.width('100%').scrollable(ScrollDirection.Horizontal) 233 | } 234 | }.blockStyle().alignItems(HorizontalAlign.Start) 235 | 236 | Column({space:size.pagePadding}) { 237 | 238 | Row() { 239 | Image($r('app.media.icon_music_circle')).classifyIconStyle() 240 | Text('电影圈').flexGrow(1) 241 | Image($r('app.media.icon_arrow')).opacity(size.opacity).arrowIconStyle() 242 | }.width('100%') 243 | 244 | Divider().height(1).color(colors.borderColor) 245 | 246 | Row() { 247 | Image($r('app.media.icon_app')).classifyIconStyle() 248 | Text('小程序').flexGrow(1) 249 | Image($r('app.media.icon_arrow')).opacity(size.opacity).arrowIconStyle() 250 | }.width('100%') 251 | }.blockStyle().margin({top:size.pagePadding,bottom:size.pagePadding}).alignItems(HorizontalAlign.Start) 252 | } 253 | }.scrollable(ScrollDirection.Vertical) 254 | } 255 | .width('100%') 256 | .height('100%') 257 | .backgroundColor(colors.pageBackgroundColor) 258 | .padding({ left: size.pagePadding, right: size.pagePadding,}) 259 | } 260 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/NavigatorTitleComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import router from '@ohos.router'; 4 | 5 | @Component 6 | export default struct NavigatorTitleComponent { 7 | @Prop title: string; 8 | 9 | build() { 10 | Row(){ 11 | Image($r('app.media.icon_back')) 12 | .width(size.smallIconSize) 13 | .height(size.smallIconSize) 14 | .opacity(size.opacity) 15 | .onClick(()=>{ 16 | router.back() 17 | }) 18 | Text(this.title) 19 | .layoutWeight(1) 20 | .textAlign(TextAlign.Center) 21 | Image($r('app.media.icon_back')) 22 | .width(size.smallIconSize) 23 | .height(size.smallIconSize) 24 | .visibility(Visibility.Hidden) 25 | } 26 | .width('100%') 27 | .padding(size.pagePadding) 28 | .backgroundColor(colors.blockColor) 29 | } 30 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/OptionDialogComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | 4 | /** 5 | * @description: 修改新别弹窗 6 | * @date: 2024-01-14 21:47 7 | * @author wuwenqiang 8 | */ 9 | @CustomDialog 10 | export default struct OptionDialogComponent { 11 | controller: CustomDialogController 12 | cancel: () => void 13 | confirm: (value: string) => void 14 | options: Array 15 | 16 | build() { 17 | Column() { 18 | Column() { 19 | ForEach(this.options, (item: string, index: number) => { 20 | Text(item) 21 | .textAlign(TextAlign.Center) 22 | .width('100%') 23 | .padding(size.pagePadding) 24 | .backgroundColor(colors.blockColor) 25 | .borderRadius(size.blockBorderRaduis) 26 | .onClick(() => { 27 | this.confirm(item) 28 | }) 29 | if (index !== this.options.length - 1) { 30 | Divider() 31 | .height(1) 32 | .backgroundColor(colors.pageBackgroundColor) 33 | } 34 | }) 35 | }.backgroundColor(colors.blockColor) 36 | .borderRadius(size.blockBorderRaduis) 37 | .padding({ left: size.pagePadding, right: size.pagePadding }) 38 | 39 | Divider() 40 | .height(size.pagePadding) 41 | .backgroundColor(Color.Transparent) 42 | Text('取消') 43 | .textAlign(TextAlign.Center) 44 | .width('100%') 45 | .padding(size.pagePadding) 46 | .backgroundColor(colors.blockColor) 47 | .borderRadius(size.blockBorderRaduis) 48 | .onClick(() => { 49 | this.cancel() 50 | }) 51 | Divider() 52 | .height(size.pagePadding) 53 | .backgroundColor(Color.Transparent) 54 | }.width('100%').backgroundColor(Color.Transparent).padding({ left: size.pagePadding, right: size.pagePadding }) 55 | } 56 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/SearchComponent.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import * as colors from '../theme/color'; 3 | import * as size from '../theme/size'; 4 | import { MovieInterface } from '../interface/Index'; 5 | import {getSearchKeyWordService} from '../service/Index'; 6 | import AvaterComponent from './AvaterComponent'; 7 | @Component 8 | export default struct SearchComponent{ 9 | 10 | @Styles blockStyle(){ 11 | .backgroundColor(colors.blockColor) 12 | .borderRadius(size.blockBorderRaduis) 13 | .padding(size.pagePadding) 14 | .width('100%') 15 | .margin({top:size.pagePadding}) 16 | } 17 | 18 | @State movieItem:MovieInterface = null 19 | @Prop classify:string; 20 | @State dimensions:number = size.middleAvaterSize;// 导入的值不能直接传给组件 21 | 22 | aboutToAppear(){ 23 | this.useSearchKeyWord() 24 | } 25 | 26 | useSearchKeyWord(){ 27 | getSearchKeyWordService(this.classify).then((res)=>{ 28 | this.movieItem = res.data; 29 | }) 30 | } 31 | 32 | build(){ 33 | Row(){ 34 | AvaterComponent({dimensions:this.dimensions}) 35 | Row(){ 36 | Text(this.movieItem?.movieName) 37 | .fontSize(size.normalFontSize) 38 | .fontColor(colors.disableTextColor) 39 | } 40 | .height(size.middleAvaterSize) 41 | .borderRadius(size.middleAvaterSize) 42 | .backgroundColor(colors.pageBackgroundColor) 43 | .margin({left: size.pagePadding}) 44 | .padding({left: size.pagePadding}) 45 | .flexGrow(1) 46 | .onClick(()=>{ 47 | router.pushUrl({ 48 | url: 'pages/MovieSearchPage', // 目标url 49 | params: { 50 | classify:this.classify, 51 | movieItem: this.movieItem 52 | } 53 | }, router.RouterMode.Standard, (err) => { 54 | if(err){ 55 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 56 | } 57 | }); 58 | }) 59 | }.blockStyle() 60 | } 61 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/SwiperComponent.ets: -------------------------------------------------------------------------------- 1 | import * as size from '../theme/size'; 2 | import { MovieInterface } from '../interface/Index'; 3 | import {getCategoryListService} from '../service/Index'; 4 | import {HOST} from '../common/constant'; 5 | 6 | @Component 7 | export default struct SwiperComponent{ 8 | @Prop classify:string; 9 | @State movieList:Array = [] 10 | 11 | private swiperController: SwiperController = new SwiperController() 12 | aboutToAppear(){ 13 | this.useCategoryList() 14 | } 15 | useCategoryList(){ 16 | getCategoryListService({classify:this.classify,category:'轮播'}).then((res)=>{ 17 | this.movieList = res.data.slice(0,5); 18 | }) 19 | } 20 | 21 | build() { 22 | if(this.movieList.length > 0){ 23 | Swiper(this.swiperController) { 24 | ForEach(this.movieList,(movieItem:MovieInterface)=>{ 25 | Image(HOST + movieItem.localImg) 26 | .height(size.swiperHeight) 27 | .width('100%') 28 | .borderRadius(size.blockBorderRaduis) 29 | }) 30 | } 31 | .loop(true) 32 | .autoPlay(true) 33 | .interval(5000) 34 | } 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/TVComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { ClassifyInterface } from '../interface/Index' 4 | import SwiperComponent from './SwiperComponent'; 5 | import { getAllCategoryListByPageNameService } from '../service/Index'; 6 | import CategoryComponent from './CategoryComponent'; 7 | import SearchComponent from './SearchComponent'; 8 | 9 | @Entry 10 | @Component 11 | export default struct TVComponent{ 12 | @State allCategoryList: Array = []; 13 | @State currentCategoryList: Array = []; 14 | @State isScrollEnd: boolean = false; 15 | scroller: Scroller = new Scroller() 16 | 17 | aboutToAppear() { 18 | this.useAllCategoryListByPageName() 19 | } 20 | 21 | useAllCategoryListByPageName() { 22 | getAllCategoryListByPageNameService('电视剧').then((res) => { 23 | this.allCategoryList = res.data; 24 | this.currentCategoryList = this.allCategoryList.slice(0, 2) 25 | }) 26 | } 27 | 28 | build() { 29 | Column() { 30 | Scroll(this.scroller) { 31 | Column(){ 32 | SearchComponent({ classify: '电视剧' }) 33 | SwiperComponent({ classify: '电视剧' }).margin({ top: size.pagePadding }) 34 | ForEach(this.currentCategoryList, (item: ClassifyInterface) => { 35 | CategoryComponent({ classifyItemStr: JSON.stringify(item) }) 36 | }) 37 | Row() { 38 | Text(this.isScrollEnd ? '已经到底了...' : '正在加载更多...') 39 | }.padding({ top: size.pagePadding,bottom:size.pagePadding }) 40 | } 41 | }.scrollable(ScrollDirection.Vertical) 42 | .onScrollEdge((side: Edge) => { 43 | if (!this.isScrollEnd) { 44 | const length: number = this.currentCategoryList.length 45 | this.currentCategoryList.push(...this.allCategoryList.slice(length, length + 2)) 46 | if (this.currentCategoryList.length === this.allCategoryList.length) { 47 | this.isScrollEnd = true 48 | } 49 | } 50 | }) 51 | } 52 | .width('100%') 53 | .height('100%') 54 | .backgroundColor(colors.pageBackgroundColor) 55 | .padding({ left: size.pagePadding, right: size.pagePadding,}) 56 | } 57 | } -------------------------------------------------------------------------------- /entry/src/main/ets/components/TitleComponent.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | 4 | 5 | @Component 6 | export default struct TitleComponent{ 7 | @Prop title:string; 8 | @Prop showMarginBottom:boolean; 9 | 10 | build(){ 11 | Row(){ 12 | Divider() 13 | .height(size.lineHeight) 14 | .width(size.lineWidth) 15 | .backgroundColor(colors.lineBackgroundColor) 16 | .margin({right:size.smallPadding}) 17 | Text(this.title).fontSize(size.normalFontSize) 18 | }.alignSelf(ItemAlign.Start) 19 | .margin({bottom:this.showMarginBottom ? size.pagePadding : 0}) 20 | } 21 | } -------------------------------------------------------------------------------- /entry/src/main/ets/controller/CommentController.ets: -------------------------------------------------------------------------------- 1 | import CommentComponent from '../components/CommentComponent'; 2 | 3 | export default class CommentController { 4 | private mComponent: CommentComponent = null; 5 | 6 | attach(component: CommentComponent) { 7 | this.mComponent = component; 8 | } 9 | 10 | public openInputDialog(): void { 11 | if (this.mComponent) { 12 | return this.mComponent.openInputDialog(); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /entry/src/main/ets/controller/LoadingController.ets: -------------------------------------------------------------------------------- 1 | import GlobalLoading from '../components/GlobalLoading'; 2 | 3 | export default class LoadingController { 4 | private mComponent: GlobalLoading = null; 5 | 6 | attach(component: GlobalLoading) { 7 | this.mComponent = component; 8 | } 9 | 10 | public showLoading(): void { 11 | if (this.mComponent) { 12 | return this.mComponent.showLoading(); 13 | } 14 | } 15 | 16 | public hideLoading(): void { 17 | if (this.mComponent) { 18 | return this.mComponent.hideLoading(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /entry/src/main/ets/entryability/EntryAbility.ts: -------------------------------------------------------------------------------- 1 | import UIAbility from '@ohos.app.ability.UIAbility'; 2 | import hilog from '@ohos.hilog'; 3 | import window from '@ohos.window'; 4 | 5 | export default class EntryAbility extends UIAbility { 6 | onCreate(want, launchParam) { 7 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); 8 | } 9 | 10 | onDestroy() { 11 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy'); 12 | } 13 | 14 | onWindowStageCreate(windowStage: window.WindowStage) { 15 | // Main window is created, set main page for this ability 16 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); 17 | 18 | windowStage.loadContent('pages/LaunchPage', (err, data) => { 19 | if (err.code) { 20 | hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 21 | return; 22 | } 23 | hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? ''); 24 | }); 25 | } 26 | 27 | onWindowStageDestroy() { 28 | // Main window is destroyed, release UI related resources 29 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); 30 | } 31 | 32 | onForeground() { 33 | // Ability has brought to foreground 34 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground'); 35 | } 36 | 37 | onBackground() { 38 | // Ability has back to background 39 | hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /entry/src/main/ets/interface/Index.ts: -------------------------------------------------------------------------------- 1 | export interface MyAwesomeData { 2 | data: T; 3 | token: string; 4 | status:string; 5 | msg:string; 6 | total:number 7 | } 8 | 9 | export interface DeviceInterface{ 10 | version:string, 11 | platform:string, 12 | device:string 13 | } 14 | 15 | export interface UserDataInterface { 16 | userAccount: string; 17 | createDate?: string; 18 | updateDate?: string; 19 | username: string; 20 | telephone: string; 21 | email: string; 22 | avater: string; 23 | birthday: string; 24 | sex: string; 25 | role: string; 26 | password: string; 27 | sign: string; 28 | region: string; 29 | disabled?: number; 30 | permission?: number; 31 | } 32 | 33 | export interface MovieInterface { 34 | description:string; 35 | classify: string; 36 | isRecommend: string; 37 | img: string; 38 | targetHref: string; 39 | updateTime: number; 40 | useStatus: string; 41 | sourceUrl: string; 42 | score: number; 43 | localImg: string; 44 | ranks: string; 45 | createTime: number; 46 | id: number; 47 | sourceName: string; 48 | category: string; 49 | movieName: string; 50 | star: string; 51 | plot: string; 52 | } 53 | 54 | export interface GlobalDataInterface{ 55 | userData: UserDataInterface; 56 | token: string 57 | } 58 | 59 | export interface ClassifyInterface{ 60 | classify: string; 61 | category: string 62 | } 63 | 64 | export interface UserMsgInterface{ 65 | userAge: number;// 使用天数 66 | favoriteCount: number;// 收藏数 67 | playRecordCount: number;// 观看记录 68 | viewRecordCount: number// 浏览记录 69 | } 70 | 71 | export interface StarInterface { 72 | id: number;//主键 73 | starName: string;//演员名称 74 | img: string;//演员图片地址 75 | localImg:string;//演员本地图片地址 76 | createTime:string;//创建时间 77 | updateTime:string;//更新时间 78 | movieId:string;//对应电影的id 79 | role: string;//角色 80 | href: string;//演员的豆瓣链接地址 81 | works: string ;//代表作 82 | } 83 | 84 | export interface MovieUrlInterface { 85 | id:number;//主键 86 | movieName:string;//电影名称 87 | movieId:number;//对应的电影的id 88 | href:string;//源地址 89 | label:string;//集数 90 | createTime:string;//创建时间 91 | updateTime:string;//更新时间 92 | url:string;//播放地址 93 | playGroup:string;//播放分组,1, 2 94 | } 95 | 96 | // 评论字段 97 | export interface CommentInterface { 98 | id:number,//主键 99 | content:string,//评论内容 100 | parentId:number,//父节点id 101 | type:string,// 类型 102 | topId:number,//顶级节点id 103 | relationId:number,//影片id 104 | createTime:string,//创建时间 105 | updateTime:string,//更新时间 106 | replyCount:number,//回复数量 107 | userId:string,//用户id 108 | username:string,//用户名 109 | avater:string,//用户头像 110 | replyUserId:string,//被回复者id 111 | replyUserName:string,//被回复者名称 112 | showCommentCount:string,//显示的回复数量 113 | replyPageNum:number,// 回复数量 114 | replyList:Array// 回复列表 115 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/ForgetPasswordPage.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { sendEmailVertifyCodeService } from '../service/Index'; 4 | import { UserDataInterface } from '../interface/Index'; 5 | import { USER_DATA } from '../common/constant'; 6 | import promptAction from '@ohos.promptAction' 7 | import display from '@ohos.display'; 8 | import NavigatorTitleComponent from '../components/NavigatorTitleComponent'; 9 | import prompt from '@system.prompt' 10 | import router from '@ohos.router'; 11 | import LoadingController from '../controller/LoadingController'; 12 | import GlobalLoading from '../components/GlobalLoading'; 13 | 14 | @Entry 15 | @Component 16 | struct LoginPage { 17 | @StorageLink(USER_DATA) userData: UserDataInterface = null; 18 | email: string = ''; 19 | loading:boolean = false; 20 | private loadingController:LoadingController = new LoadingController() 21 | 22 | @Styles blockStyle(){ 23 | .backgroundColor(colors.blockColor) 24 | .borderRadius(size.blockBorderRaduis) 25 | .padding(size.pagePadding) 26 | .width('100%') 27 | .margin({ top: size.pagePadding }) 28 | } 29 | 30 | @Styles rowStyle(){ 31 | .border({ 32 | width: { 33 | bottom: 1, 34 | }, 35 | color: { 36 | bottom: colors.pageBackgroundColor 37 | }, 38 | style: { 39 | bottom: BorderStyle.Solid 40 | } 41 | }) 42 | .width('100%') 43 | .padding({ top: size.pagePadding, bottom: size.pagePadding }) 44 | } 45 | 46 | useSumbit=()=>{ 47 | if(this.loading)return true; 48 | if (!this.email) { 49 | return promptAction.showToast({ 50 | message: "邮箱不能为空", 51 | duration: 2000, 52 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 53 | }) 54 | } else { 55 | this.loadingController.showLoading(); 56 | this.loading = true; 57 | sendEmailVertifyCodeService(this.email).then((res)=>{ 58 | promptAction.showToast({ 59 | message: res.msg, 60 | duration: 2000, 61 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 62 | }); 63 | router.pushUrl({ 64 | url: 'pages/ResetPasswordPage', // 目标url 65 | params: { 66 | email: this.email 67 | } 68 | }, router.RouterMode.Single, (err) => { 69 | if (err) { 70 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 71 | } 72 | }); 73 | }).finally(()=>{ 74 | this.loadingController.showLoading(); 75 | this.loading = false; 76 | }) 77 | } 78 | this.loading = true; 79 | } 80 | 81 | build() { 82 | Column(){ 83 | GlobalLoading({controller:this.loadingController}) 84 | Column() { 85 | NavigatorTitleComponent({ title: "忘记密码" }) 86 | Column() { 87 | Row() { 88 | Text("*").fontColor(colors.warnColor) 89 | TextInput({ placeholder: "请输入邮箱" }) 90 | .layoutWeight(1) 91 | .backgroundColor(Color.Transparent) 92 | .onChange((value) => { 93 | this.email = value; 94 | }) 95 | } 96 | .alignItems(VerticalAlign.Center) 97 | .blockStyle() 98 | 99 | Text('提交') 100 | .width('100%') 101 | .padding(size.pagePadding) 102 | .textAlign(TextAlign.Center) 103 | .backgroundColor(colors.warnColor) 104 | .margin({ top: size.pagePadding }) 105 | .fontColor(Color.White) 106 | .borderRadius(size.blockBorderRaduis * 2) 107 | .onClick(this.useSumbit) 108 | 109 | } 110 | .padding({left:size.pagePadding,right:size.pagePadding}) 111 | .backgroundColor(colors.pageBackgroundColor) 112 | } 113 | .width('100%') 114 | .height('100%') 115 | } 116 | .width('100%') 117 | .height('100%') 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/IndexPage.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import HomeComponent from '../components/HomeComponent' 4 | import MovieComponent from '../components/MovieComponent' 5 | import MyComponent from '../components/MyComponent' 6 | import TVComponent from '../components/TVComponent' 7 | 8 | @Entry 9 | @Component 10 | struct Index { 11 | @State activeIndex: number = 0; 12 | @State isInitPage: Array = [true, false, false, false]; 13 | 14 | build() { 15 | Column() { 16 | Tabs({ 17 | index: this.activeIndex, 18 | barPosition: BarPosition.End 19 | }) { 20 | TabContent() { 21 | HomeComponent() 22 | } 23 | .tabBar(this.tabBuilder(0, '首页', $r('app.media.icon_home_active'), $r('app.media.icon_home'))) 24 | 25 | TabContent() { 26 | if (this.isInitPage[1]) { 27 | MovieComponent() 28 | } else { 29 | Column() 30 | } 31 | } 32 | .tabBar(this.tabBuilder(1, '电影', $r('app.media.icon_movie_active'), $r('app.media.icon_movie'))) 33 | 34 | TabContent() { 35 | if (this.isInitPage[2]) { 36 | TVComponent() 37 | } else { 38 | Column() 39 | } 40 | } 41 | .tabBar(this.tabBuilder(2, '电视剧', $r('app.media.icon_tv_active'), $r('app.media.icon_tv'))) 42 | 43 | TabContent() { 44 | if (this.isInitPage[3]) { 45 | MyComponent() 46 | } else { 47 | Column() 48 | } 49 | } 50 | .tabBar(this.tabBuilder(3, '我的', $r('app.media.icon_user_active'), $r('app.media.icon_user'))) 51 | 52 | } 53 | .barHeight(size.barHeight) 54 | .barMode(BarMode.Fixed) 55 | .onChange((index) => { 56 | this.isInitPage[index] = true; 57 | this.activeIndex = index 58 | }) 59 | } 60 | .width('100%') 61 | .height('100%') 62 | } 63 | 64 | @Builder tabBuilder(index: number, title: string, selectedImage: Resource, normalImage: Resource) { 65 | Column() { 66 | Image(this.activeIndex == index ? selectedImage : normalImage) 67 | .width(size.middlIconSize) 68 | .height(size.middlIconSize) 69 | .margin({ top: size.smallPadding, bottom: size.smallPadding }) 70 | Text(title) 71 | .fontColor(this.activeIndex == index ? colors.tabSelectedColor : colors.tabNormalColor) 72 | .fontSize(size.normalFontSize) 73 | .padding({ bottom: size.pagePadding }) 74 | } 75 | .width('100%') 76 | .justifyContent(FlexAlign.Center) 77 | .border({ 78 | width: { top: 1 }, 79 | color: { top: colors.disableTextColor }, 80 | style: { top: BorderStyle.Solid } 81 | }) 82 | } 83 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/LaunchPage.ets: -------------------------------------------------------------------------------- 1 | import httpRequest from '../utils/HttpUtil'; 2 | import deviceInfo from '@ohos.deviceInfo'; //设备信息 3 | import { DeviceInterface, UserDataInterface } from '../interface/Index' 4 | import preference from '../utils/PreferenceModel'; 5 | import { DEVICE_INFO, USER_DATA } from '../common/constant'; 6 | import { getUserDataService } from '../service/Index'; 7 | import router from '@ohos.router'; 8 | 9 | @Preview 10 | @Entry 11 | @Component 12 | struct LaunchPage { 13 | @State activeIndex: number = 0; 14 | @State isInitPage: Array = [true, false, false, false]; 15 | @State isInitIndex: boolean = false; 16 | 17 | build() { 18 | Column() { 19 | Text('欢迎使用') 20 | } 21 | .justifyContent(FlexAlign.Center) 22 | .alignItems(HorizontalAlign.Center) 23 | .width('100%') 24 | .height('100%') 25 | } 26 | 27 | async aboutToAppear() { 28 | const {marketName,productModel,sdkApiVersion} = deviceInfo 29 | AppStorage.SetOrCreate(DEVICE_INFO, {device:productModel,platform:marketName,version:sdkApiVersion.toString()}) 30 | const token: string = await preference.getToken(); 31 | setTimeout(()=>{// 加载用户信息 32 | if(token){ 33 | getUserDataService(token).then((res) => { 34 | preference.setToke(res.token); 35 | httpRequest.setToken(res.token); 36 | AppStorage.SetOrCreate(USER_DATA, res.data) 37 | router.replaceUrl({ 38 | url: 'pages/IndexPage' 39 | }); 40 | }).catch(()=>{ 41 | router.replaceUrl({ 42 | url: 'pages/LoginPage' 43 | }); 44 | }) 45 | }else{ 46 | router.replaceUrl({ 47 | url: 'pages/LoginPage' 48 | }); 49 | } 50 | 51 | },1000) 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/MovieDetailPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import {MovieInterface,StarInterface} from "../interface"; 3 | import * as colors from '../theme/color'; 4 | import * as size from '../theme/size'; 5 | import {HOST} from '../common/constant'; 6 | import TitleComponent from '../components/TitleComponent'; 7 | import {getMovieStartListService,getRecommentListService,saveViewRecordService} from '../service/Index'; 8 | @Entry 9 | @Component 10 | struct MovieDetailPage { 11 | @State movieItem:MovieInterface = null;// 电影详情 12 | @State starList:Array = [];// 主演 13 | @State recommendMovieList:Array = [];// 推荐的电影 14 | 15 | @Styles blockStyle(){ 16 | .backgroundColor(colors.blockColor) 17 | .borderRadius(size.blockBorderRaduis) 18 | .padding(size.pagePadding) 19 | .width('100%') 20 | .margin({ top: size.pagePadding }) 21 | } 22 | 23 | aboutToAppear() { 24 | const params = router.getParams(); // 获取传递过来的参数对象 25 | this.movieItem = params['movieItem'] as MovieInterface; // 获取info属性的值 26 | getMovieStartListService(this.movieItem.id).then(res => this.starList = res.data);// 获取主演 27 | getRecommentListService(encodeURIComponent(this.movieItem.classify)).then(res => this.recommendMovieList = res.data);// 获取推荐的电影 28 | saveViewRecordService(this.movieItem);// 插入浏览记录 29 | } 30 | 31 | build() { 32 | Column(){ 33 | Scroll() { 34 | Column(){ 35 | Row(){ 36 | Row(){ 37 | Image($r('app.media.icon_detail_play')) 38 | .width(size.bigIconSize) 39 | .height(size.bigIconSize) 40 | } 41 | .borderRadius(size.blockBorderRaduis) 42 | .justifyContent(FlexAlign.Center) 43 | .alignItems(VerticalAlign.Center) 44 | .width(size.movieWidth) 45 | .height(size.movieHeight) 46 | .backgroundImage(HOST + this.movieItem.localImg,ImageRepeat.NoRepeat) 47 | .backgroundImageSize(ImageSize.Cover) 48 | .onClick((event:ClickEvent)=>{ 49 | router.pushUrl({ 50 | url: 'pages/MoviePlayPage', // 目标url 51 | params: { 52 | movieItem: this.movieItem 53 | } 54 | }, router.RouterMode.Standard, (err) => { 55 | if(err){ 56 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 57 | } 58 | }); 59 | }) 60 | Column(){ 61 | Text(this.movieItem.movieName) 62 | .padding({bottom:size.smallPadding}) 63 | .fontWeight(FontWeight.Bolder) 64 | .fontSize(size.bigFontSize) 65 | Text(this.movieItem.description?.replace(/\n|\s/g,'') || '') 66 | .padding({bottom:size.smallPadding}) 67 | .fontSize(size.normalFontSize) 68 | .fontColor(colors.disableTextColor) 69 | Text(this.movieItem.star) 70 | .padding({bottom:size.smallPadding}) 71 | .fontSize(size.normalFontSize) 72 | .fontColor(colors.disableTextColor) 73 | if(this.movieItem.score){ 74 | Row(){ 75 | Rating().stars(this.movieItem.score).stepSize(0.1) 76 | Text(this.movieItem.score.toString()) 77 | .padding({left:size.smallPadding}) 78 | .fontColor(Color.Red) 79 | .fontSize(size.normalFontSize) 80 | .fontWeight(FontWeight.Bolder) 81 | }.justifyContent(FlexAlign.Start).margin({top:size.smallPadding}) 82 | } 83 | }.flexGrow(1) 84 | .alignItems(HorizontalAlign.Start) 85 | .margin({left:size.pagePadding}) 86 | }.blockStyle() 87 | 88 | Column(){ 89 | TitleComponent({title:'剧情',showMarginBottom:true}) 90 | Text(this.movieItem.plot) 91 | .padding({top:size.smallPadding}) 92 | .fontSize(size.normalFontSize) 93 | .fontColor(colors.disableTextColor) 94 | }.justifyContent(FlexAlign.Start) 95 | .blockStyle() 96 | 97 | Column(){ 98 | TitleComponent({title:'演员',showMarginBottom:true}) 99 | Scroll(){ 100 | Row(){ 101 | ForEach(this.starList,(item:StarInterface)=>{ 102 | Column(){ 103 | Image(HOST + item.localImg) 104 | .width(size.movieWidth) 105 | .height(size.movieHeight) 106 | .borderRadius(size.blockBorderRaduis) 107 | .margin({bottom:size.smallPadding}) 108 | Text(item.starName).fontSize(size.normalFontSize) 109 | } 110 | .margin({right:size.smallPadding}) 111 | .alignItems(HorizontalAlign.Center) 112 | .width(size.movieWidth) 113 | }) 114 | } 115 | }.width('100%').scrollable(ScrollDirection.Horizontal) 116 | } 117 | .blockStyle() 118 | 119 | Column(){ 120 | TitleComponent({title:'推荐',showMarginBottom:true}) 121 | Scroll(){ 122 | Row(){ 123 | ForEach(this.recommendMovieList,(item:MovieInterface)=>{ 124 | Column(){ 125 | Image(HOST + item.localImg) 126 | .width(size.movieWidth) 127 | .height(size.movieHeight) 128 | .borderRadius(size.blockBorderRaduis) 129 | .margin({bottom:size.smallPadding}) 130 | Text(item.movieName).fontSize(size.normalFontSize) 131 | } 132 | .margin({right:size.smallPadding}) 133 | .alignItems(HorizontalAlign.Center) 134 | .width(size.movieWidth) 135 | }) 136 | } 137 | }.width('100%').scrollable(ScrollDirection.Horizontal) 138 | } 139 | .blockStyle() 140 | 141 | }.justifyContent(FlexAlign.Start) 142 | } 143 | }.width('100%') 144 | .height('100%') 145 | .padding({ left: size.pagePadding, right: size.pagePadding,bottom:size.pagePadding }) 146 | .justifyContent(FlexAlign.Start) 147 | .backgroundColor(colors.pageBackgroundColor) 148 | } 149 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/MoviePlayPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import web_webview from '@ohos.web.webview' 3 | import { MovieInterface, MovieUrlInterface } from "../interface"; 4 | import * as colors from '../theme/color'; 5 | import * as size from '../theme/size'; 6 | import { getMovieUrlService } from '../service/Index'; 7 | import { getCommentCountService, isFavoriteService, saveFavoriteService, deleteFavoriteService } from '../service/Index'; 8 | import { SocialEnum } from '../common/enum'; 9 | import BottomDialogComponent from '../components/BottomDialogComponent'; 10 | import CommentComponent from '../components/CommentComponent'; 11 | 12 | @Entry 13 | @Component 14 | struct MoviePlayPage { 15 | @State movieItem: MovieInterface = null; // 电影详情 16 | @State recommendMovieList: Array = []; // 推荐的电影 17 | @State currentUrl: string = ''; // 当前播放地址 18 | @State currentUrlGroup: number = 0; // 当前选中的url分组 19 | @State commentTotal: number = 0; // 评论总数 20 | @State isFavorite: boolean = false; // 是否搜查电影 21 | private loading: boolean = false; 22 | private controller: web_webview.WebviewController = new web_webview.WebviewController(); 23 | private customDialogController: CustomDialogController; 24 | @State movieUrlGroup: Array> = >> []; // 电影分组 25 | 26 | @Styles blockStyle(){ 27 | .backgroundColor(colors.blockColor) 28 | .borderRadius(size.blockBorderRaduis) 29 | .padding(size.pagePadding) 30 | .width('100%') 31 | .margin({ top: size.pagePadding }) 32 | } 33 | 34 | aboutToDisappear() { 35 | this.customDialogController = null; 36 | } 37 | 38 | aboutToAppear() { 39 | const params = router.getParams(); // 获取传递过来的参数对象 40 | this.movieItem = params['movieItem'] as MovieInterface; // 获取info属性的值 41 | this.movieItem.id = 72667;// 测试数据 42 | getMovieUrlService(this.movieItem.id).then(res => { // 获取电影播放地址分组 43 | res.data.forEach((dItem, dIndex) => { 44 | if (dIndex === 0) { 45 | this.currentUrl = dItem.url; 46 | } 47 | const index: number = this.movieUrlGroup.findIndex((mItem) => mItem[0].playGroup === dItem.playGroup) 48 | if (index != -1) { 49 | this.movieUrlGroup[index].push(dItem); 50 | } else { 51 | this.movieUrlGroup.push([dItem]); 52 | } 53 | }) 54 | }) 55 | 56 | /** 57 | * @author: wuwenqiang 58 | * @description: 查询评论数量 59 | * @date: 2024-05-25 16:30 60 | */ 61 | getCommentCountService(this.movieItem.id, SocialEnum.MOVIE.toString()).then((res) => { 62 | this.commentTotal = res.data; 63 | }); 64 | 65 | /** 66 | * @author: wuwenqiang 67 | * @description: 查询是否已经收藏 68 | * @date: 2024-05-25 16:30 69 | */ 70 | isFavoriteService(this.movieItem.id).then((res) => { 71 | this.isFavorite = res.data > 0; 72 | }) 73 | } 74 | 75 | /** 76 | * @author: wuwenqiang 77 | * @description: 创建评论 78 | * @date: 2024-05-25 16:30 79 | */ 80 | @Builder commentBuilder() { 81 | CommentComponent({commentListStr:'' ,relationId: this.movieItem.id, type: SocialEnum.MOVIE.toString() }) 82 | } 83 | 84 | /** 85 | * @author: wuwenqiang 86 | * @description: 电影播放地址分组 87 | * @date: 2025-01-7 23:49 88 | */ 89 | getGroup(movieUrlList:Array):Array>{ 90 | const movieUrlGroup:Array> = []; 91 | let myMovieUrlList:Array 92 | movieUrlList.forEach((item:MovieUrlInterface,index:number)=>{ 93 | if(movieUrlGroup.length === 0 || movieUrlGroup[movieUrlGroup.length - 1].length === 4){ 94 | myMovieUrlList = []; 95 | movieUrlGroup.push(myMovieUrlList) 96 | }else{ 97 | myMovieUrlList = movieUrlGroup[movieUrlGroup.length - 1] 98 | } 99 | myMovieUrlList.push(item) 100 | }) 101 | if(movieUrlGroup[movieUrlGroup.length - 1].length < 4){ 102 | for(let i = 0; i < 4 - movieUrlGroup[movieUrlGroup.length - 1].length; i++){ 103 | movieUrlGroup[movieUrlGroup.length - 1].push(null) 104 | } 105 | } 106 | return movieUrlGroup 107 | } 108 | 109 | build() { 110 | Column() { 111 | if (this.currentUrl) { 112 | Web({ src: this.currentUrl, controller: this.controller }) 113 | .width('100%') 114 | .aspectRatio(16 / 9) 115 | .backgroundColor(Color.Black) 116 | } else { 117 | Row().height(size.webviewHeight).width('100%').backgroundColor(Color.Black) 118 | } 119 | Scroll() { 120 | Column() { 121 | Row() { 122 | Image($r('app.media.icon_comment')) 123 | .height(size.middlIconSize) 124 | .width(size.middlIconSize) 125 | .margin({ right: size.pagePadding }).onClick(() => { 126 | if (!this.customDialogController) { 127 | this.customDialogController = new CustomDialogController({ 128 | customStyle: true, 129 | builder: BottomDialogComponent({ 130 | dialogHeight: '80%', 131 | builder: this.commentBuilder.bind(this) 132 | }), 133 | alignment: DialogAlignment.Bottom, 134 | }) 135 | } 136 | this.customDialogController.open(); 137 | }) 138 | Text(this.commentTotal.toString()) 139 | Blank() 140 | Image(this.isFavorite ? $r('app.media.icon_collection_active') : $r('app.media.icon_collection')) 141 | .height(size.middlIconSize) 142 | .width(size.middlIconSize) 143 | .margin({ right: size.pagePadding }).onClick(() => { 144 | if (this.loading) return; 145 | this.loading = false; 146 | if (this.isFavorite) { 147 | deleteFavoriteService(this.movieItem.id) 148 | .then(res => this.isFavorite = !(res.data > 0)) 149 | .finally(() => this.loading = false) 150 | } else { 151 | saveFavoriteService(this.movieItem.id) 152 | .then(res => this.isFavorite = res.data > 0) 153 | .finally(() => this.loading = false) 154 | } 155 | }) 156 | Image($r('app.media.icon_share')) 157 | .height(size.middlIconSize) 158 | .width(size.middlIconSize) 159 | }.blockStyle() 160 | Column() { 161 | Text(this.movieItem.movieName) 162 | .fontWeight(FontWeight.Bolder) 163 | .fontSize(size.bigFontSize) 164 | .padding({ bottom: size.smallPadding }) 165 | Text(this.movieItem.star).fontSize(size.normalFontSize) 166 | if (this.movieItem.score) { 167 | Row() { 168 | Rating().stars(this.movieItem.score).stepSize(0.1) 169 | Text(this.movieItem.score.toString()) 170 | .padding({ left: size.smallPadding }) 171 | .fontColor(Color.Red) 172 | .fontSize(size.normalFontSize) 173 | .fontWeight(FontWeight.Bolder) 174 | }.justifyContent(FlexAlign.Start).margin({ top: size.smallPadding }) 175 | } 176 | }.blockStyle().alignItems(HorizontalAlign.Start) 177 | Column() { 178 | ForEach(this.movieUrlGroup, (items: Array, index: number) => { 179 | Text((/^\d$/.test(items[0].playGroup) ? '分组' : '') + items[0].playGroup) 180 | ForEach(this.getGroup(items),(aItem,aIndex)=>{ 181 | Row({space:size.pagePadding}){ 182 | ForEach(aItem,(bItem)=>{ 183 | if(bItem){ 184 | Text(bItem.label) 185 | .border({ 186 | width: 1, 187 | color: this.currentUrl == bItem.url ? Color.Orange : Color.Black, 188 | style: BorderStyle.Solid 189 | }) 190 | .padding(size.smallPadding) 191 | .fontColor(this.currentUrl == bItem.url ? Color.Orange : Color.Black) 192 | .textAlign(TextAlign.Center) 193 | .layoutWeight(1) 194 | .borderRadius(size.blockBorderRaduis) 195 | }else { 196 | Blank().layoutWeight(1) 197 | } 198 | }) 199 | }.width('100%').justifyContent(FlexAlign.Start).margin({ 200 | top: size.pagePadding 201 | }) 202 | }) 203 | if( index !== this.movieUrlGroup.length - 1){ 204 | Blank().height(size.pagePadding) 205 | Divider().height(1).color(colors.borderColor) 206 | Blank().height(size.pagePadding) 207 | } 208 | }) 209 | }.blockStyle().alignItems(HorizontalAlign.Start) 210 | }.justifyContent(FlexAlign.Start) 211 | .backgroundColor(colors.pageBackgroundColor) 212 | .padding({ left: size.pagePadding, right: size.pagePadding, bottom: size.pagePadding }) 213 | }.layoutWeight(1) 214 | }.width('100%') 215 | .height('100%') 216 | .justifyContent(FlexAlign.Start) 217 | .backgroundColor(colors.pageBackgroundColor) 218 | } 219 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/MovieSearchPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import * as colors from '../theme/color'; 3 | import * as size from '../theme/size'; 4 | import { MovieInterface } from '../interface/Index'; 5 | import TitleComponent from '../components/TitleComponent'; 6 | import MovieListComponent from '../components/MovieListComponent'; 7 | import { getRecommendSerivce, getSearchResultService } from '../service/Index'; 8 | import preference from '../utils/PreferenceModel'; 9 | 10 | @Entry 11 | @Component 12 | struct MovieSearchPage { 13 | scroller: Scroller = new Scroller() 14 | @State searchKeyWord: string = ''; // 搜索词 15 | @State classify: string = ''; 16 | @State recommendMovieList: Array = []; // 推荐的电影 17 | @State searching: boolean = false; 18 | @State searchMovieList: Array = []; 19 | @State loading: boolean = false; 20 | @State searchRecordList: Array = [] 21 | 22 | @Styles blockStyle(){ 23 | .backgroundColor(colors.blockColor) 24 | .borderRadius(size.blockBorderRaduis) 25 | .padding(size.pagePadding) 26 | .width('100%') 27 | .margin({ top: size.pagePadding }) 28 | } 29 | 30 | @State movieItem: MovieInterface = null; 31 | 32 | async aboutToAppear() { 33 | const params = router.getParams(); // 获取传递过来的参数对象 34 | this.movieItem = params['movieItem'] as MovieInterface; // 获取info属性的值 35 | this.classify = params['classify'] as string; // 获取info属性的值 36 | preference.getMovieSeachKeyWord().then(res => { 37 | this.searchRecordList = res; 38 | }) 39 | getRecommendSerivce(this.classify).then(res => { 40 | this.recommendMovieList.push(...res.data); 41 | }) 42 | } 43 | 44 | /** 45 | * @description: 音乐搜索 46 | * @date: 2024-01-10 23:01 47 | * @author wuwenqiang 48 | */ 49 | useSearch = () => { 50 | if (this.loading) return; 51 | this.loading = true; 52 | this.searching = true; 53 | if (!this.searchKeyWord) { 54 | this.searchKeyWord = this.movieItem.movieName; 55 | } 56 | // 搜索记录写入缓存 57 | preference.setMovieSeachKeyWord(this.searchKeyWord).then((res) => { 58 | this.searchRecordList = res; 59 | }); 60 | // 搜索 61 | getSearchResultService(this.searchKeyWord, 20, 1).then((res) => { 62 | this.searchMovieList = res.data; 63 | }).finally(() => this.loading = false) 64 | } 65 | 66 | build() { 67 | Scroll() { 68 | Column() { 69 | Row() { 70 | Row({space:size.pagePadding}) { 71 | TextInput({text: this.searchKeyWord, placeholder: this.movieItem?.movieName }) 72 | .height(size.inputHeight) 73 | .layoutWeight(1) 74 | .backgroundColor(Color.Transparent) 75 | .onChange((value) => { 76 | this.searchKeyWord = value.trim(); 77 | }) 78 | 79 | if (this.searchKeyWord) { 80 | Image($r('app.media.icon_clear')) 81 | .width(size.smallIconSize) 82 | .height(size.smallIconSize) 83 | .onClick(() => { 84 | this.searchKeyWord = ''; 85 | }) 86 | .margin({ right: size.pagePadding }) 87 | .onClick(() => { 88 | this.searchKeyWord = ''; 89 | this.searching = false; 90 | }) 91 | } 92 | } 93 | .alignItems(VerticalAlign.Center) 94 | .borderRadius(size.inputHeight) 95 | .backgroundColor(colors.pageBackgroundColor) 96 | .layoutWeight(1) 97 | Text("搜索") 98 | .width(size.btnWidth) 99 | .textAlign(TextAlign.Center) 100 | .fontSize(size.normalFontSize) 101 | .margin({ left: size.pagePadding }) 102 | .backgroundColor(colors.lineBackgroundColor) 103 | .borderRadius(size.pagePadding * 2) 104 | .height(size.inputHeight) 105 | .fontColor(colors.blockColor) 106 | .onClick(this.useSearch) 107 | }.blockStyle() 108 | 109 | if (this.searching) { 110 | if (!this.loading) { 111 | Column() { 112 | if (this.searchMovieList.length === 0) { 113 | Text("暂无搜索结果") 114 | .width('100%') 115 | .height(size.bigAvaterSize) 116 | .textAlign(TextAlign.Center) 117 | } else { 118 | MovieListComponent({ movieList: $searchMovieList, gravity: 'vertical' }) 119 | } 120 | }.blockStyle() 121 | } 122 | } else { 123 | Column() { 124 | Column() { 125 | TitleComponent({ title: "历史搜索",showMarginBottom:true }) 126 | if (this.searchRecordList.length === 0) { 127 | Text("暂无搜索记录") 128 | .width('100%') 129 | .height(size.bigAvaterSize) 130 | .textAlign(TextAlign.Center) 131 | } else { 132 | Flex({ wrap: FlexWrap.Wrap }) { 133 | ForEach(this.searchRecordList, (item: string) => { 134 | Text(item) 135 | .backgroundColor(colors.pageBackgroundColor) 136 | .height(size.middleAvaterSize) 137 | .borderRadius(size.pagePadding * 2) 138 | .textAlign(TextAlign.Center) 139 | .padding({ left: size.pagePadding, right: size.pagePadding }) 140 | .onClick(() => { 141 | this.searchKeyWord = item; 142 | }) 143 | }) 144 | } 145 | } 146 | }.blockStyle() 147 | 148 | if (this.recommendMovieList.length > 0) { 149 | Column() { 150 | TitleComponent({ title: "推荐",showMarginBottom: true }) 151 | MovieListComponent({ movieList: $recommendMovieList, gravity: 'vertical' }) 152 | }.blockStyle().margin({ top: size.pagePadding, bottom: size.pagePadding }) 153 | } 154 | } 155 | } 156 | }.justifyContent(FlexAlign.Start) 157 | } 158 | .backgroundColor(colors.pageBackgroundColor) 159 | .padding({ 160 | left: size.pagePadding, 161 | right: size.pagePadding 162 | }) 163 | .align(Alignment.Top) 164 | .scrollable(ScrollDirection.Vertical) 165 | .height('100%') 166 | .width('100%') 167 | } 168 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/MovieUserPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import { UserDataInterface } from "../interface"; 3 | import * as colors from '../theme/color'; 4 | import * as size from '../theme/size'; 5 | import { HOST } from '../common/constant'; 6 | import { USER_DATA } from '../common/constant'; 7 | import { updateUserDataService } from '../service/Index'; 8 | import preference from '../utils/PreferenceModel'; 9 | import OptionDialogComponent from '../components/OptionDialogComponent'; 10 | 11 | @Entry 12 | @Component 13 | struct MovieUserPage { 14 | @StorageLink(USER_DATA) userData: UserDataInterface = null; 15 | title: string = ''; 16 | @State field: string = ''; 17 | 18 | @Styles blockStyle(){ 19 | .backgroundColor(colors.blockColor) 20 | .borderRadius(size.blockBorderRaduis) 21 | .padding(size.pagePadding) 22 | .width('100%') 23 | .margin({ top: size.pagePadding }) 24 | } 25 | 26 | @Styles arrowStyle(){ 27 | .margin({ left: size.smallPadding }) 28 | .height(size.smallIconSize) 29 | .width(size.smallIconSize) 30 | } 31 | 32 | @Styles rowStyle(){ 33 | .border({ 34 | width: { 35 | bottom: 1, 36 | }, 37 | color: { 38 | bottom: colors.pageBackgroundColor 39 | }, 40 | style: { 41 | bottom: BorderStyle.Solid 42 | } 43 | }) 44 | .width('100%') 45 | .padding({ top: size.pagePadding, bottom: size.pagePadding }) 46 | } 47 | 48 | useShowDialog(title: string, field: string) { 49 | this.title = title; 50 | this.field = field; 51 | if (field === 'sex') { 52 | this.dialogController = new CustomDialogController({ 53 | customStyle: true, 54 | builder: OptionDialogComponent({ 55 | cancel: () => this.onCancel(), 56 | confirm: (value) => this.onConfirm(value), 57 | options: ['男', '女'], 58 | }), 59 | alignment: DialogAlignment.Bottom, 60 | }) 61 | } else if (title === 'logout') { 62 | this.dialogController = new CustomDialogController({ 63 | customStyle: false, 64 | builder: LogoutDialogComponent({ 65 | cancel: () => this.onCancel(), 66 | confirm: () => this.onLogout(), 67 | }), 68 | alignment: DialogAlignment.Center, 69 | }) 70 | } else { 71 | this.dialogController = new CustomDialogController({ 72 | customStyle: true, 73 | builder: CustomDialogComponent({ 74 | cancel: () => this.onCancel(), 75 | confirm: (value) => this.onConfirm(value), 76 | title: this.title, 77 | text: this.userData[this.field] 78 | }), 79 | alignment: DialogAlignment.Center, 80 | }) 81 | } 82 | this.dialogController.open() 83 | } 84 | 85 | dialogController: CustomDialogController = null 86 | 87 | onCancel() { 88 | this.dialogController.close() 89 | } 90 | 91 | /** 92 | * @description: 修改用户信息 93 | * @date: 2024-01-10 23:01 94 | * @author wuwenqiang 95 | */ 96 | onConfirm(value) { 97 | const userData: UserDataInterface = { ...this.userData } 98 | userData[this.field] = value 99 | updateUserDataService(userData).then(() => { 100 | this.userData[this.field] = value; 101 | this.dialogController.close() 102 | }) 103 | } 104 | 105 | onLogout() { 106 | preference.setToke(null); 107 | router.replaceUrl({ 108 | url: 'pages/MovieLoginPage', // 目标url 109 | }, router.RouterMode.Single, (err) => { 110 | if (err) { 111 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 112 | } 113 | }); 114 | router.clear(); // 清除历史页面 115 | } 116 | 117 | build() { 118 | Column() { 119 | Column() { 120 | Row() { 121 | Text('头像').flexGrow(1) 122 | Image(this.userData?.avater ? HOST + this.userData.avater : $r('app.media.default_avater')) 123 | .height(size.bigAvaterSize) 124 | .width(size.bigAvaterSize) 125 | .borderRadius(size.bigAvaterSize) 126 | Image($r('app.media.icon_arrow')).arrowStyle() 127 | }.rowStyle().justifyContent(FlexAlign.Center) 128 | 129 | Row() { 130 | Text('昵称').flexGrow(1) 131 | Text(this.userData.username) 132 | Image($r('app.media.icon_arrow')).arrowStyle() 133 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 134 | this.useShowDialog('昵称', 'username') 135 | }) 136 | 137 | Row() { 138 | Text('性别').flexGrow(1) 139 | Text(this.userData.sex) 140 | Image($r('app.media.icon_arrow')).arrowStyle() 141 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 142 | this.useShowDialog('性别', 'sex') 143 | }) 144 | 145 | Row() { 146 | Text('电话').flexGrow(1) 147 | Text(this.userData.telephone) 148 | Image($r('app.media.icon_arrow')).arrowStyle() 149 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 150 | this.useShowDialog('电话', 'telephone') 151 | }) 152 | 153 | Row() { 154 | Text('邮箱').flexGrow(1) 155 | Text(this.userData.email) 156 | Image($r('app.media.icon_arrow')).arrowStyle() 157 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 158 | this.useShowDialog('邮箱', 'email') 159 | }) 160 | 161 | Row() { 162 | Text('生日').flexGrow(1) 163 | Text(this.userData.birthday) 164 | Image($r('app.media.icon_arrow')).arrowStyle() 165 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 166 | DatePickerDialog.show({ 167 | start: new Date("1970-1-1"), 168 | end: new Date("2100-12-31"), 169 | selected: new Date(this.userData.birthday), 170 | onChange: (value: DatePickerResult) => { 171 | this.userData.birthday = `${value.year}-${value.month}-${value.day}`; 172 | } 173 | }) 174 | }) 175 | 176 | Row() { 177 | Text('个性签名').flexGrow(1) 178 | Text(this.userData.sign) 179 | Image($r('app.media.icon_arrow')).arrowStyle() 180 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 181 | this.useShowDialog('个性签名', 'sign') 182 | }) 183 | 184 | Row() { 185 | Text('区域').flexGrow(1) 186 | Text(this.userData.region) 187 | Image($r('app.media.icon_arrow')).arrowStyle() 188 | }.rowStyle().border({ width: 0 }).justifyContent(FlexAlign.Center).onClick(() => { 189 | this.useShowDialog('区域', 'region') 190 | }) 191 | 192 | }.blockStyle().padding({ top: 0, left: size.pagePadding, right: size.pagePadding }) 193 | 194 | Button('退出登录') 195 | .width('100%') 196 | .padding(size.pagePadding) 197 | .backgroundColor(colors.warnColor) 198 | .margin({ top: size.pagePadding }) 199 | .fontColor(Color.White) 200 | .borderRadius(size.blockBorderRaduis * 2) 201 | .onClick(() => { 202 | this.useShowDialog('logout', ''); 203 | }) 204 | } 205 | .width('100%') 206 | .padding({ left: size.pagePadding, right: size.pagePadding, bottom: size.pagePadding }) 207 | .height('100%') 208 | .justifyContent(FlexAlign.Start) 209 | .backgroundColor(colors.pageBackgroundColor) 210 | } 211 | } 212 | 213 | /** 214 | * @description: 修改用户信息弹窗 215 | * @date: 2024-01-14 21:47 216 | * @author wuwenqiang 217 | */ 218 | @CustomDialog 219 | struct CustomDialogComponent { 220 | controller: CustomDialogController 221 | cancel: () => void 222 | confirm: (value: string) => void 223 | title: string 224 | text: string 225 | value: string 226 | 227 | aboutToAppear() { 228 | this.value = this.text 229 | } 230 | 231 | build() { 232 | Column({space:size.pagePadding}) { 233 | Text("请输入") 234 | .margin({ top: size.pagePadding }) 235 | Row() { 236 | Text(this.title) 237 | .margin({ right: size.smallIconSize }) 238 | TextInput({ placeholder: '请输入', text: this.text }) 239 | .layoutWeight(1) 240 | .backgroundColor(colors.pageBackgroundColor) 241 | .height(size.lineHeight * 2) 242 | .onChange((value: string) => { 243 | this.value = value 244 | }) 245 | }.width('100%') 246 | .padding({left:size.pagePadding,right:size.pagePadding}) 247 | .alignItems(VerticalAlign.Center) 248 | 249 | Row() { 250 | Text('取消') 251 | .onClick(() => { 252 | this.controller.close() 253 | this.cancel() 254 | }) 255 | .flexGrow(1) 256 | .textAlign(TextAlign.Center) 257 | .backgroundColor(colors.blockColor) 258 | .fontColor(Color.Black) 259 | Divider().width(1).height('100%').backgroundColor(colors.borderColor) 260 | Text('确定') 261 | .onClick(() => { 262 | this.confirm(this.value) 263 | }) 264 | .flexGrow(1) 265 | .textAlign(TextAlign.Center) 266 | .backgroundColor(colors.blockColor) 267 | .fontColor(Color.Red) 268 | }.height(size.dialogBtnHeight).border({ 269 | width: { 270 | top: 1, 271 | }, 272 | color: { 273 | top: colors.borderColor 274 | }, 275 | style: { 276 | top: BorderStyle.Solid 277 | } 278 | }) 279 | .width('100%') 280 | } 281 | .backgroundColor(colors.blockColor) 282 | .borderRadius(size.blockBorderRaduis) 283 | .margin({ left: size.pagePadding, right: size.pagePadding }) 284 | } 285 | } 286 | 287 | 288 | /** 289 | * @description: 退出登录弹窗 290 | * @date: 2024-01-14 21:47 291 | * @author wuwenqiang 292 | */ 293 | @CustomDialog 294 | struct LogoutDialogComponent { 295 | controller: CustomDialogController 296 | cancel: () => void 297 | confirm: () => void 298 | title: string 299 | 300 | build() { 301 | Column() { 302 | Text("是否退出登录?") 303 | .padding(size.pagePadding * 2) 304 | Row() { 305 | Text('取消') 306 | .onClick(() => { 307 | this.controller.close() 308 | this.cancel() 309 | }) 310 | .flexGrow(1) 311 | .textAlign(TextAlign.Center) 312 | .backgroundColor(colors.blockColor) 313 | .fontColor(Color.Black) 314 | .onClick(() => { 315 | this.cancel() 316 | }) 317 | Divider().height('100%').width(1).backgroundColor(colors.pageBackgroundColor) 318 | Text('确定') 319 | .onClick(() => { 320 | this.confirm() 321 | }) 322 | .flexGrow(1) 323 | .textAlign(TextAlign.Center) 324 | .backgroundColor(colors.blockColor) 325 | .fontColor(Color.Red) 326 | .onClick(() => { 327 | this.confirm() 328 | }) 329 | }.border({ 330 | width: { 331 | top: 1, 332 | }, 333 | color: { 334 | top: colors.pageBackgroundColor 335 | }, 336 | style: { 337 | top: BorderStyle.Solid 338 | } 339 | }).alignItems(VerticalAlign.Center).width('100%').height(size.dialogBtnHeight) 340 | } 341 | .width('100%') 342 | .backgroundColor(colors.blockColor) 343 | .borderRadius(size.blockBorderRaduis) 344 | .margin({ left: size.pagePadding, right: size.pagePadding }) 345 | } 346 | } -------------------------------------------------------------------------------- /entry/src/main/ets/pages/RegisterPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import * as colors from '../theme/color'; 3 | import * as size from '../theme/size'; 4 | import { UserDataInterface } from '../interface/Index'; 5 | import promptAction from '@ohos.promptAction' 6 | import { registerService, verifyUserService } from '../service/Index'; 7 | import httpRequest from '../utils/HttpUtil'; 8 | import preference from '../utils/PreferenceModel'; 9 | import display from '@ohos.display'; 10 | import OptionDialogComponent from '../components/OptionDialogComponent'; 11 | import { zerofull } from '../utils/common'; 12 | import { USER_DATA } from '../common/constant'; 13 | import NavigatorTitleComponent from '../components/NavigatorTitleComponent'; 14 | @Entry 15 | @Component 16 | struct RegisterPage { 17 | @State userData: UserDataInterface = { 18 | userAccount: '', 19 | username: '', 20 | telephone: '', 21 | email: '', 22 | avater: '', 23 | birthday: '', 24 | sex: '', 25 | role: '', 26 | password: '', 27 | sign: '', 28 | region: '', 29 | } 30 | loading: boolean = false; 31 | comfirmPassword: string = ''; // 确认密码 32 | sexController = new TextInputController() 33 | birthdayController = new TextInputController() 34 | 35 | @Styles blockStyle(){ 36 | .backgroundColor(colors.blockColor) 37 | .borderRadius(size.blockBorderRaduis) 38 | .padding(size.pagePadding) 39 | .width('100%') 40 | .margin({ top: size.pagePadding }) 41 | } 42 | 43 | @Styles inputStyle(){ 44 | .border({ 45 | width: { 46 | bottom: 1 47 | }, 48 | color: { 49 | bottom: colors.borderColor 50 | }, 51 | style: { 52 | bottom: BorderStyle.Solid 53 | } 54 | }) 55 | .borderRadius(0) 56 | .backgroundColor(Color.Transparent) 57 | .width('80%') 58 | } 59 | 60 | dialogController: CustomDialogController = null; // 性别和姓名弹窗 61 | 62 | /** 63 | * @description: 校验必填字段 64 | * @date: 2024-01-14 21:47 65 | * @author wuwenqiang 66 | */ 67 | verify(value: string, title: string) { 68 | if (value.length > 18 || value.length < 6) { 69 | promptAction.showToast({ 70 | message: `请输入6-18的${title}`, 71 | duration: 2000, 72 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 73 | }); 74 | return false; 75 | } else if (!value.trim()) { 76 | promptAction.showToast({ 77 | message: `${title}不能为空`, 78 | duration: 2000, 79 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 80 | }); 81 | return false; 82 | } 83 | return true; 84 | } 85 | 86 | useRegister=async ()=>{ 87 | if ( 88 | this.verify(this.userData.userAccount, '账号') && 89 | this.verify(this.userData.password, '密码') && 90 | this.verify(this.comfirmPassword, '确认密码') && 91 | this.verify(this.userData.username, '昵称') && 92 | this.verify(this.userData.email, '邮箱') 93 | ) { 94 | if(this.loading)return; 95 | this.loading = true; 96 | const {data,msg} = await verifyUserService(this.userData.userAccount,this.userData.email) 97 | if(data > 0){ 98 | promptAction.showToast({ 99 | message: msg, 100 | duration: 2000, 101 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 102 | }); 103 | return this.loading = false; 104 | } 105 | registerService(this.userData).then(async res => { 106 | preference.setPassword(this.userData.userAccount, this.userData.password) 107 | preference.setToke(res.token); 108 | httpRequest.setToken(res.token); 109 | AppStorage.SetOrCreate(USER_DATA, res.data) 110 | router.replaceUrl({ 111 | url: 'pages/IndexPage', // 目标url 112 | }, router.RouterMode.Single, (err) => { 113 | if (err) { 114 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 115 | } 116 | }); 117 | router.clear() 118 | }).finally(()=>{ 119 | this.loading = false; 120 | }) 121 | } 122 | } 123 | 124 | build() { 125 | Column() { 126 | NavigatorTitleComponent({title:"注册"}) 127 | Scroll(){ 128 | Column(){ 129 | Column() { 130 | Row() { 131 | Row() { 132 | Text("*").fontColor(colors.warnColor) 133 | Text("账号:") 134 | }.width('20%') 135 | 136 | TextInput({ placeholder: "请输入6-18位数的账号", text: this.userData.userAccount }) 137 | .inputStyle() 138 | .maxLength(18) 139 | .onChange((value) => { 140 | this.userData.userAccount = value; 141 | }).onBlur(() => { 142 | if (this.verify(this.userData.userAccount, '账号')) { 143 | if (this.loading) return; 144 | this.loading = true; 145 | verifyUserService(this.userData.userAccount,undefined).then((res) => { 146 | if (res.data > 0) { 147 | promptAction.showToast({ 148 | message: '该账号已经存在', 149 | duration: 2000, 150 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 151 | }); 152 | } 153 | }).finally(() => this.loading = false); 154 | } 155 | }) 156 | } 157 | 158 | Row() { 159 | Row() { 160 | Text("*").fontColor(colors.warnColor) 161 | Text("密码:") 162 | }.width('20%') 163 | 164 | TextInput({ placeholder: "请输入6-18位数的密码", text: this.userData.password }) 165 | .type(InputType.Password) 166 | .maxLength(18) 167 | .inputStyle() 168 | .onChange((value) => { 169 | this.userData.password = value; 170 | }) 171 | .onBlur(() => { 172 | this.verify(this.userData.password, '密码') 173 | }) 174 | }.margin({ top: size.pagePadding }) 175 | 176 | Row() { 177 | Row() { 178 | Text("*").fontColor(colors.warnColor) 179 | Text("确认密码:") 180 | }.width('20%') 181 | 182 | TextInput({ placeholder: "请输入6-18位数的确认密码", text: this.comfirmPassword }) 183 | .type(InputType.Password) 184 | .maxLength(18) 185 | .inputStyle() 186 | .onChange((value) => { 187 | this.comfirmPassword = value; 188 | }) 189 | .onBlur(() => { 190 | this.verify(this.comfirmPassword, '确认密码'); 191 | }) 192 | }.margin({ top: size.pagePadding }) 193 | 194 | Row() { 195 | Row() { 196 | Text("*").fontColor(colors.warnColor) 197 | Text("昵称:") 198 | }.width('20%') 199 | 200 | TextInput({ placeholder: "请输入昵称", text: this.userData.username }) 201 | .inputStyle() 202 | .onChange((value) => { 203 | this.userData.username = value; 204 | }).onBlur(() => { 205 | this.verify(this.userData.username, '昵称'); 206 | }) 207 | }.margin({ top: size.pagePadding }) 208 | 209 | Row() { 210 | Row() { 211 | Text("性别:") 212 | }.width('20%') 213 | 214 | TextInput({ 215 | placeholder: "请选择性别", 216 | text: this.userData.sex, 217 | controller: this.birthdayController 218 | }).fontColor(colors.tabNormalColor).enabled(false).inputStyle() 219 | }.margin({ top: size.pagePadding }).onClick(() => { 220 | this.useShowDialog() 221 | }) 222 | 223 | Row() { 224 | Row() { 225 | Text("出生日期:") 226 | }.width('20%') 227 | 228 | TextInput({ 229 | placeholder: "请选择出生日期", 230 | text: this.userData.birthday, 231 | controller: this.birthdayController 232 | }) 233 | .enabled(false) 234 | .inputStyle() 235 | .fontColor(colors.tabNormalColor) 236 | .onChange((value) => { 237 | this.userData.birthday = value; 238 | }) 239 | }.margin({ top: size.pagePadding }).onClick(() => { 240 | DatePickerDialog.show({ 241 | start: new Date("1970-1-1"), 242 | end: new Date("2100-12-31"), 243 | selected: new Date(this.userData.birthday || '1990-1-1'), 244 | onChange: (value: DatePickerResult) => { 245 | this.userData.birthday = `${value.year}-${zerofull(value.month + 1)}-${zerofull(value.day)}`; 246 | } 247 | }) 248 | }) 249 | 250 | Row() { 251 | Row() { 252 | Text("手机号码:") 253 | }.width('20%') 254 | 255 | TextInput({ placeholder: "请输入手机号码", text: this.userData.telephone }) 256 | .inputStyle() 257 | .onChange((value) => { 258 | this.userData.telephone = value; 259 | }) 260 | }.margin({ top: size.pagePadding }) 261 | 262 | Row() { 263 | Row() { 264 | Text("*").fontColor(colors.warnColor) 265 | Text("邮箱:") 266 | }.width('20%') 267 | 268 | TextInput({ placeholder: "请输入邮箱", text: this.userData.email }) 269 | .inputStyle() 270 | .onChange((value) => { 271 | this.userData.email = value; 272 | }).onBlur(() => { 273 | if (this.verify(this.userData.email, '邮箱')) { 274 | if (this.loading) return; 275 | this.loading = true; 276 | verifyUserService(undefined,this.userData.email).then((res) => { 277 | if (res.data > 0) { 278 | promptAction.showToast({ 279 | message: '邮箱已经存在', 280 | duration: 2000, 281 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 282 | }); 283 | } 284 | }).finally(() => this.loading = false); 285 | } 286 | }) 287 | }.margin({ top: size.pagePadding }) 288 | 289 | Row() { 290 | Row() { 291 | Text("地区:") 292 | }.width('20%') 293 | 294 | TextInput({ placeholder: "请输入地区", text: this.userData.region }) 295 | .inputStyle() 296 | .onChange((value) => { 297 | this.userData.region = value; 298 | }) 299 | }.margin({ top: size.pagePadding }) 300 | 301 | Row() { 302 | Row() { 303 | Text("个性签名:") 304 | }.width('20%') 305 | 306 | TextInput({ placeholder: "请输入个性签名", text: this.userData.sign }) 307 | .inputStyle() 308 | .onChange((value) => { 309 | this.userData.sign = value; 310 | }) 311 | }.margin({ top: size.pagePadding }) 312 | 313 | }.blockStyle() 314 | Text('注册') 315 | .width('100%') 316 | .padding(size.pagePadding) 317 | .textAlign(TextAlign.Center) 318 | .backgroundColor(colors.warnColor) 319 | .margin({ top: size.pagePadding }) 320 | .fontColor(Color.White) 321 | .borderRadius(size.blockBorderRaduis * 2) 322 | .onClick(this.useRegister) 323 | }.justifyContent(FlexAlign.Start) 324 | } 325 | .align(Alignment.Top) 326 | .scrollable(ScrollDirection.Vertical) 327 | .layoutWeight(1) 328 | .padding({left:size.pagePadding,right:size.pagePadding}) 329 | 330 | } 331 | .width('100%') 332 | .height('100%') 333 | .backgroundColor(colors.pageBackgroundColor) 334 | } 335 | 336 | useShowDialog() { 337 | this.dialogController = new CustomDialogController({ 338 | customStyle: true, 339 | builder: OptionDialogComponent({ 340 | cancel: () => this.onCancel(), 341 | confirm: (value) => this.onConfirm(value), 342 | options: ['男', '女'], 343 | }), 344 | alignment: DialogAlignment.Bottom, 345 | }) 346 | this.dialogController.open() 347 | } 348 | 349 | onCancel() { 350 | this.dialogController.close() 351 | } 352 | 353 | /** 354 | * @description: 修改用户信息 355 | * @date: 2024-01-10 23:01 356 | * @author wuwenqiang 357 | */ 358 | onConfirm(value) { 359 | this.userData.sex = value; 360 | this.dialogController.close(); 361 | } 362 | } 363 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/ResetPasswordPage.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { resetPasswordService } from '../service/Index'; 4 | import { UserDataInterface } from '../interface/Index'; 5 | import { USER_DATA } from '../common/constant'; 6 | import promptAction from '@ohos.promptAction' 7 | import display from '@ohos.display'; 8 | import NavigatorTitleComponent from '../components/NavigatorTitleComponent'; 9 | import router from '@ohos.router'; 10 | import preference from '../utils/PreferenceModel'; 11 | import httpRequest from '../utils/HttpUtil'; 12 | 13 | @Entry 14 | @Component 15 | struct ResetPasswordPage { 16 | code: string = ''; 17 | password:string = ""; 18 | comfirmPassword:string = "" 19 | email:string = router.getParams()['email']; // 获取传递过来的参数对象 20 | loading:boolean = false; 21 | 22 | @Styles blockStyle(){ 23 | .backgroundColor(colors.blockColor) 24 | .borderRadius(size.blockBorderRaduis) 25 | .padding(size.pagePadding) 26 | .width('100%') 27 | .margin({ top: size.pagePadding }) 28 | } 29 | 30 | @Styles rowStyle(){ 31 | .border({ 32 | width: { 33 | bottom: 1, 34 | }, 35 | color: { 36 | bottom: colors.pageBackgroundColor 37 | }, 38 | style: { 39 | bottom: BorderStyle.Solid 40 | } 41 | }) 42 | .width('100%') 43 | .padding({ top: size.pagePadding, bottom: size.pagePadding }) 44 | } 45 | 46 | verify(value: string, title: string) { 47 | if (value.length > 18 || value.length < 6) { 48 | promptAction.showToast({ 49 | message: `请输入6-18的${title}`, 50 | duration: 2000, 51 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 52 | }); 53 | return false; 54 | } else if (!value.trim()) { 55 | promptAction.showToast({ 56 | message: `${title}不能为空`, 57 | duration: 2000, 58 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 59 | }); 60 | return false; 61 | } 62 | return true; 63 | } 64 | 65 | useSumbit=()=>{ 66 | if(this.loading)return true; 67 | if(!this.code){ 68 | promptAction.showToast({ 69 | message: "验证码不能为空", 70 | duration: 2000, 71 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 72 | }); 73 | }else if(this.code.length < 4){ 74 | promptAction.showToast({ 75 | message: "请输入四位数的验证码", 76 | duration: 2000, 77 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 78 | }); 79 | }else if(this.password !== this.comfirmPassword){ 80 | promptAction.showToast({ 81 | message: "密码和确认密码不一致", 82 | duration: 2000, 83 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 84 | }); 85 | } else if (this.verify(this.password,'密码') && 86 | this.verify(this.password,'确认密码')) { 87 | this.loading = true; 88 | resetPasswordService(this.email,this.password,this.code).then(async (res)=>{ 89 | // prompt.hideLoading() 90 | promptAction.showToast({ 91 | message: res.msg, 92 | duration: 2000, 93 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 94 | }); 95 | await preference.setToke(res.token); 96 | httpRequest.setToken(res.token); 97 | AppStorage.SetOrCreate(USER_DATA, res.data) 98 | router.replaceUrl({ 99 | url: 'pages/IndexPage', // 目标url 100 | }); 101 | router.clear(); // 清除历史页面 102 | }).finally(()=>{ 103 | // prompt.hideLoading() 104 | this.loading = false; 105 | }) 106 | } 107 | this.loading = true; 108 | } 109 | 110 | build() { 111 | Column() { 112 | NavigatorTitleComponent({ title: "重置密码" }) 113 | Column() { 114 | Column({space:size.pagePadding}){ 115 | Row() { 116 | Text("*").fontColor(colors.warnColor) 117 | TextInput({ placeholder: "请输入验证码" }) 118 | .layoutWeight(1) 119 | .backgroundColor(Color.Transparent) 120 | .onChange((value) => { 121 | this.code = value; 122 | }) 123 | } 124 | Divider().height(size.pagePadding).color(colors.borderColor) 125 | Row() { 126 | Text("*").fontColor(colors.warnColor) 127 | TextInput({ placeholder: "请输入密码" }) 128 | .layoutWeight(1) 129 | .type(InputType.Password) 130 | .backgroundColor(Color.Transparent) 131 | .onChange((value) => { 132 | this.password = value; 133 | }) 134 | } 135 | Divider().height(size.pagePadding).color(colors.borderColor) 136 | Row() { 137 | Text("*").fontColor(colors.warnColor) 138 | TextInput({ placeholder: "请输入确认密码" }) 139 | .layoutWeight(1) 140 | .type(InputType.Password) 141 | .backgroundColor(Color.Transparent) 142 | .onChange((value) => { 143 | this.comfirmPassword = value; 144 | }) 145 | } 146 | } 147 | .blockStyle() 148 | 149 | Text('提交') 150 | .width('100%') 151 | .padding(size.pagePadding) 152 | .textAlign(TextAlign.Center) 153 | .backgroundColor(colors.warnColor) 154 | .margin({ top: size.pagePadding }) 155 | .fontColor(Color.White) 156 | .borderRadius(size.blockBorderRaduis * 2) 157 | .onClick(this.useSumbit) 158 | 159 | } 160 | .width('100%') 161 | .height('100%') 162 | .padding({left:size.pagePadding,right:size.pagePadding}) 163 | .backgroundColor(colors.pageBackgroundColor) 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/UpdatePasswordPage.ets: -------------------------------------------------------------------------------- 1 | import * as colors from '../theme/color'; 2 | import * as size from '../theme/size'; 3 | import { updatePasswordService } from '../service/Index'; 4 | import { UserDataInterface } from '../interface/Index'; 5 | import { USER_DATA } from '../common/constant'; 6 | import promptAction from '@ohos.promptAction' 7 | import display from '@ohos.display'; 8 | import NavigatorTitleComponent from '../components/NavigatorTitleComponent'; 9 | import router from '@ohos.router'; 10 | import preference from '../utils/PreferenceModel'; 11 | import httpRequest from '../utils/HttpUtil'; 12 | 13 | @Entry 14 | @Component 15 | struct UpdatePasswordPage { 16 | oldPassword: string = ''; 17 | newPassword:string = ""; 18 | newComfirmPassword:string = "" 19 | loading:boolean = false; 20 | 21 | @Styles blockStyle(){ 22 | .backgroundColor(colors.blockColor) 23 | .borderRadius(size.blockBorderRaduis) 24 | .padding(size.pagePadding) 25 | .width('100%') 26 | .margin({ top: size.pagePadding }) 27 | } 28 | 29 | @Styles rowStyle(){ 30 | .border({ 31 | width: { 32 | bottom: 1, 33 | }, 34 | color: { 35 | bottom: colors.pageBackgroundColor 36 | }, 37 | style: { 38 | bottom: BorderStyle.Solid 39 | } 40 | }) 41 | .width('100%') 42 | .padding({ top: size.pagePadding, bottom: size.pagePadding }) 43 | } 44 | 45 | verify(value: string, title: string) { 46 | if (value.length > 18 || value.length < 6) { 47 | promptAction.showToast({ 48 | message: `请输入6-18的${title}`, 49 | duration: 2000, 50 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 51 | }); 52 | return false; 53 | } else if (!value.trim()) { 54 | promptAction.showToast({ 55 | message: `${title}不能为空`, 56 | duration: 2000, 57 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 58 | }); 59 | return false; 60 | } 61 | return true; 62 | } 63 | 64 | useSumbit=()=>{ 65 | if(this.newPassword && this.newComfirmPassword && this.newPassword !== this.newComfirmPassword){ 66 | promptAction.showToast({ 67 | message: "密码和确认密码不一致", 68 | duration: 2000, 69 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 70 | }); 71 | } else if ( 72 | this.verify(this.oldPassword,'旧密码') && 73 | this.verify(this.newPassword,'新密码') && 74 | this.verify(this.newPassword,'确认新密码') 75 | ) { 76 | if(this.loading)return; 77 | this.loading = true; 78 | updatePasswordService(this.oldPassword,this.newPassword).then((res)=>{ 79 | promptAction.showToast({ 80 | message: `修改密码成功`, 81 | duration: 2000, 82 | bottom: px2vp(display.getDefaultDisplaySync().height) / 2 83 | }); 84 | router.back(); 85 | }).finally(()=>{ 86 | this.loading = false; 87 | }) 88 | } 89 | } 90 | 91 | build() { 92 | Column() { 93 | NavigatorTitleComponent({ title: "修改密码" }) 94 | Column() { 95 | Column(){ 96 | Row() { 97 | Text("*").fontColor(colors.warnColor) 98 | TextInput({ placeholder: "请输入旧密码" }) 99 | .layoutWeight(1) 100 | .type(InputType.Password) 101 | .backgroundColor(Color.Transparent) 102 | .onChange((value) => { 103 | this.oldPassword = value; 104 | }) 105 | } 106 | Divider().height(size.pagePadding).color(colors.borderColor) 107 | Row() { 108 | Text("*").fontColor(colors.warnColor) 109 | TextInput({ placeholder: "请输入新密码" }) 110 | .layoutWeight(1) 111 | .type(InputType.Password) 112 | .backgroundColor(Color.Transparent) 113 | .onChange((value) => { 114 | this.newPassword = value; 115 | }) 116 | }.margin({top:size.pagePadding}) 117 | Divider().height(size.pagePadding).color(colors.borderColor) 118 | Row() { 119 | Text("*").fontColor(colors.warnColor) 120 | TextInput({ placeholder: "请输入新确认密码" }) 121 | .layoutWeight(1) 122 | .type(InputType.Password) 123 | .backgroundColor(Color.Transparent) 124 | .onChange((value) => { 125 | this.newComfirmPassword = value; 126 | }) 127 | }.margin({top:size.pagePadding}) 128 | } 129 | .blockStyle() 130 | 131 | Text('确定') 132 | .width('100%') 133 | .padding(size.pagePadding) 134 | .textAlign(TextAlign.Center) 135 | .backgroundColor(colors.warnColor) 136 | .margin({ top: size.pagePadding }) 137 | .fontColor(Color.White) 138 | .borderRadius(size.blockBorderRaduis * 2) 139 | .onClick(this.useSumbit) 140 | 141 | } 142 | .width('100%') 143 | .height('100%') 144 | .padding({left:size.pagePadding,right:size.pagePadding}) 145 | .backgroundColor(colors.pageBackgroundColor) 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /entry/src/main/ets/pages/UserPage.ets: -------------------------------------------------------------------------------- 1 | import router from '@ohos.router'; 2 | import { UserDataInterface } from "../interface/Index"; 3 | import * as colors from '../theme/color'; 4 | import * as size from '../theme/size'; 5 | import { HOST } from '../common/constant'; 6 | import { USER_DATA } from '../common/constant'; 7 | import { updateUserDataService } from '../service/Index'; 8 | import preference from '../utils/PreferenceModel'; 9 | import OptionDialogComponent from '../components/OptionDialogComponent'; 10 | import NavigatorTitleComponent from '../components/NavigatorTitleComponent'; 11 | 12 | @Entry 13 | @Component 14 | struct UserPage { 15 | @StorageLink(USER_DATA) userData: UserDataInterface = null; 16 | title: string = ''; 17 | @State field: string = ''; 18 | 19 | @Styles blockStyle(){ 20 | .backgroundColor(colors.blockColor) 21 | .borderRadius(size.blockBorderRaduis) 22 | .padding(size.pagePadding) 23 | .width('100%') 24 | .margin({ top: size.pagePadding }) 25 | } 26 | 27 | @Styles arrowStyle(){ 28 | .margin({ left: size.smallPadding }) 29 | .height(size.smallIconSize) 30 | .width(size.smallIconSize) 31 | } 32 | 33 | @Styles rowStyle(){ 34 | .border({ 35 | width: { 36 | bottom: 1, 37 | }, 38 | color: { 39 | bottom: colors.pageBackgroundColor 40 | }, 41 | style: { 42 | bottom: BorderStyle.Solid 43 | } 44 | }) 45 | .width('100%') 46 | .padding({ top: size.pagePadding, bottom: size.pagePadding }) 47 | } 48 | 49 | useShowDialog(title: string, field: string) { 50 | this.title = title; 51 | this.field = field; 52 | if (field === 'sex') { 53 | this.dialogController = new CustomDialogController({ 54 | customStyle: true, 55 | builder: OptionDialogComponent({ 56 | cancel: () => this.onCancel(), 57 | confirm: (value) => this.onConfirm(value), 58 | options: ['男', '女'], 59 | }), 60 | alignment: DialogAlignment.Bottom, 61 | }) 62 | } else if (title === 'logout') { 63 | this.dialogController = new CustomDialogController({ 64 | customStyle: false, 65 | builder: LogoutDialogComponent({ 66 | cancel: () => this.onCancel(), 67 | confirm: () => this.onLogout(), 68 | }), 69 | alignment: DialogAlignment.Center, 70 | }) 71 | } else { 72 | this.dialogController = new CustomDialogController({ 73 | customStyle: true, 74 | builder: CustomDialogComponent({ 75 | cancel: () => this.onCancel(), 76 | confirm: (value) => this.onConfirm(value), 77 | title: this.title, 78 | text: this.userData[this.field] 79 | }), 80 | alignment: DialogAlignment.Center, 81 | }) 82 | } 83 | this.dialogController.open() 84 | } 85 | 86 | dialogController: CustomDialogController = null 87 | 88 | onCancel() { 89 | this.dialogController.close() 90 | } 91 | 92 | /** 93 | * @description: 修改用户信息 94 | * @date: 2024-01-10 23:01 95 | * @author wuwenqiang 96 | */ 97 | onConfirm(value) { 98 | const userData: UserDataInterface = { ...this.userData } 99 | userData[this.field] = value 100 | updateUserDataService(userData).then(() => { 101 | this.userData[this.field] = value; 102 | this.dialogController.close() 103 | }) 104 | } 105 | 106 | onLogout() { 107 | preference.setToke(null); 108 | router.replaceUrl({ 109 | url: 'pages/LoginPage', // 目标url 110 | }, router.RouterMode.Single, (err) => { 111 | if (err) { 112 | console.error(`Invoke showAlertBeforeBackPage failed, code is ${err.code}, message is ${err.message}`); 113 | } 114 | }); 115 | router.clear(); // 清除历史页面 116 | } 117 | 118 | build() { 119 | Column() { 120 | NavigatorTitleComponent({title:"用户信息"}) 121 | Scroll(){ 122 | Column(){ 123 | Column() { 124 | Row() { 125 | Text('头像').flexGrow(1) 126 | Image(this.userData?.avater ? HOST + this.userData.avater : $r('app.media.default_avater')) 127 | .height(size.bigAvaterSize) 128 | .width(size.bigAvaterSize) 129 | .borderRadius(size.bigAvaterSize) 130 | Image($r('app.media.icon_arrow')).arrowStyle() 131 | }.rowStyle().justifyContent(FlexAlign.Center) 132 | 133 | Row() { 134 | Text('昵称').flexGrow(1) 135 | Text(this.userData.username) 136 | Image($r('app.media.icon_arrow')).arrowStyle() 137 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 138 | this.useShowDialog('昵称', 'username') 139 | }) 140 | 141 | Row() { 142 | Text('性别').flexGrow(1) 143 | Text(this.userData.sex) 144 | Image($r('app.media.icon_arrow')).arrowStyle() 145 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 146 | this.useShowDialog('性别', 'sex') 147 | }) 148 | 149 | Row() { 150 | Text('电话').flexGrow(1) 151 | Text(this.userData.telephone) 152 | Image($r('app.media.icon_arrow')).arrowStyle() 153 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 154 | this.useShowDialog('电话', 'telephone') 155 | }) 156 | 157 | Row() { 158 | Text('邮箱').flexGrow(1) 159 | Text(this.userData.email) 160 | Image($r('app.media.icon_arrow')).arrowStyle() 161 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 162 | this.useShowDialog('邮箱', 'email') 163 | }) 164 | 165 | Row() { 166 | Text('生日').flexGrow(1) 167 | Text(this.userData.birthday) 168 | Image($r('app.media.icon_arrow')).arrowStyle() 169 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 170 | DatePickerDialog.show({ 171 | start: new Date("1970-1-1"), 172 | end: new Date("2100-12-31"), 173 | selected: new Date(this.userData.birthday), 174 | onChange: (value: DatePickerResult) => { 175 | this.userData.birthday = `${value.year}-${value.month}-${value.day}`; 176 | } 177 | }) 178 | }) 179 | 180 | Row() { 181 | Text('个性签名').flexGrow(1) 182 | Text(this.userData.sign) 183 | Image($r('app.media.icon_arrow')).arrowStyle() 184 | }.rowStyle().justifyContent(FlexAlign.Center).onClick(() => { 185 | this.useShowDialog('个性签名', 'sign') 186 | }) 187 | 188 | Row() { 189 | Text('区域').flexGrow(1) 190 | Text(this.userData.region) 191 | Image($r('app.media.icon_arrow')).arrowStyle() 192 | }.rowStyle().border({ width: 0 }).justifyContent(FlexAlign.Center).onClick(() => { 193 | this.useShowDialog('区域', 'region') 194 | }) 195 | 196 | }.blockStyle().padding({ top: 0, left: size.pagePadding, right: size.pagePadding }) 197 | 198 | Button('退出登录') 199 | .width('100%') 200 | .padding(size.pagePadding) 201 | .backgroundColor(colors.warnColor) 202 | .margin({ top: size.pagePadding }) 203 | .fontColor(Color.White) 204 | .borderRadius(size.blockBorderRaduis * 2) 205 | .onClick(() => { 206 | this.useShowDialog('logout', ''); 207 | }) 208 | 209 | Text('修改密码') 210 | .padding(size.smallPadding) 211 | .border({ 212 | width: 1, 213 | color: colors.borderColor, 214 | style: BorderStyle.Solid 215 | }) 216 | .borderRadius(size.blockBorderRaduis * 2) 217 | .width('100%') 218 | .padding(size.pagePadding) 219 | .textAlign(TextAlign.Center) 220 | .margin({ top: size.pagePadding,bottom:size.pagePadding }) 221 | .onClick(() => { 222 | router.pushUrl({ 223 | url: 'pages/UpdatePasswordPage', // 目标url 224 | }); 225 | }) 226 | }.padding({left:size.pagePadding,right:size.pagePadding}) 227 | }.layoutWeight(1).scrollable(ScrollDirection.Vertical).align(Alignment.Top) 228 | 229 | } 230 | .width('100%') 231 | .height('100%') 232 | .justifyContent(FlexAlign.Start) 233 | .backgroundColor(colors.pageBackgroundColor) 234 | } 235 | } 236 | 237 | /** 238 | * @description: 修改用户信息弹窗 239 | * @date: 2024-01-14 21:47 240 | * @author wuwenqiang 241 | */ 242 | @CustomDialog 243 | struct CustomDialogComponent { 244 | controller: CustomDialogController 245 | cancel: () => void 246 | confirm: (value: string) => void 247 | title: string 248 | text: string 249 | value: string 250 | 251 | aboutToAppear() { 252 | this.value = this.text 253 | } 254 | 255 | build() { 256 | Column({space:size.pagePadding}) { 257 | Text("请输入") 258 | .margin({ top: size.pagePadding }) 259 | Row() { 260 | Text(this.title) 261 | .margin({ right: size.smallIconSize }) 262 | TextInput({ placeholder: '请输入', text: this.text }) 263 | .layoutWeight(1) 264 | .backgroundColor(colors.pageBackgroundColor) 265 | .height(size.lineHeight * 2) 266 | .onChange((value: string) => { 267 | this.value = value 268 | }) 269 | }.width('100%') 270 | .padding({left:size.pagePadding,right:size.pagePadding}) 271 | .alignItems(VerticalAlign.Center) 272 | 273 | Row() { 274 | Text('取消') 275 | .onClick(() => { 276 | this.controller.close() 277 | this.cancel() 278 | }) 279 | .flexGrow(1) 280 | .textAlign(TextAlign.Center) 281 | .backgroundColor(colors.blockColor) 282 | .fontColor(Color.Black) 283 | Divider().width(1).height('100%').backgroundColor(colors.borderColor) 284 | Text('确定') 285 | .onClick(() => { 286 | this.confirm(this.value) 287 | }) 288 | .flexGrow(1) 289 | .textAlign(TextAlign.Center) 290 | .backgroundColor(colors.blockColor) 291 | .fontColor(Color.Red) 292 | }.height(size.dialogBtnHeight).border({ 293 | width: { 294 | top: 1, 295 | }, 296 | color: { 297 | top: colors.borderColor 298 | }, 299 | style: { 300 | top: BorderStyle.Solid 301 | } 302 | }) 303 | .width('100%') 304 | } 305 | .backgroundColor(colors.blockColor) 306 | .borderRadius(size.blockBorderRaduis) 307 | .margin({ left: size.pagePadding, right: size.pagePadding }) 308 | } 309 | } 310 | 311 | 312 | /** 313 | * @description: 退出登录弹窗 314 | * @date: 2024-01-14 21:47 315 | * @author wuwenqiang 316 | */ 317 | @CustomDialog 318 | struct LogoutDialogComponent { 319 | controller: CustomDialogController 320 | cancel: () => void 321 | confirm: () => void 322 | title: string 323 | 324 | build() { 325 | Column() { 326 | Text("是否退出登录?") 327 | .padding(size.pagePadding * 2) 328 | Row() { 329 | Text('取消') 330 | .onClick(() => { 331 | this.controller.close() 332 | this.cancel() 333 | }) 334 | .flexGrow(1) 335 | .textAlign(TextAlign.Center) 336 | .backgroundColor(colors.blockColor) 337 | .fontColor(Color.Black) 338 | .onClick(() => { 339 | this.cancel() 340 | }) 341 | Divider().height('100%').width(1).backgroundColor(colors.pageBackgroundColor) 342 | Text('确定') 343 | .onClick(() => { 344 | this.confirm() 345 | }) 346 | .flexGrow(1) 347 | .textAlign(TextAlign.Center) 348 | .backgroundColor(colors.blockColor) 349 | .fontColor(Color.Red) 350 | .onClick(() => { 351 | this.confirm() 352 | }) 353 | }.border({ 354 | width: { 355 | top: 1, 356 | }, 357 | color: { 358 | top: colors.pageBackgroundColor 359 | }, 360 | style: { 361 | top: BorderStyle.Solid 362 | } 363 | }).alignItems(VerticalAlign.Center).width('100%').height(size.dialogBtnHeight) 364 | } 365 | .width('100%') 366 | .backgroundColor(colors.blockColor) 367 | .borderRadius(size.blockBorderRaduis) 368 | .margin({ left: size.pagePadding, right: size.pagePadding }) 369 | } 370 | } -------------------------------------------------------------------------------- /entry/src/main/ets/service/Index.ets: -------------------------------------------------------------------------------- 1 | import api from '../api/index'; 2 | import httpRequest from '../utils/HttpUtil'; 3 | import * as types from '../interface/Index' 4 | import { MyAwesomeData } from '../interface'; 5 | import CryptoJS from '@ohos/crypto-js'; 6 | import { CommentInterface } from '../interface/Index'; 7 | 8 | /** 9 | * @description: 登录 10 | * @date: 2024-01-15 21:32 11 | * @author wuwenqiang 12 | */ 13 | export const loginService = (userAccount:string,password:string):Promise>=>{ 14 | password = CryptoJS.MD5(password).toString();// 使用md5加密 15 | return httpRequest.post(api.login,{userAccount,password}) 16 | }; 17 | 18 | /** 19 | * @description: 根据token获取用户信息 20 | * @date: 2023-12-1 23:39 21 | * @author wuwenqiang 22 | */ 23 | export const getUserDataService = (token:string):Promise>=> { 24 | httpRequest.setToken(token); 25 | return httpRequest.get(api.getUserData); 26 | } 27 | 28 | /** 29 | * @description: 注册 30 | * @date: 2024-01-21 14:48 31 | * @author wuwenqiang 32 | */ 33 | export const registerService = (userData:types.UserDataInterface):Promise>=>{ 34 | userData = {...userData}; 35 | userData.password = CryptoJS.MD5(userData.password).toString();// 使用md5加密 36 | return httpRequest.post(api.register,userData) 37 | }; 38 | 39 | /** 40 | * @description: 注册 41 | * @date: 2024-01-21 14:48 42 | * @author wuwenqiang 43 | */ 44 | export const verifyUserService = (userAccount:string|undefined,email:string|undefined):Promise>=>{ 45 | return httpRequest.post(api.vertifyUser,{userAccount,email}) 46 | }; 47 | 48 | /** 49 | * @description: 修改用户信息 50 | * @date: 2024-01-10 23:01 51 | * @author wuwenqiang 52 | */ 53 | export const updateUserDataService = (userData:types.UserDataInterface):Promise>=>{ 54 | return httpRequest.put(api.updateUser,userData) 55 | }; 56 | 57 | /** 58 | * @description: 找回密码 59 | * @date: 2025-01-19 22:59 60 | * @author wuwenqiang 61 | */ 62 | export const sendEmailVertifyCodeService = (email:string):Promise>=>{ 63 | return httpRequest.post(api.sendEmailVertifyCode,{email}) 64 | }; 65 | 66 | /** 67 | * @description: 邮箱验证码登录 68 | * @date: 2025-01-28 14:22 69 | * @author wuwenqiang 70 | */ 71 | export const loginByEmailService = (email:string,code:string):Promise>=>{ 72 | return httpRequest.post(api.loginByEmail,{email,code}) 73 | }; 74 | 75 | /** 76 | * @description: 重置密码 77 | * @date: 2025-01-26 22:21 78 | * @author wuwenqiang 79 | */ 80 | export const resetPasswordService = (email:string,password:string,code:string):Promise>=>{ 81 | password = CryptoJS.MD5(password).toString();// 使用md5加密 82 | return httpRequest.post(api.resetPassword,{email,password,code}) 83 | }; 84 | 85 | /** 86 | * @description: 更新密码 87 | * @date: 2025-01-28 14:22 88 | * @author wuwenqiang 89 | */ 90 | export const updatePasswordService = (oldPassword:string,newPassword:string):Promise>=>{ 91 | oldPassword = CryptoJS.MD5(oldPassword).toString();// 使用md5加密 92 | newPassword = CryptoJS.MD5(newPassword).toString();// 使用md5加密 93 | return httpRequest.put(api.updatePassword,{oldPassword,newPassword}) 94 | }; 95 | 96 | /** 97 | * @description: 获取搜索框的关键词 98 | * @date: 2023-12-1 23:50 99 | * @author wuwenqiang 100 | */ 101 | export const getSearchKeyWordService = (classify:string):Promise>=> { 102 | return httpRequest.get(api.getKeyWord,{classify}); 103 | } 104 | 105 | /** 106 | * @description: 根据大分类和小分类获取电影列表数据 107 | * @date: 2023-12-1 23:09 108 | * @author wuwenqiang 109 | */ 110 | export const getCategoryListService = (classifyItem:types.ClassifyInterface):Promise>>=> { 111 | return httpRequest.get>(api.getCategoryList,classifyItem) 112 | } 113 | 114 | /** 115 | * @description: 根据大分类和小分类获取电影列表数据 116 | * @date: 2023-12-1 23:09 117 | * @author wuwenqiang 118 | */ 119 | export const getAllCategoryListByPageNameService = (pageName:string):Promise>>=> { 120 | return httpRequest.get>(api.getAllCategoryListByPageName,{pageName}) 121 | } 122 | 123 | /** 124 | * @description: 获取用户使用天数、访问记录数量等 125 | * @date: 2023-12-10 10:15 126 | * @author wuwenqiang 127 | */ 128 | export const getUserMsgService = ():Promise>=> { 129 | return httpRequest.get(api.getUserMsg) 130 | } 131 | 132 | /** 133 | * @description: 获取用户观看记录 134 | * @date: 2023-12-13 21:45 135 | * @author wuwenqiang 136 | */ 137 | export const getPlayRecordMovieListService = (pageNum:number,pageSize:number):Promise>>=> { 138 | return httpRequest.get>(`${api.getPlayRecord}?pageNum=${pageNum}&pageSize=${pageSize}`) 139 | } 140 | 141 | /** 142 | * @description: 获取用户收藏的电影 143 | * @date: 2023-12-15 22:26 144 | * @author wuwenqiang 145 | */ 146 | export const getMyFavoriteMovieListService = (pageNum:number,pageSize:number):Promise>>=> { 147 | return httpRequest.get>(`${api.getFavorite}?pageNum=${pageNum}&pageSize=${pageSize}`) 148 | } 149 | 150 | /** 151 | * @description: 获取用户浏览过的电影 152 | * @date: 2023-12-15 23:28 153 | * @author wuwenqiang 154 | */ 155 | export const getMyViewsMovieListService = (pageNum:number,pageSize:number):Promise>>=> { 156 | return httpRequest.get>(`${api.getViewRecord}?pageNum=${pageNum}&pageSize=${pageSize}`) 157 | } 158 | 159 | /** 160 | * @description: 获取演员信息 161 | * @date: 2023-12-16 18:26 162 | * @author wuwenqiang 163 | */ 164 | export const getMovieStartListService = (movieId:number):Promise>>=> { 165 | return httpRequest.get>(`${api.getStar}${movieId}`) 166 | } 167 | 168 | /** 169 | * @description: 获取推荐的电影 170 | * @date: 2023-12-16 18:28 171 | * @author wuwenqiang 172 | */ 173 | export const getRecommentListService = (classify:string):Promise>>=> { 174 | return httpRequest.get>(`${api.getRecommend}?classify=${classify}`) 175 | } 176 | 177 | /** 178 | * @description: 插入浏览记录 179 | * @date: 2023-12-23 22:12 180 | * @author wuwenqiang 181 | */ 182 | export const saveViewRecordService = (movieItem:types.MovieInterface):Promise>=> { 183 | return httpRequest.post(api.saveViewRecord,movieItem) 184 | } 185 | 186 | /** 187 | * @description: 获取电影地址分株 188 | * @date: 2023-12-26 22:45 189 | * @author wuwenqiang 190 | */ 191 | export const getMovieUrlService = (movieId:number):Promise>>=> { 192 | return httpRequest.get>(`${api.getMovieUrl}?movieId=${movieId}`) 193 | } 194 | 195 | /** 196 | * @description: 获取推荐的电影 197 | * @date: 2024-01-22 23:05 198 | * @author wuwenqiang 199 | */ 200 | export const getRecommendSerivce = (classify:string):Promise>>=>{ 201 | return httpRequest.get>(`${api.getRecommend}?classify=${encodeURIComponent(classify)}`) 202 | }; 203 | 204 | 205 | /** 206 | * @description: 电影搜索 207 | * @date: 2024-01-23 22:12 208 | * @author wuwenqiang 209 | */ 210 | export const getSearchResultService = (keyword:string, pageSize:number = 20, pageNum:number = 1):Promise>>=>{ 211 | return httpRequest.get>(`${api.getSearchResult}?keyword=${encodeURIComponent(keyword)}&pageSize=${pageSize}&pageNum=${pageNum}`) 212 | }; 213 | 214 | 215 | /** 216 | * @author: wuwenqiang 217 | * @description: 获取影片评论总数 218 | * @date: 2023-12-28 23:18 219 | */ 220 | export const getCommentCountService = (id:number,type:string):Promise>=>{ 221 | return httpRequest.get(`${api.getCommentCount}?relationId=${id}&type=${type}&pageSize=20&pageNum=1`) 222 | }; 223 | 224 | /** 225 | * @author: wuwenqiang 226 | * @description: 查询是否已经收藏 227 | * @date: 2023-12-28 22:53 228 | */ 229 | export const isFavoriteService = (movieId:number):Promise>=>{ 230 | return httpRequest.get(`${api.isFavorite}?movieId=${movieId}`) 231 | }; 232 | 233 | /** 234 | * @author: wuwenqiang 235 | * @description: 添加收藏 236 | * @date: 2023-12-28 22:58 237 | */ 238 | export const saveFavoriteService = (movieId:number):Promise>=>{ 239 | return httpRequest.post(`${api.saveFavorite}/${movieId}`,{}) 240 | }; 241 | 242 | /** 243 | * @author: wuwenqiang 244 | * @description: 取消收藏 245 | * @date: 2023-12-28 22:58 246 | */ 247 | export const deleteFavoriteService = (movieId:number):Promise>=>{ 248 | return httpRequest.delete(`${api.deleteFavorite}/${movieId}`); 249 | }; 250 | 251 | /** 252 | * @author: wuwenqiang 253 | * @description: 取消收藏 254 | * @date: 2023-12-28 22:58 255 | */ 256 | export const insertCommentService = (commentItem:CommentInterface):Promise> => { 257 | return httpRequest.post(api.insertComment,commentItem); 258 | } 259 | 260 | /** 261 | * @description: 获取一级评论 262 | * @date: 2024-05-12 12:21 263 | * @author wuwenqiang 264 | */ 265 | export const getTopCommentListService = (relationId:number,type:string,pageNum:number,pageSize:number):Promise>> => { 266 | return httpRequest.get>(`${api.getTopCommentList}?relationId=${relationId}&type=${type}&pageSize=${pageSize}&pageNum=${pageNum}`); 267 | } 268 | -------------------------------------------------------------------------------- /entry/src/main/ets/theme/color.ts: -------------------------------------------------------------------------------- 1 | export const pageBackgroundColor:string = '#efefef' 2 | export const borderColor:string = '#e9e9e9' 3 | export const tabSelectedColor:string = '#ffae00' 4 | export const tabNormalColor:string = '#000000' 5 | export const blockColor:string = '#fff' 6 | export const disableTextColor:string = '#999999' 7 | export const lineBackgroundColor:string = '#2196f3' 8 | export const warnColor:string = '#f7453b'; 9 | export const blueColor:string = '#3e7d9b'; 10 | export const playerOuterCircleColor = 'rgba(0, 0, 0, 0.1)'; 11 | export const blackBackgroundColor:string = 'rgba(0, 0, 0, 0.8)'; 12 | export const textareaColor:string = '#dddddd'; -------------------------------------------------------------------------------- /entry/src/main/ets/theme/size.ts: -------------------------------------------------------------------------------- 1 | export const pagePadding:number = 15; 2 | export const miniPadding:number = 5; 3 | export const smallPadding:number = 10; 4 | export const smallIconSize:number = 20; 5 | export const middlIconSize:number = 30; 6 | export const bigIconSize:number = 40; 7 | export const normalFontSize:number = 15; 8 | export const bigFontSize:number = 25; 9 | export const smallBorderRaduis:number = 10; 10 | export const blockBorderRaduis:number = 15; 11 | export const smallAvaterSize:number = 30; 12 | export const middleAvaterSize:number = 40; 13 | export const roundedSquareSize:number = 60; 14 | export const bigAvaterSize:number = 80; 15 | export const swiperHeight:number = 180; 16 | export const lineHeight:number = 20; 17 | export const lineWidth:number = 5; 18 | export const movieWidth:number = 150; 19 | export const movieHeight:number = 200; 20 | export const webviewHeight:number = 300; 21 | export const dialogBtnHeight:number = 60; 22 | export const btnWidth:number = 100; 23 | export const inputHeight:number = 40; 24 | export const opacity:number = 0.5; 25 | export const popupMenuWidth:number = 200; 26 | export const popupMenuHeight:number = 40; 27 | export const barHeight:number = 70; 28 | -------------------------------------------------------------------------------- /entry/src/main/ets/utils/HttpUtil.ets: -------------------------------------------------------------------------------- 1 | import http from '@ohos.net.http'; 2 | import {HOST} from '../common/constant'; 3 | import {MyAwesomeData} from '../interface/Index' 4 | import promptAction from '@ohos.promptAction'; 5 | import display from '@ohos.display'; 6 | 7 | /** 8 | * @description: 声明业务数据类型 9 | */ 10 | 11 | enum STATUS { 12 | SUCCESS = 'SUCCESS', 13 | FAIL = 'FAIL', 14 | } 15 | 16 | class HttpRequest { 17 | private static instance: HttpRequest; 18 | private token: string; 19 | private constructor() { } 20 | /** 请求函数(单例模式) 21 | * 22 | * **注意:** 23 | * `method`需使用`HttpMethod`枚举类,切勿自行定义 24 | * 25 | * **示例代码** 26 | * ```js 27 | HttpRequest.getInstance().request({ 28 | url: "/Api", 29 | method: HttpMethod.GET 30 | }) 31 | * ``` 32 | */ 33 | public setToken(token:string){ 34 | this.token = token; 35 | } 36 | 37 | public static getInstance(): HttpRequest { 38 | if (!this.instance) { 39 | this.instance = new HttpRequest() 40 | } 41 | return this.instance; 42 | } 43 | 44 | // 服务器接口请求 45 | public request(url:string,options: http.HttpRequestOptions): Promise> { 46 | 47 | const defaultOptions:http.HttpRequestOptions = { 48 | extraData: null, 49 | method: http.RequestMethod.GET, 50 | connectTimeout: 10000, 51 | readTimeout: 10000, 52 | header: { 53 | "content-type": "application/json", 54 | "Authorization": this.token 55 | } 56 | } 57 | 58 | options = {...defaultOptions,...options} 59 | 60 | let httpRequest = http.createHttp(); 61 | return new Promise((resolve, reject) => { 62 | httpRequest.request(HOST + url,options).then((response:http.HttpResponse)=>{ 63 | const result:MyAwesomeData = JSON.parse(response.result.toString()) as MyAwesomeData 64 | if(result.status == STATUS.SUCCESS){ 65 | resolve(result) 66 | }else{ 67 | promptAction.showToast({ 68 | message: result.msg, 69 | duration: 2000, 70 | bottom: px2fp(display.getDefaultDisplaySync().height) / 2 71 | }); 72 | reject(result) 73 | } 74 | }).catch((err:Error)=>{ 75 | reject(err); 76 | promptAction.showToast({ 77 | message: `请求错误,地址:${HOST + url}${options.extraData &&',请求参数:'+ JSON.stringify(options.extraData)},错误信息: ${JSON.stringify(err)}`, 78 | duration: 2000, 79 | bottom: px2fp(display.getDefaultDisplaySync().height) / 2 80 | }); 81 | }).finally(()=>{ 82 | // 当该请求使用完毕时,调用destroy方法主动销毁。 83 | httpRequest.destroy(); 84 | }); 85 | }) 86 | } 87 | 88 | /** 89 | * @description: get请求函数 90 | * @param {string} url 请求地址 91 | * @param {Object} data 请求参数 92 | * @param {RequestConfig} OtherConfig request其他配置 93 | * @return {*} 94 | */ 95 | public get(url: string, data?: Object):Promise> { 96 | return this.request(url, { method: http.RequestMethod.GET, extraData: data }) 97 | } 98 | /** 99 | * @description: post请求函数 100 | * @param {string} url 请求地址 101 | * @param {Object} data 请求参数 102 | * @param {RequestConfig} OtherConfig request其他配置 103 | * @return {*} 104 | */ 105 | public post(url: string, data?: Object): Promise> { 106 | return this.request(url,{ method: http.RequestMethod.POST,extraData: data}) 107 | } 108 | 109 | /** 110 | * @description: delete请求函数 111 | * @param {string} url 请求地址 112 | * @param {Object} data 请求参数 113 | * @param {RequestConfig} OtherConfig request其他配置 114 | * @return {*} 115 | */ 116 | public delete(url: string, data?: Object): Promise> { 117 | return this.request(url,{ method: http.RequestMethod.DELETE,extraData: data}) 118 | } 119 | 120 | /** 121 | * @description: put请求函数 122 | * @param {string} url 请求地址 123 | * @param {Object} data 请求参数 124 | * @param {RequestConfig} OtherConfig request其他配置 125 | * @return {*} 126 | */ 127 | public put(url: string, data?: Object): Promise> { 128 | return this.request(url,{ method: http.RequestMethod.PUT,extraData: data}) 129 | } 130 | 131 | } 132 | 133 | export default HttpRequest.getInstance() -------------------------------------------------------------------------------- /entry/src/main/ets/utils/Lyric.ts: -------------------------------------------------------------------------------- 1 | const timeExp:RegExp = /\[(\d{2,}):(\d{2})(?:\.(\d{2,3}))?]/g 2 | 3 | enum STATUS { 4 | STATE_PAUSE = 0, 5 | STATE_PLAYING = 1 6 | } 7 | 8 | interface TagRegInterface { 9 | title?:string, 10 | artist?:string, 11 | album?:string, 12 | offset?:string, 13 | by?:string, 14 | } 15 | 16 | export interface LineInterface { 17 | time?:number, 18 | txt:string, 19 | lineNum?:number 20 | } 21 | 22 | const tagRegMap:TagRegInterface = { 23 | title: 'ti', 24 | artist: 'ar', 25 | album: 'al', 26 | offset: 'offset', 27 | by: 'by' 28 | } 29 | 30 | export default class Lyric { 31 | private lrc:string = ''; 32 | private tags:TagRegInterface = {}; 33 | public lines:Array = [] 34 | private state:STATUS = STATUS.STATE_PAUSE; 35 | private curLine:number = 0; 36 | private curNum:number = 0; 37 | private startStamp:number = 0; 38 | private timer:number = 0; 39 | private pauseStamp:number; 40 | private handler:(data:LineInterface) => void 41 | 42 | constructor(lrc:string, handlder:(data:LineInterface) => void) { 43 | this.lrc = lrc; 44 | this.handler = handlder; 45 | this._init(); 46 | } 47 | 48 | _init() { 49 | this._initTag() 50 | 51 | this._initLines() 52 | } 53 | 54 | _initTag() { 55 | for (let tag in tagRegMap) { 56 | const matches = this.lrc.match(new RegExp(`\\[${tagRegMap[tag]}:([^\\]]*)]`, 'i')) 57 | this.tags[tag] = matches && matches[1] || '' 58 | } 59 | } 60 | 61 | _initLines() { 62 | const lines:Array = this.lrc.split('\n') 63 | for (let i = 0; i < lines.length; i++) { 64 | const line = lines[i] 65 | let result:Array|null = timeExp.exec(line) 66 | if (result) { 67 | const txt = line.replace(timeExp, '').trim() 68 | if (txt) { 69 | this.lines.push({ 70 | time: parseInt(result[1]) * 60 * 1000 + parseInt(result[2]) * 1000 + (parseInt(result[3]) || 0) * 10, 71 | txt 72 | }) 73 | } 74 | } 75 | } 76 | 77 | this.lines.sort((a, b) => { 78 | return a.time - b.time 79 | }) 80 | } 81 | 82 | _findCurNum(time) { 83 | for (let i = 0; i < this.lines.length; i++) { 84 | if (time <= this.lines[i].time) { 85 | return i 86 | } 87 | } 88 | return this.lines.length - 1 89 | } 90 | 91 | _callHandler(i) { 92 | if (i < 0) { 93 | return 94 | } 95 | this.handler({ 96 | txt: this.lines[i].txt, 97 | lineNum: i 98 | }) 99 | } 100 | 101 | _playRest() { 102 | let line = this.lines[this.curNum] 103 | let delay = line.time - (+new Date() - this.startStamp) 104 | 105 | this.timer = setTimeout(() => { 106 | this._callHandler(this.curNum++) 107 | if (this.curNum < this.lines.length && this.state === STATUS.STATE_PLAYING) { 108 | this._playRest() 109 | } 110 | }, delay) 111 | } 112 | 113 | play(startTime:number = 0, skipLast:boolean = false) { 114 | if (!this.lines.length) { 115 | return 116 | } 117 | this.state = STATUS.STATE_PLAYING 118 | 119 | this.curNum = this._findCurNum(startTime) 120 | this.startStamp = +new Date() - startTime 121 | 122 | if (!skipLast) { 123 | this._callHandler(this.curNum - 1) 124 | } 125 | 126 | if (this.curNum < this.lines.length) { 127 | clearTimeout(this.timer) 128 | this._playRest() 129 | } 130 | } 131 | 132 | togglePlay() { 133 | const now:number = +new Date() 134 | if (this.state === STATUS.STATE_PLAYING) { 135 | this.stop() 136 | this.pauseStamp = now 137 | } else { 138 | this.state = STATUS.STATE_PLAYING 139 | this.play((this.pauseStamp || now) - (this.startStamp || now), true) 140 | this.pauseStamp = 0 141 | } 142 | } 143 | 144 | stop() { 145 | this.state =STATUS.STATE_PAUSE 146 | clearTimeout(this.timer) 147 | } 148 | 149 | seek(offset) { 150 | this.play(offset) 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /entry/src/main/ets/utils/PreferenceModel.ets: -------------------------------------------------------------------------------- 1 | import dataPreferences from "@ohos.data.preferences" 2 | 3 | let context = getContext(this) 4 | let preference: dataPreferences.Preferences = null 5 | 6 | class PreferenceModel { 7 | //初始化Preferences首选项 8 | async getPreferencesFromStorage() { 9 | try { 10 | preference = await dataPreferences.getPreferences(context, 'mystore') 11 | } catch (err) { 12 | console.error(err) 13 | } 14 | } 15 | 16 | //删除preferences实例对应的首选项 17 | async deletePreferences() { 18 | try { 19 | await dataPreferences.deletePreferences(context, 'mystore') 20 | } catch (err) { 21 | console.error(err) 22 | } 23 | preference = null 24 | } 25 | 26 | //设置key-value 27 | async putPreference(key:string,value:string) { 28 | if (preference === null) { 29 | await this.getPreferencesFromStorage() 30 | } 31 | try { 32 | await preference.put(key, value) 33 | } catch (err) { 34 | console.error(err) 35 | } 36 | await preference.flush() 37 | } 38 | 39 | //获取key对应的value 40 | async getPreference(key:string){ 41 | let value = "" 42 | if (preference === null) { 43 | await this.getPreferencesFromStorage() 44 | } 45 | try { 46 | value = await preference.get(key, null) 47 | } catch (err) { 48 | console.error(err) 49 | } 50 | return value; 51 | } 52 | 53 | //删除key对应的value 54 | async deletePreference(key:string) { 55 | try { 56 | await preference.delete(key) 57 | } catch (err) { 58 | console.error(err) 59 | } 60 | } 61 | 62 | //检查参数是否为null 63 | isNull(value: any) { 64 | if (value === null) { 65 | return false 66 | } 67 | return true 68 | } 69 | 70 | //获取date日期对应的浏览历史 71 | async getToken() { 72 | return 'eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MTk4NDE4NjUsInN1YiI6IntcImF2YXRlclwiOlwiL3N0YXRpYy91c2VyL2F2YXRlci_lkLTmgKjlkLTmgpQuanBnXCIsXCJiaXJ0aGRheVwiOlwiMTk5MC0xMC04XCIsXCJjcmVhdGVEYXRlXCI6MTU2NTcwMTMxNjAwMCxcImRpc2FibGVkXCI6MCxcImVtYWlsXCI6XCIyNzUwMTg3MjNAcXEuY29tXCIsXCJwZXJtaXNzaW9uXCI6MCxcInJvbGVcIjpcInB1YmxpY1wiLFwic2V4XCI6XCLnlLdcIixcInNpZ25cIjpcIuaXoOaAqO-8jOacieaClFwiLFwidGVsZXBob25lXCI6XCIxNTMwMjY4Njk0N1wiLFwidXBkYXRlRGF0ZVwiOjE1NjU3MDEzMjIwMDAsXCJ1c2VySWRcIjpcIuWQtOW_p-WQtOiZkVwiLFwidXNlcm5hbWVcIjpcIuWQtOW_p-WQtOiZkVwifSIsImV4cCI6MTcyMjQzMzg2NX0.GbEsgtlPl4SaN9ccE9L1EDlmHDZ3cyWyJbtqlsUas0E'; 73 | // let token = await this.getPreference('token') 74 | // return token ?? null 75 | } 76 | 77 | //写入date日期对应的浏览历史 78 | async setToke(token) { 79 | return this.putPreference('token',token) 80 | } 81 | 82 | //获取date日期对应的浏览历史 83 | async getPassword(userAccount:string) { 84 | let token = await this.getPreference(userAccount) 85 | return token ?? null 86 | } 87 | 88 | //写入date日期对应的浏览历史 89 | setPassword(userAccount:string,password:string) { 90 | this.putPreference(userAccount,password); 91 | } 92 | 93 | //获取date日期对应的浏览历史 94 | async getMovieSeachKeyWord():Promise> { 95 | let movieSearchKeyWord = await this.getPreference('movieSearchKeyWord'); 96 | if(movieSearchKeyWord){ 97 | return JSON.parse(movieSearchKeyWord) 98 | }else { 99 | return [] 100 | } 101 | } 102 | 103 | // 电影搜索记录 104 | async setMovieSeachKeyWord(keyWord):Promise> { 105 | const movieSearchKeyWord:Array = await this.getMovieSeachKeyWord(); 106 | const index = movieSearchKeyWord.findIndex(item => item === keyWord); 107 | if(index !== -1){ 108 | movieSearchKeyWord.splice(index,1) 109 | } 110 | movieSearchKeyWord.unshift(keyWord); 111 | // 最多只存十条记录 112 | if(movieSearchKeyWord.length > 10)movieSearchKeyWord.splice(10,movieSearchKeyWord.length - 10) 113 | return movieSearchKeyWord; 114 | } 115 | } 116 | 117 | export default new PreferenceModel() -------------------------------------------------------------------------------- /entry/src/main/ets/utils/common.ets: -------------------------------------------------------------------------------- 1 | import {HOST} from '../common/constant'; 2 | import router from '@ohos.router'; 3 | 4 | export const zerofull=(value:number):string|number=>{ 5 | return value < 10 ? "0" + value : value + '' 6 | } 7 | 8 | export const formatTime=(value:string|number):string=>{ 9 | var date =new Date(typeof value === 'string' ? value.replace(/T/,' ') : value); 10 | var nowDate = new Date() 11 | let diff = Math.ceil((nowDate.getTime()-date.getTime())/1000); 12 | if(diff < 60){ 13 | return "刚刚"; 14 | }else if(diff < 60*60){ 15 | return Math.ceil(diff/60) + "分前"; 16 | }else if(diff < 60*60*24){ 17 | return Math.ceil(diff/(60*60))+"小时前"; 18 | }else if(diff < 60*60*24*30){ 19 | return Math.ceil(diff/(60*60*24))+"天前"; 20 | }else if(diff < 60*60*24*30*12){ 21 | return Math.ceil(diff/(60*60*24*30))+"个月前"; 22 | } 23 | const year = zerofull(date.getFullYear()); 24 | const month = zerofull(date.getMonth()+1); 25 | const dates = zerofull(date.getDate()); 26 | const hour = zerofull(date.getHours()); 27 | const minutes = zerofull(date.getMinutes()); 28 | const seconds = zerofull(date.getSeconds()); 29 | return `${year}-${month}-${dates} ${hour}:${minutes}:${seconds}` 30 | }; 31 | 32 | export const formatSecond=(value:number,showHour:boolean = false):string => { 33 | if(showHour){ 34 | return `${zerofull(Math.floor(value / (60 * 60)))}:${zerofull(Math.floor(value % (60 * 60) / 60))}:${zerofull(Math.floor(value % (60 * 60) % 60))}` 35 | }else{ 36 | return `${zerofull(Math.floor(value / 60))}:${zerofull(Math.floor(value % 60))}` 37 | } 38 | }; 39 | 40 | export const getMusicCover = (cover:string) => /http[s]?:\/\//.test(cover) ? cover.replace('{size}', '480') : HOST + cover 41 | 42 | export const strictEmailRegex = /^[a-zA-Z0-9]+([._%+-][a-zA-Z0-9]+)*@([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,6}$/; -------------------------------------------------------------------------------- /entry/src/main/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry", 4 | "type": "entry", 5 | "description": "$string:module_desc", 6 | "mainElement": "EntryAbility", 7 | "deviceTypes": [ 8 | "phone", 9 | "tablet" 10 | ], 11 | "deliveryWithInstall": true, 12 | "installationFree": false, 13 | "pages": "$profile:main_pages", 14 | "abilities": [ 15 | { 16 | "name": "EntryAbility", 17 | "srcEntry": "./ets/entryability/EntryAbility.ts", 18 | "description": "$string:EntryAbility_desc", 19 | "icon": "$media:icon", 20 | "label": "$string:EntryAbility_label", 21 | "startWindowIcon": "$media:icon", 22 | "startWindowBackground": "$color:start_window_background", 23 | "exported": true, 24 | "skills": [ 25 | { 26 | "entities": [ 27 | "entity.system.home" 28 | ], 29 | "actions": [ 30 | "action.system.home" 31 | ] 32 | } 33 | ] 34 | } 35 | ], 36 | "requestPermissions": [ 37 | { 38 | "name": "ohos.permission.INTERNET" 39 | } 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | { 4 | "name": "start_window_background", 5 | "value": "#FFFFFF" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "module description" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "movie" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/default_avater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/default_avater.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/default_cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/default_cover.jpg -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_add.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_app.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_arrow.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_avater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_avater.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_back.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_classify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_classify.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_clear.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_close.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_collection.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_collection_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_collection_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_comment.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_comment_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_comment_white.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_delete.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_detail_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_detail_play.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_down.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_edit.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_empty_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_empty_star.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_favorite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_favorite.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_full_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_full_star.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_half_star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_half_star.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_history.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_home.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_home_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_home_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_hot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_hot.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_like.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_like_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_like_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_like_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_like_white.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_logo.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_menu_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_menu_add.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_menu_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_menu_board.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_menu_collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_menu_collect.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_menu_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_menu_history.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_menu_like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_menu_like.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_movie.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_movie_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_movie_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_add.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_circle.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_circle_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_circle_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_classics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_classics.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_classify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_classify.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_collect.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_comments.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_default_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_default_cover.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_down.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_like.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_loop.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_menu.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_next.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_order.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_play.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_play_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_play_menu.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_play_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_play_white.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_playing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_playing.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_playing_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_playing_grey.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_prev.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_random.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_rank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_rank.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_singer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_singer.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_music_white_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_music_white_menu.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_no1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_no1.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_no2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_no2.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_no3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_no3.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_password.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_permission.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_play.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_play_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_play_record.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_recomment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_recomment.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_recomment_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_recomment_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_record.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_search.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_share.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_share_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_share_music.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_song_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_song_default.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_talk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_talk.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_top.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_tv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_tv.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_tv_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_tv_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_user.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/media/icon_user_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/main/resources/base/media/icon_user_active.png -------------------------------------------------------------------------------- /entry/src/main/resources/base/profile/main_pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": [ 3 | "pages/LaunchPage", 4 | "pages/UserPage", 5 | "pages/LoginPage", 6 | "pages/RegisterPage", 7 | "pages/ForgetPasswordPage", 8 | "pages/ResetPasswordPage", 9 | "pages/UpdatePasswordPage", 10 | "pages/IndexPage", 11 | "pages/MovieDetailPage", 12 | "pages/MoviePlayPage", 13 | "pages/MovieUserPage", 14 | "pages/MovieSearchPage" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /entry/src/main/resources/en_US/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "module description" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "label" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /entry/src/main/resources/zh_CN/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_desc", 5 | "value": "模块描述" 6 | }, 7 | { 8 | "name": "EntryAbility_desc", 9 | "value": "description" 10 | }, 11 | { 12 | "name": "EntryAbility_label", 13 | "value": "label" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/TestAbility/TestAbility.ets: -------------------------------------------------------------------------------- 1 | import UIAbility from '@ohos.app.ability.UIAbility'; 2 | import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; 3 | import hilog from '@ohos.hilog'; 4 | import { Hypium } from '@ohos/hypium'; 5 | import testsuite from '../test/List.test'; 6 | import window from '@ohos.window'; 7 | 8 | export default class TestAbility extends UIAbility { 9 | onCreate(want, launchParam) { 10 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate'); 11 | hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? ''); 12 | hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? ''); 13 | var abilityDelegator: any 14 | abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() 15 | var abilityDelegatorArguments: any 16 | abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() 17 | hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!'); 18 | Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite) 19 | } 20 | 21 | onDestroy() { 22 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy'); 23 | } 24 | 25 | onWindowStageCreate(windowStage: window.WindowStage) { 26 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate'); 27 | windowStage.loadContent('testability/pages/Index', (err, data) => { 28 | if (err.code) { 29 | hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); 30 | return; 31 | } 32 | hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', 33 | JSON.stringify(data) ?? ''); 34 | }); 35 | } 36 | 37 | onWindowStageDestroy() { 38 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy'); 39 | } 40 | 41 | onForeground() { 42 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground'); 43 | } 44 | 45 | onBackground() { 46 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground'); 47 | } 48 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/TestAbility/pages/index.ets: -------------------------------------------------------------------------------- 1 | import hilog from '@ohos.hilog'; 2 | 3 | @Entry 4 | @Component 5 | struct Index { 6 | aboutToAppear() { 7 | hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear'); 8 | } 9 | @State message: string = 'Hello World' 10 | build() { 11 | Row() { 12 | Column() { 13 | Text(this.message) 14 | .fontSize(50) 15 | .fontWeight(FontWeight.Bold) 16 | Button() { 17 | Text('next page') 18 | .fontSize(20) 19 | .fontWeight(FontWeight.Bold) 20 | }.type(ButtonType.Capsule) 21 | .margin({ 22 | top: 20 23 | }) 24 | .backgroundColor('#0D9FFB') 25 | .width('35%') 26 | .height('5%') 27 | .onClick(()=>{ 28 | }) 29 | } 30 | .width('100%') 31 | } 32 | .height('100%') 33 | } 34 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/TestRunner/OpenHarmonyTestRunner.ts: -------------------------------------------------------------------------------- 1 | import hilog from '@ohos.hilog'; 2 | import TestRunner from '@ohos.application.testRunner'; 3 | import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry'; 4 | 5 | var abilityDelegator = undefined 6 | var abilityDelegatorArguments = undefined 7 | 8 | async function onAbilityCreateCallback() { 9 | hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback'); 10 | } 11 | 12 | async function addAbilityMonitorCallback(err: any) { 13 | hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? ''); 14 | } 15 | 16 | export default class OpenHarmonyTestRunner implements TestRunner { 17 | constructor() { 18 | } 19 | 20 | onPrepare() { 21 | hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare '); 22 | } 23 | 24 | async onRun() { 25 | hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run'); 26 | abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments() 27 | abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator() 28 | var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility' 29 | let lMonitor = { 30 | abilityName: testAbilityName, 31 | onAbilityCreate: onAbilityCreateCallback, 32 | }; 33 | abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback) 34 | var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName 35 | var debug = abilityDelegatorArguments.parameters['-D'] 36 | if (debug == 'true') 37 | { 38 | cmd += ' -D' 39 | } 40 | hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd); 41 | abilityDelegator.executeShellCommand(cmd, 42 | (err: any, d: any) => { 43 | hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? ''); 44 | hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? ''); 45 | hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? ''); 46 | }) 47 | hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end'); 48 | } 49 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/Ability.test.ets: -------------------------------------------------------------------------------- 1 | import hilog from '@ohos.hilog'; 2 | import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium' 3 | 4 | export default function abilityTest() { 5 | describe('ActsAbilityTest', function () { 6 | // Defines a test suite. Two parameters are supported: test suite name and test suite function. 7 | beforeAll(function () { 8 | // Presets an action, which is performed only once before all test cases of the test suite start. 9 | // This API supports only one parameter: preset action function. 10 | }) 11 | beforeEach(function () { 12 | // Presets an action, which is performed before each unit test case starts. 13 | // The number of execution times is the same as the number of test cases defined by **it**. 14 | // This API supports only one parameter: preset action function. 15 | }) 16 | afterEach(function () { 17 | // Presets a clear action, which is performed after each unit test case ends. 18 | // The number of execution times is the same as the number of test cases defined by **it**. 19 | // This API supports only one parameter: clear action function. 20 | }) 21 | afterAll(function () { 22 | // Presets a clear action, which is performed after all test cases of the test suite end. 23 | // This API supports only one parameter: clear action function. 24 | }) 25 | it('assertContain',0, function () { 26 | // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. 27 | hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); 28 | let a = 'abc' 29 | let b = 'b' 30 | // Defines a variety of assertion methods, which are used to declare expected boolean conditions. 31 | expect(a).assertContain(b) 32 | expect(a).assertEqual(a) 33 | }) 34 | }) 35 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/ets/test/List.test.ets: -------------------------------------------------------------------------------- 1 | import abilityTest from './Ability.test' 2 | 3 | export default function testsuite() { 4 | abilityTest() 5 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/module.json5: -------------------------------------------------------------------------------- 1 | { 2 | "module": { 3 | "name": "entry_test", 4 | "type": "feature", 5 | "description": "$string:module_test_desc", 6 | "mainElement": "TestAbility", 7 | "deviceTypes": [ 8 | "phone", 9 | "tablet" 10 | ], 11 | "deliveryWithInstall": true, 12 | "installationFree": false, 13 | "pages": "$profile:test_pages", 14 | "abilities": [ 15 | { 16 | "name": "TestAbility", 17 | "srcEntry": "./ets/testability/TestAbility.ets", 18 | "description": "$string:TestAbility_desc", 19 | "icon": "$media:icon", 20 | "label": "$string:TestAbility_label", 21 | "exported": true, 22 | "startWindowIcon": "$media:icon", 23 | "startWindowBackground": "$color:start_window_background", 24 | "skills": [ 25 | { 26 | "actions": [ 27 | "action.system.home" 28 | ], 29 | "entities": [ 30 | "entity.system.home" 31 | ] 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /entry/src/ohosTest/resources/base/element/color.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": [ 3 | { 4 | "name": "start_window_background", 5 | "value": "#FFFFFF" 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/resources/base/element/string.json: -------------------------------------------------------------------------------- 1 | { 2 | "string": [ 3 | { 4 | "name": "module_test_desc", 5 | "value": "test ability description" 6 | }, 7 | { 8 | "name": "TestAbility_desc", 9 | "value": "the test ability" 10 | }, 11 | { 12 | "name": "TestAbility_label", 13 | "value": "test label" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /entry/src/ohosTest/resources/base/media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/entry/src/ohosTest/resources/base/media/icon.png -------------------------------------------------------------------------------- /entry/src/ohosTest/resources/base/profile/test_pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "src": [ 3 | "testability/pages/Index" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /hvigor/hvigor-config.json5: -------------------------------------------------------------------------------- 1 | { 2 | "hvigorVersion": "2.4.2", 3 | "dependencies": { 4 | "@ohos/hvigor-ohos-plugin": "2.4.2" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /hvigorfile.ts: -------------------------------------------------------------------------------- 1 | // Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. 2 | export { appTasks } from '@ohos/hvigor-ohos-plugin'; -------------------------------------------------------------------------------- /hvigorw: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ---------------------------------------------------------------------------- 4 | # Hvigor startup script, version 1.0.0 5 | # 6 | # Required ENV vars: 7 | # ------------------ 8 | # NODE_HOME - location of a Node home dir 9 | # or 10 | # Add /usr/local/nodejs/bin to the PATH environment variable 11 | # ---------------------------------------------------------------------------- 12 | 13 | HVIGOR_APP_HOME=$(dirname $(readlink -f $0)) 14 | HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js 15 | warn() { 16 | echo "" 17 | echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" 18 | } 19 | 20 | error() { 21 | echo "" 22 | echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m" 23 | } 24 | 25 | fail() { 26 | error "$@" 27 | exit 1 28 | } 29 | 30 | # Determine node to start hvigor wrapper script 31 | if [ -n "${NODE_HOME}" ];then 32 | EXECUTABLE_NODE="${NODE_HOME}/bin/node" 33 | if [ ! -x "$EXECUTABLE_NODE" ];then 34 | fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed" 35 | fi 36 | else 37 | EXECUTABLE_NODE="node" 38 | which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path" 39 | fi 40 | 41 | # Check hvigor wrapper script 42 | if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then 43 | fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}" 44 | fi 45 | 46 | # start hvigor-wrapper script 47 | exec "${EXECUTABLE_NODE}" \ 48 | "${HVIGOR_WRAPPER_SCRIPT}" "$@" 49 | -------------------------------------------------------------------------------- /hvigorw.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Hvigor startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 17 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 18 | 19 | set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js 20 | set NODE_EXE=node.exe 21 | 22 | goto start 23 | 24 | :start 25 | @rem Find node.exe 26 | if defined NODE_HOME goto findNodeFromNodeHome 27 | 28 | %NODE_EXE% --version >NUL 2>&1 29 | if "%ERRORLEVEL%" == "0" goto execute 30 | 31 | echo. 32 | echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. 33 | echo. 34 | echo Please set the NODE_HOME variable in your environment to match the 35 | echo location of your NodeJs installation. 36 | 37 | goto fail 38 | 39 | :findNodeFromNodeHome 40 | set NODE_HOME=%NODE_HOME:"=% 41 | set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE% 42 | 43 | if exist "%NODE_EXE_PATH%" goto execute 44 | echo. 45 | echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH. 46 | echo. 47 | echo Please set the NODE_HOME variable in your environment to match the 48 | echo location of your NodeJs installation. 49 | 50 | goto fail 51 | 52 | :execute 53 | @rem Execute hvigor 54 | "%NODE_EXE%" %WRAPPER_MODULE_PATH% %* 55 | 56 | if "%ERRORLEVEL%" == "0" goto hvigorwEnd 57 | 58 | :fail 59 | exit /b 1 60 | 61 | :hvigorwEnd 62 | if "%OS%" == "Windows_NT" endlocal 63 | 64 | :end 65 | -------------------------------------------------------------------------------- /oh-package-lock.json5: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", 4 | "specifiers": { 5 | "@ohos/hypium@1.0.6": "@ohos/hypium@1.0.6" 6 | }, 7 | "packages": { 8 | "@ohos/hypium@1.0.6": { 9 | "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.6.tgz", 10 | "integrity": "sha512-bb3DWeWhYrFqj9mPFV3yZQpkm36kbcK+YYaeY9g292QKSjOdmhEIQR2ULPvyMsgSR4usOBf5nnYrDmaCCXirgQ==" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /oh-package.json5: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myapplication", 3 | "version": "1.0.0", 4 | "description": "Please describe the basic information.", 5 | "main": "", 6 | "author": "", 7 | "license": "", 8 | "dependencies": { 9 | }, 10 | "devDependencies": { 11 | "@ohos/hypium": "1.0.6" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /一键提交到gitee.bat: -------------------------------------------------------------------------------- 1 | git remote rm origin 2 | git remote add origin https://gitee.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui.git 3 | git push origin master 4 | pause -------------------------------------------------------------------------------- /一键提交到github.bat: -------------------------------------------------------------------------------- 1 | git remote rm origin 2 | git remote add origin https://github.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui.git 3 | git push origin master 4 | pause -------------------------------------------------------------------------------- /外网映射正常访问提示.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/外网映射正常访问提示.png -------------------------------------------------------------------------------- /实际效果预览.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/实际效果预览.png -------------------------------------------------------------------------------- /新版电影APP整体预览图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/新版电影APP整体预览图.jpg -------------------------------------------------------------------------------- /更改用户信息1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/更改用户信息1.png -------------------------------------------------------------------------------- /更改用户信息2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/更改用户信息2.png -------------------------------------------------------------------------------- /更改用户信息3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/更改用户信息3.png -------------------------------------------------------------------------------- /更改用户信息4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/更改用户信息4.png -------------------------------------------------------------------------------- /用户信息.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/用户信息.png -------------------------------------------------------------------------------- /电影app整体预览.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影app整体预览.jpg -------------------------------------------------------------------------------- /电影app整体预览2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影app整体预览2.jpg -------------------------------------------------------------------------------- /电影预览1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览1.png -------------------------------------------------------------------------------- /电影预览10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览10.png -------------------------------------------------------------------------------- /电影预览11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览11.png -------------------------------------------------------------------------------- /电影预览13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览13.jpg -------------------------------------------------------------------------------- /电影预览14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览14.jpg -------------------------------------------------------------------------------- /电影预览16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览16.png -------------------------------------------------------------------------------- /电影预览2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览2.png -------------------------------------------------------------------------------- /电影预览3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览3.png -------------------------------------------------------------------------------- /电影预览4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览4.png -------------------------------------------------------------------------------- /电影预览6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览6.png -------------------------------------------------------------------------------- /电影预览7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览7.png -------------------------------------------------------------------------------- /电影预览8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/电影预览8.png -------------------------------------------------------------------------------- /登录.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyuanwuhui99/Harmony-arkts-movie-music-app-ui/d5e9bebe1dca2759cba417d2b6b402941d3bc273/登录.png --------------------------------------------------------------------------------