Repository: nanbouking/WeTravel Branch: master Commit: 3d07a91e98bc Files: 509 Total size: 1.3 MB Directory structure: gitextract_4tbgnvos/ ├── .gitignore ├── README.md ├── cloudfunctions/ │ └── mcloud/ │ ├── config/ │ │ └── config.js │ ├── config.json │ ├── framework/ │ │ ├── cloud/ │ │ │ ├── cloud_base.js │ │ │ └── cloud_util.js │ │ ├── core/ │ │ │ ├── app_code.js │ │ │ ├── app_error.js │ │ │ ├── app_other.js │ │ │ ├── app_util.js │ │ │ └── application.js │ │ ├── database/ │ │ │ ├── db_util.js │ │ │ ├── model.js │ │ │ └── multi_model.js │ │ ├── lib/ │ │ │ ├── faker_lib.js │ │ │ ├── md5_lib.js │ │ │ └── mini_lib.js │ │ ├── platform/ │ │ │ ├── controller/ │ │ │ │ ├── base_admin_controller.js │ │ │ │ └── base_controller.js │ │ │ ├── model/ │ │ │ │ ├── admin_model.js │ │ │ │ ├── base_model.js │ │ │ │ └── log_model.js │ │ │ └── service/ │ │ │ ├── base_admin_service.js │ │ │ └── base_service.js │ │ ├── utils/ │ │ │ ├── constant.js │ │ │ ├── data_util.js │ │ │ ├── export_util.js │ │ │ ├── log_util.js │ │ │ ├── math_util.js │ │ │ ├── setup/ │ │ │ │ ├── setup_model.js │ │ │ │ └── setup_util.js │ │ │ ├── time_util.js │ │ │ └── util.js │ │ └── validate/ │ │ ├── content_check.js │ │ └── data_check.js │ ├── index.js │ ├── package.json │ └── project/ │ └── TRIP1/ │ ├── controller/ │ │ ├── admin/ │ │ │ ├── admin_album_controller.js │ │ │ ├── admin_home_controller.js │ │ │ ├── admin_meet_controller.js │ │ │ ├── admin_mgr_controller.js │ │ │ ├── admin_news_controller.js │ │ │ ├── admin_product_controller.js │ │ │ ├── admin_setup_controller.js │ │ │ ├── admin_user_controller.js │ │ │ └── base_project_admin_controller.js │ │ ├── album_controller.js │ │ ├── base_project_controller.js │ │ ├── check_controller.js │ │ ├── fav_controller.js │ │ ├── home_controller.js │ │ ├── meet_controller.js │ │ ├── my_controller.js │ │ ├── news_controller.js │ │ ├── passport_controller.js │ │ ├── product_controller.js │ │ └── test/ │ │ └── test_controller.js │ ├── model/ │ │ ├── album_model.js │ │ ├── base_project_model.js │ │ ├── day_model.js │ │ ├── fav_model.js │ │ ├── join_model.js │ │ ├── meet_model.js │ │ ├── news_model.js │ │ ├── product_model.js │ │ └── user_model.js │ ├── public/ │ │ ├── constants.js │ │ ├── project_config.js │ │ └── route.js │ └── service/ │ ├── admin/ │ │ ├── admin_album_service.js │ │ ├── admin_home_service.js │ │ ├── admin_meet_service.js │ │ ├── admin_mgr_service.js │ │ ├── admin_news_service.js │ │ ├── admin_product_service.js │ │ ├── admin_setup_service.js │ │ ├── admin_user_service.js │ │ └── base_project_admin_service.js │ ├── album_service.js │ ├── base_project_service.js │ ├── fav_service.js │ ├── home_service.js │ ├── meet_service.js │ ├── news_service.js │ ├── passport_service.js │ └── product_service.js ├── miniprogram/ │ ├── app.js │ ├── app.json │ ├── app.wxss │ ├── cmpts/ │ │ ├── biz/ │ │ │ ├── detail/ │ │ │ │ ├── detail_cmpt.js │ │ │ │ ├── detail_cmpt.json │ │ │ │ ├── detail_cmpt.wxml │ │ │ │ └── detail_cmpt.wxss │ │ │ └── foot/ │ │ │ ├── foot_cmpt.js │ │ │ ├── foot_cmpt.json │ │ │ ├── foot_cmpt.wxml │ │ │ └── foot_cmpt.wxss │ │ └── public/ │ │ ├── calendar/ │ │ │ ├── calendar_comm/ │ │ │ │ ├── calendar_comm_cmpt.js │ │ │ │ ├── calendar_comm_cmpt.json │ │ │ │ ├── calendar_comm_cmpt.wxml │ │ │ │ ├── calendar_comm_cmpt.wxss │ │ │ │ └── din.wxss │ │ │ ├── calendar_lib.js │ │ │ ├── calendar_meet/ │ │ │ │ ├── calendar_meet_cmpt.js │ │ │ │ ├── calendar_meet_cmpt.json │ │ │ │ ├── calendar_meet_cmpt.wxml │ │ │ │ └── calendar_meet_cmpt.wxss │ │ │ ├── date_select/ │ │ │ │ ├── date_select_cmpt.js │ │ │ │ ├── date_select_cmpt.json │ │ │ │ ├── date_select_cmpt.wxml │ │ │ │ └── date_select_cmpt.wxss │ │ │ └── time_select/ │ │ │ ├── time_select_cmpt.js │ │ │ ├── time_select_cmpt.json │ │ │ ├── time_select_cmpt.wxml │ │ │ └── time_select_cmpt.wxss │ │ ├── checkbox/ │ │ │ ├── checkbox_cmpt.js │ │ │ ├── checkbox_cmpt.json │ │ │ ├── checkbox_cmpt.wxml │ │ │ └── checkbox_cmpt.wxss │ │ ├── editor/ │ │ │ ├── editor_cmpt.js │ │ │ ├── editor_cmpt.json │ │ │ ├── editor_cmpt.wxml │ │ │ └── editor_cmpt.wxss │ │ ├── form/ │ │ │ ├── form_set/ │ │ │ │ ├── field/ │ │ │ │ │ ├── form_set_field.js │ │ │ │ │ ├── form_set_field.json │ │ │ │ │ ├── form_set_field.wxml │ │ │ │ │ └── form_set_field.wxss │ │ │ │ ├── form_set_cmpt.js │ │ │ │ ├── form_set_cmpt.json │ │ │ │ ├── form_set_cmpt.wxml │ │ │ │ └── form_set_cmpt.wxss │ │ │ ├── form_set_helper.js │ │ │ └── form_show/ │ │ │ ├── content/ │ │ │ │ ├── form_show_content.js │ │ │ │ ├── form_show_content.json │ │ │ │ ├── form_show_content.wxml │ │ │ │ └── form_show_content.wxss │ │ │ ├── form_show_cmpt.js │ │ │ ├── form_show_cmpt.json │ │ │ ├── form_show_cmpt.wxml │ │ │ └── form_show_cmpt.wxss │ │ ├── img/ │ │ │ ├── img_upload_cmpt.js │ │ │ ├── img_upload_cmpt.json │ │ │ ├── img_upload_cmpt.wxml │ │ │ └── img_upload_cmpt.wxss │ │ ├── list/ │ │ │ ├── comm_list_cmpt.js │ │ │ ├── comm_list_cmpt.json │ │ │ ├── comm_list_cmpt.wxml │ │ │ └── comm_list_cmpt.wxss │ │ ├── modal/ │ │ │ ├── modal_cmpt.js │ │ │ ├── modal_cmpt.json │ │ │ ├── modal_cmpt.wxml │ │ │ └── modal_cmpt.wxss │ │ ├── picker/ │ │ │ ├── picker_cmpt.js │ │ │ ├── picker_cmpt.json │ │ │ ├── picker_cmpt.wxml │ │ │ └── picker_cmpt.wxss │ │ ├── picker_multi/ │ │ │ ├── picker_multi_cmpt.js │ │ │ ├── picker_multi_cmpt.json │ │ │ ├── picker_multi_cmpt.wxml │ │ │ └── picker_multi_cmpt.wxss │ │ ├── picker_time/ │ │ │ ├── datetime_picker.js │ │ │ ├── picker_time_cmpt.js │ │ │ ├── picker_time_cmpt.json │ │ │ ├── picker_time_cmpt.wxml │ │ │ └── picker_time_cmpt.wxss │ │ ├── poster/ │ │ │ ├── poster_cmpt.js │ │ │ ├── poster_cmpt.json │ │ │ ├── poster_cmpt.wxml │ │ │ ├── poster_cmpt.wxss │ │ │ ├── poster_cmpt_helper.js │ │ │ └── wxa-plugin-canvas/ │ │ │ ├── index/ │ │ │ │ ├── index.js │ │ │ │ ├── index.json │ │ │ │ ├── index.wxml │ │ │ │ └── index.wxss │ │ │ └── poster/ │ │ │ ├── index.js │ │ │ ├── index.json │ │ │ ├── index.wxml │ │ │ ├── index.wxss │ │ │ └── poster.js │ │ ├── radio/ │ │ │ ├── radio_cmpt.js │ │ │ ├── radio_cmpt.json │ │ │ ├── radio_cmpt.wxml │ │ │ └── radio_cmpt.wxss │ │ ├── swiper/ │ │ │ ├── swiper_cmpt.js │ │ │ ├── swiper_cmpt.json │ │ │ ├── swiper_cmpt.wxml │ │ │ └── swiper_cmpt.wxss │ │ └── table/ │ │ ├── table_cmpt.js │ │ ├── table_cmpt.json │ │ ├── table_cmpt.wxml │ │ └── table_cmpt.wxss │ ├── comm/ │ │ ├── behavior/ │ │ │ ├── about_bh.js │ │ │ ├── my_fav_bh.js │ │ │ ├── my_foot_bh.js │ │ │ ├── news_index_bh.js │ │ │ └── search_bh.js │ │ ├── biz/ │ │ │ ├── admin_biz.js │ │ │ ├── base_biz.js │ │ │ ├── fav_biz.js │ │ │ ├── foot_biz.js │ │ │ ├── passport_biz.js │ │ │ ├── public_biz.js │ │ │ └── search_biz.js │ │ └── constants.js │ ├── helper/ │ │ ├── cache_helper.js │ │ ├── cloud_helper.js │ │ ├── content_check_helper.js │ │ ├── data_helper.js │ │ ├── file_helper.js │ │ ├── form_helper.js │ │ ├── helper.js │ │ ├── mini_helper.js │ │ ├── page_helper.js │ │ ├── pic_helper.js │ │ ├── time_helper.js │ │ └── validate.js │ ├── lib/ │ │ └── tools/ │ │ ├── base64_lib.js │ │ ├── lunar_lib.js │ │ └── qrcode_lib.js │ ├── pages/ │ │ └── test1/ │ │ ├── test1.js │ │ └── test1.wxml │ ├── projects/ │ │ └── TRIP1/ │ │ ├── biz/ │ │ │ ├── admin_album_biz.js │ │ │ ├── admin_meet_biz.js │ │ │ ├── admin_news_biz.js │ │ │ ├── admin_product_biz.js │ │ │ ├── album_biz.js │ │ │ ├── meet_biz.js │ │ │ ├── news_biz.js │ │ │ ├── product_biz.js │ │ │ └── project_biz.js │ │ ├── pages/ │ │ │ ├── about/ │ │ │ │ ├── index/ │ │ │ │ │ ├── about_index.js │ │ │ │ │ ├── about_index.json │ │ │ │ │ ├── about_index.wxml │ │ │ │ │ └── about_index.wxss │ │ │ │ └── service/ │ │ │ │ ├── about_service.js │ │ │ │ ├── about_service.json │ │ │ │ ├── about_service.wxml │ │ │ │ └── about_service.wxss │ │ │ ├── admin/ │ │ │ │ ├── album/ │ │ │ │ │ ├── add/ │ │ │ │ │ │ ├── admin_album_add.js │ │ │ │ │ │ ├── admin_album_add.json │ │ │ │ │ │ ├── admin_album_add.wxml │ │ │ │ │ │ └── admin_album_add.wxss │ │ │ │ │ ├── admin_album_form_tpl.wxml │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── admin_album_edit.js │ │ │ │ │ │ ├── admin_album_edit.json │ │ │ │ │ │ ├── admin_album_edit.wxml │ │ │ │ │ │ └── admin_album_edit.wxss │ │ │ │ │ └── list/ │ │ │ │ │ ├── admin_album_list.js │ │ │ │ │ ├── admin_album_list.json │ │ │ │ │ ├── admin_album_list.wxml │ │ │ │ │ └── admin_album_list.wxss │ │ │ │ ├── content/ │ │ │ │ │ ├── admin_content.js │ │ │ │ │ ├── admin_content.json │ │ │ │ │ ├── admin_content.wxml │ │ │ │ │ └── admin_content.wxss │ │ │ │ ├── index/ │ │ │ │ │ ├── home/ │ │ │ │ │ │ ├── admin_home.js │ │ │ │ │ │ ├── admin_home.json │ │ │ │ │ │ ├── admin_home.wxml │ │ │ │ │ │ └── admin_home.wxss │ │ │ │ │ └── login/ │ │ │ │ │ ├── admin_login.js │ │ │ │ │ ├── admin_login.json │ │ │ │ │ ├── admin_login.wxml │ │ │ │ │ └── admin_login.wxss │ │ │ │ ├── meet/ │ │ │ │ │ ├── cover/ │ │ │ │ │ │ ├── admin_meet_cover.js │ │ │ │ │ │ ├── admin_meet_cover.json │ │ │ │ │ │ ├── admin_meet_cover.wxml │ │ │ │ │ │ └── admin_meet_cover.wxss │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── admin_meet_edit.js │ │ │ │ │ │ ├── admin_meet_edit.json │ │ │ │ │ │ ├── admin_meet_edit.wxml │ │ │ │ │ │ └── admin_meet_edit.wxss │ │ │ │ │ ├── export/ │ │ │ │ │ │ ├── admin_join_export.js │ │ │ │ │ │ ├── admin_join_export.json │ │ │ │ │ │ ├── admin_join_export.wxml │ │ │ │ │ │ └── admin_join_export.wxss │ │ │ │ │ ├── join/ │ │ │ │ │ │ ├── admin_meet_join.js │ │ │ │ │ │ ├── admin_meet_join.json │ │ │ │ │ │ ├── admin_meet_join.wxml │ │ │ │ │ │ └── admin_meet_join.wxss │ │ │ │ │ ├── list/ │ │ │ │ │ │ ├── admin_meet_list.js │ │ │ │ │ │ ├── admin_meet_list.json │ │ │ │ │ │ ├── admin_meet_list.wxml │ │ │ │ │ │ └── admin_meet_list.wxss │ │ │ │ │ ├── record/ │ │ │ │ │ │ ├── admin_record_list.js │ │ │ │ │ │ ├── admin_record_list.json │ │ │ │ │ │ ├── admin_record_list.wxml │ │ │ │ │ │ └── admin_record_list.wxss │ │ │ │ │ ├── scan/ │ │ │ │ │ │ ├── admin_meet_scan.js │ │ │ │ │ │ ├── admin_meet_scan.json │ │ │ │ │ │ ├── admin_meet_scan.wxml │ │ │ │ │ │ └── admin_meet_scan.wxss │ │ │ │ │ ├── self/ │ │ │ │ │ │ ├── admin_meet_self.js │ │ │ │ │ │ ├── admin_meet_self.json │ │ │ │ │ │ ├── admin_meet_self.wxml │ │ │ │ │ │ └── admin_meet_self.wxss │ │ │ │ │ ├── temp/ │ │ │ │ │ │ ├── admin_temp_select.js │ │ │ │ │ │ ├── admin_temp_select.json │ │ │ │ │ │ ├── admin_temp_select.wxml │ │ │ │ │ │ └── admin_temp_select.wxss │ │ │ │ │ └── time/ │ │ │ │ │ ├── admin_meet_time.js │ │ │ │ │ ├── admin_meet_time.json │ │ │ │ │ ├── admin_meet_time.wxml │ │ │ │ │ └── admin_meet_time.wxss │ │ │ │ ├── mgr/ │ │ │ │ │ ├── add/ │ │ │ │ │ │ ├── admin_mgr_add.js │ │ │ │ │ │ ├── admin_mgr_add.json │ │ │ │ │ │ ├── admin_mgr_add.wxml │ │ │ │ │ │ └── admin_mgr_add.wxss │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── admin_mgr_edit.js │ │ │ │ │ │ ├── admin_mgr_edit.json │ │ │ │ │ │ ├── admin_mgr_edit.wxml │ │ │ │ │ │ └── admin_mgr_edit.wxss │ │ │ │ │ ├── list/ │ │ │ │ │ │ ├── admin_mgr_list.js │ │ │ │ │ │ ├── admin_mgr_list.json │ │ │ │ │ │ ├── admin_mgr_list.wxml │ │ │ │ │ │ └── admin_mgr_list.wxss │ │ │ │ │ ├── log/ │ │ │ │ │ │ ├── admin_log_list.js │ │ │ │ │ │ ├── admin_log_list.json │ │ │ │ │ │ ├── admin_log_list.wxml │ │ │ │ │ │ └── admin_log_list.wxss │ │ │ │ │ └── pwd/ │ │ │ │ │ ├── admin_mgr_pwd.js │ │ │ │ │ ├── admin_mgr_pwd.json │ │ │ │ │ ├── admin_mgr_pwd.wxml │ │ │ │ │ └── admin_mgr_pwd.wxss │ │ │ │ ├── news/ │ │ │ │ │ ├── add/ │ │ │ │ │ │ ├── admin_news_add.js │ │ │ │ │ │ ├── admin_news_add.json │ │ │ │ │ │ ├── admin_news_add.wxml │ │ │ │ │ │ └── admin_news_add.wxss │ │ │ │ │ ├── admin_news_form_tpl.wxml │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── admin_news_edit.js │ │ │ │ │ │ ├── admin_news_edit.json │ │ │ │ │ │ ├── admin_news_edit.wxml │ │ │ │ │ │ └── admin_news_edit.wxss │ │ │ │ │ └── list/ │ │ │ │ │ ├── admin_news_list.js │ │ │ │ │ ├── admin_news_list.json │ │ │ │ │ ├── admin_news_list.wxml │ │ │ │ │ └── admin_news_list.wxss │ │ │ │ ├── product/ │ │ │ │ │ ├── add/ │ │ │ │ │ │ ├── admin_product_add.js │ │ │ │ │ │ ├── admin_product_add.json │ │ │ │ │ │ ├── admin_product_add.wxml │ │ │ │ │ │ └── admin_product_add.wxss │ │ │ │ │ ├── admin_product_form_tpl.wxml │ │ │ │ │ ├── edit/ │ │ │ │ │ │ ├── admin_product_edit.js │ │ │ │ │ │ ├── admin_product_edit.json │ │ │ │ │ │ ├── admin_product_edit.wxml │ │ │ │ │ │ └── admin_product_edit.wxss │ │ │ │ │ └── list/ │ │ │ │ │ ├── admin_product_list.js │ │ │ │ │ ├── admin_product_list.json │ │ │ │ │ ├── admin_product_list.wxml │ │ │ │ │ └── admin_product_list.wxss │ │ │ │ ├── setup/ │ │ │ │ │ ├── about/ │ │ │ │ │ │ ├── admin_setup_about.js │ │ │ │ │ │ ├── admin_setup_about.json │ │ │ │ │ │ ├── admin_setup_about.wxml │ │ │ │ │ │ └── admin_setup_about.wxss │ │ │ │ │ ├── about_list/ │ │ │ │ │ │ ├── admin_setup_about_list.js │ │ │ │ │ │ ├── admin_setup_about_list.json │ │ │ │ │ │ ├── admin_setup_about_list.wxml │ │ │ │ │ │ └── admin_setup_about_list.wxss │ │ │ │ │ └── qr/ │ │ │ │ │ ├── admin_setup_qr.js │ │ │ │ │ ├── admin_setup_qr.json │ │ │ │ │ ├── admin_setup_qr.wxml │ │ │ │ │ └── admin_setup_qr.wxss │ │ │ │ └── user/ │ │ │ │ ├── detail/ │ │ │ │ │ ├── admin_user_detail.js │ │ │ │ │ ├── admin_user_detail.json │ │ │ │ │ ├── admin_user_detail.wxml │ │ │ │ │ └── admin_user_detail.wxss │ │ │ │ ├── export/ │ │ │ │ │ ├── admin_user_export.js │ │ │ │ │ ├── admin_user_export.json │ │ │ │ │ ├── admin_user_export.wxml │ │ │ │ │ └── admin_user_export.wxss │ │ │ │ └── list/ │ │ │ │ ├── admin_user_list.js │ │ │ │ ├── admin_user_list.json │ │ │ │ ├── admin_user_list.wxml │ │ │ │ └── admin_user_list.wxss │ │ │ ├── album/ │ │ │ │ ├── detail/ │ │ │ │ │ ├── album_detail.js │ │ │ │ │ ├── album_detail.json │ │ │ │ │ ├── album_detail.wxml │ │ │ │ │ └── album_detail.wxss │ │ │ │ └── index/ │ │ │ │ ├── album_index.js │ │ │ │ ├── album_index.json │ │ │ │ ├── album_index.wxml │ │ │ │ └── album_index.wxss │ │ │ ├── default/ │ │ │ │ └── index/ │ │ │ │ ├── default_index.js │ │ │ │ ├── default_index.json │ │ │ │ ├── default_index.wxml │ │ │ │ └── default_index.wxss │ │ │ ├── meet/ │ │ │ │ ├── calendar/ │ │ │ │ │ ├── meet_calendar.js │ │ │ │ │ ├── meet_calendar.json │ │ │ │ │ ├── meet_calendar.wxml │ │ │ │ │ └── meet_calendar.wxss │ │ │ │ ├── detail/ │ │ │ │ │ ├── meet_detail.js │ │ │ │ │ ├── meet_detail.json │ │ │ │ │ ├── meet_detail.wxml │ │ │ │ │ └── meet_detail.wxss │ │ │ │ ├── index/ │ │ │ │ │ ├── meet_index.js │ │ │ │ │ ├── meet_index.json │ │ │ │ │ ├── meet_index.wxml │ │ │ │ │ └── meet_index.wxss │ │ │ │ ├── join/ │ │ │ │ │ ├── meet_join.js │ │ │ │ │ ├── meet_join.json │ │ │ │ │ ├── meet_join.wxml │ │ │ │ │ └── meet_join.wxss │ │ │ │ ├── my_join_detail/ │ │ │ │ │ ├── meet_my_join_detail.js │ │ │ │ │ ├── meet_my_join_detail.json │ │ │ │ │ ├── meet_my_join_detail.wxml │ │ │ │ │ └── meet_my_join_detail.wxss │ │ │ │ ├── my_join_list/ │ │ │ │ │ ├── meet_my_join_list.js │ │ │ │ │ ├── meet_my_join_list.json │ │ │ │ │ ├── meet_my_join_list.wxml │ │ │ │ │ └── meet_my_join_list.wxss │ │ │ │ └── self/ │ │ │ │ ├── meet_self.js │ │ │ │ ├── meet_self.json │ │ │ │ ├── meet_self.wxml │ │ │ │ └── meet_self.wxss │ │ │ ├── my/ │ │ │ │ ├── edit/ │ │ │ │ │ ├── my_edit.js │ │ │ │ │ ├── my_edit.json │ │ │ │ │ ├── my_edit.wxml │ │ │ │ │ ├── my_edit.wxss │ │ │ │ │ └── user_form.wxml │ │ │ │ ├── fav/ │ │ │ │ │ ├── my_fav.js │ │ │ │ │ ├── my_fav.json │ │ │ │ │ ├── my_fav.wxml │ │ │ │ │ └── my_fav.wxss │ │ │ │ ├── foot/ │ │ │ │ │ ├── my_foot.js │ │ │ │ │ ├── my_foot.json │ │ │ │ │ ├── my_foot.wxml │ │ │ │ │ └── my_foot.wxss │ │ │ │ ├── index/ │ │ │ │ │ ├── my_index.js │ │ │ │ │ ├── my_index.json │ │ │ │ │ ├── my_index.wxml │ │ │ │ │ └── my_index.wxss │ │ │ │ └── reg/ │ │ │ │ ├── my_reg.js │ │ │ │ ├── my_reg.json │ │ │ │ ├── my_reg.wxml │ │ │ │ └── my_reg.wxss │ │ │ ├── news/ │ │ │ │ ├── cate1/ │ │ │ │ │ ├── news_cate1.js │ │ │ │ │ ├── news_cate1.json │ │ │ │ │ ├── news_cate1.wxml │ │ │ │ │ └── news_cate1.wxss │ │ │ │ ├── cate2/ │ │ │ │ │ ├── news_cate2.js │ │ │ │ │ ├── news_cate2.json │ │ │ │ │ ├── news_cate2.wxml │ │ │ │ │ └── news_cate2.wxss │ │ │ │ ├── detail/ │ │ │ │ │ ├── news_detail.js │ │ │ │ │ ├── news_detail.json │ │ │ │ │ ├── news_detail.wxml │ │ │ │ │ └── news_detail.wxss │ │ │ │ └── index/ │ │ │ │ ├── news_index.js │ │ │ │ ├── news_index.json │ │ │ │ ├── news_index.wxml │ │ │ │ └── news_index.wxss │ │ │ ├── product/ │ │ │ │ ├── detail/ │ │ │ │ │ ├── product_detail.js │ │ │ │ │ ├── product_detail.json │ │ │ │ │ ├── product_detail.wxml │ │ │ │ │ └── product_detail.wxss │ │ │ │ └── index/ │ │ │ │ ├── product_index.js │ │ │ │ ├── product_index.json │ │ │ │ ├── product_index.wxml │ │ │ │ └── product_index.wxss │ │ │ ├── search/ │ │ │ │ ├── search.js │ │ │ │ ├── search.json │ │ │ │ ├── search.wxml │ │ │ │ └── search.wxss │ │ │ └── tpls/ │ │ │ └── menu_tpl.wxml │ │ ├── public/ │ │ │ └── project_setting.js │ │ └── style/ │ │ └── skin.wxss │ ├── setting/ │ │ └── setting.js │ ├── sitemap.json │ ├── style/ │ │ ├── base/ │ │ │ ├── animation.wxss │ │ │ ├── avatar.wxss │ │ │ ├── background.wxss │ │ │ ├── bar.wxss │ │ │ ├── base.wxss │ │ │ ├── border.wxss │ │ │ ├── button.wxss │ │ │ ├── comm.wxss │ │ │ ├── form.wxss │ │ │ ├── icon.wxss │ │ │ ├── image.wxss │ │ │ ├── layout.wxss │ │ │ ├── list.wxss │ │ │ ├── load.wxss │ │ │ ├── modal.wxss │ │ │ ├── nav.wxss │ │ │ ├── shadow.wxss │ │ │ ├── table.wxss │ │ │ ├── tag.wxss │ │ │ └── text.wxss │ │ ├── project/ │ │ │ ├── admin_list_style.wxss │ │ │ ├── my_fav_style.wxss │ │ │ ├── my_foot_style.wxss │ │ │ └── search_style.wxss │ │ └── public/ │ │ ├── admin.wxss │ │ ├── article_list.wxss │ │ ├── comm_box_list.wxss │ │ ├── detail.wxss │ │ └── project.wxss │ └── tpls/ │ ├── project/ │ │ ├── about_tpl.wxml │ │ ├── my_fav_tpl.wxml │ │ ├── my_foot_tpl.wxml │ │ ├── news_index_tpl.wxml │ │ └── search_tpl.wxml │ ├── public/ │ │ ├── admin_forms_detail_tpl.wxml │ │ ├── base_list_tpl.wxml │ │ ├── list_load_tpl.wxml │ │ └── top_tpl.wxml │ └── wxs/ │ └── tools.wxs ├── project.config.json ├── project.private.config.json └── 旅游景区门户小程序安装使用手册.docx ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Windows [Dd]esktop.ini Thumbs.db $RECYCLE.BIN/ # macOS .DS_Store .fseventsd .Spotlight-V100 .TemporaryItems .Trashes # Node.js node_modules/ ================================================ FILE: README.md ================================================ ## 功能 介绍 旅游景区门户小程序是一个为游客朋友提供多元化服务的一站式数字文旅平台,提供“吃、住、游、购、娱”等旅游行程中的多种服务,全面支持景区介绍,景点攻略,景点预约,停车预约、景区导览等功能,游客可以在小程序中了解旅游度假区的景点信息、历史文化、各类活动等。前后端代码完整,采用腾讯提供的小程序云开发解决方案,无须服务器和域名。 - 景点预约管理:开始/截止时间/人数均可灵活设置,可以自定义客户预约填写的数据项 - 景点预约凭证:支持线下到场后校验签到/核销/二维码自助签到等多种方式 - 详尽的预约数据:支持预约名单数据导出Excel,打印 ![image](https://user-images.githubusercontent.com/96864248/189519239-7707dfcc-5fe8-4ad1-9e07-e7bf73adb076.png) ![image](https://user-images.githubusercontent.com/96864248/189519246-c5b61c34-958b-473a-b9ac-c3a2ff08fdb1.png) ## 技术运用 - 本项目使用微信小程序平台进行开发。 - 使用腾讯专门的小程序云开发技术,云资源包含云函数,数据库,带宽,存储空间,定时器等,资源配额价格低廉,无需域名和服务器即可搭建。 - 小程序本身的即用即走,适合小工具的使用场景,也适合快速开发迭代。 - 云开发技术采用腾讯内部链路,没有被黑客攻击的风险,安全性高且免维护。 - 资源承载力可根据业务发展需要随时弹性扩展。 ## 作者 - 如有疑问,欢迎骚扰联系我:开发交流,技术分享,问题答疑,功能建议收集,版本更新通知,安装部署协助,小程序开发定制等。 - 俺的微信: ![image](https://user-images.githubusercontent.com/96864248/189519251-86ee2260-a55d-4158-b3ce-06c170f1ece4.png) ## 演示 ![image](https://user-images.githubusercontent.com/96864248/189519248-5532edd2-e763-40d6-9fea-c69edca87287.png) ## 安装 - 安装手册见源码包里的word文档 ![image](https://user-images.githubusercontent.com/96864248/189519252-b69954c6-caf5-4800-9800-d4251ffa4011.png) ![image](https://user-images.githubusercontent.com/96864248/189519255-c82f58e7-f790-4f42-8ea2-9d44ecfcacc4.png) ![image](https://user-images.githubusercontent.com/96864248/189519258-0f46606e-35e2-4b4b-8760-1497419eac10.png) ![image](https://user-images.githubusercontent.com/96864248/189519261-db1daaa2-1433-4b65-b3c6-efabb62bf047.png) ![image](https://user-images.githubusercontent.com/96864248/189519265-24fd846c-466d-4257-b9c5-f5d0b4d00687.png) ![image](https://user-images.githubusercontent.com/96864248/189519268-784bd0f0-009e-446b-81ce-a6b83cf9bcff.png) ![image](https://user-images.githubusercontent.com/96864248/189519271-6e2a223e-8d88-43f8-aa30-eb2bc056274a.png) ![image](https://user-images.githubusercontent.com/96864248/189519273-4aa22512-69bc-4a02-9b35-59e2be029aa9.png) ![image](https://user-images.githubusercontent.com/96864248/189519278-64310e7e-321f-4f36-8a35-5918de0583fc.png) ![image](https://user-images.githubusercontent.com/96864248/189519281-da759fef-9404-402d-8ae8-0e8ef1cd4706.png) ## 截图 ## 后台管理系统截图 - 后台超级管理员默认账号:admin,密码123456,请登录后台后及时修改密码和创建普通管理员。 ![image](https://user-images.githubusercontent.com/96864248/189519285-09317ce4-779a-4ffb-a26d-bfe9e947ffd4.png) ![image](https://user-images.githubusercontent.com/96864248/189519287-b4f08489-abe7-4395-84dd-0de6060d065b.png) ![image](https://user-images.githubusercontent.com/96864248/189519290-56b56e45-ac29-48b7-b3ab-2de853657f97.png) ![image](https://user-images.githubusercontent.com/96864248/189519293-dd9164cc-3235-42e0-98d9-aabbf0bafa99.png) ![image](https://user-images.githubusercontent.com/96864248/189519296-a6255dd9-80b0-4091-a08a-ec1ded16c2dd.png) ![image](https://user-images.githubusercontent.com/96864248/189519299-50e99c08-21e5-4587-ab3e-86feade044c3.png) ![image](https://user-images.githubusercontent.com/96864248/189519302-5ed8d472-8a6e-4b41-9b24-24ae94280d54.png) ================================================ FILE: cloudfunctions/mcloud/config/config.js ================================================ module.exports = { //### 环境相关 CLOUD_ID: 'init-5go8b8pdc98ea814', //你的云环境id // ################################################################## COLLECTION_PRFIX: 'bx_', IS_DEMO: false, //是否演示版 (后台不可操作提交动作) // ################################################################## // #### 调试相关 TEST_MODE: false, // 测试模式 涉及小程序码生成路径, 用以下 TEST_TOKEN_ID openid.. TEST_TOKEN_ID: 'oD58U5Ej-gK0BjqSspqjQEPgXuQQ', // #### 内容安全 CLIENT_CHECK_CONTENT: false, //前台图片文字是否校验 ADMIN_CHECK_CONTENT: false, //后台图片文字是否校验 // ### 后台业务相关 ADMIN_LOGIN_EXPIRE: 86400, //管理员token过期时间 (秒) } ================================================ FILE: cloudfunctions/mcloud/config.json ================================================ { "permissions": { "openapi": ["wxacode.getUnlimited", "security.imgSecCheck", "security.msgSecCheck","serviceMarket.invokeService"] } } ================================================ FILE: cloudfunctions/mcloud/framework/cloud/cloud_base.js ================================================ /** * Notes: 云初始化实例 * Ver : CCMiniCloud Framework 2.2.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const config = require('../../config/config.js'); /** * 获得云实例 */ function getCloud() { const cloud = require('wx-server-sdk'); cloud.init({ env: config.CLOUD_ID }); return cloud; } module.exports = { getCloud } ================================================ FILE: cloudfunctions/mcloud/framework/cloud/cloud_util.js ================================================ /** * Notes: 云基本操作模块 * Ver : CCMiniCloud Framework 2.3.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const cloudBase = require('./cloud_base.js'); function log(method, err, level = 'error') { const cloud = cloudBase.getCloud(); const log = cloud.logger(); log.error({ method: method, errCode: err.code, errMsg: err.message, errStack: err.stack }); } async function getTempFileURLOne(fileID) { if (!fileID) return ''; const cloud = cloudBase.getCloud(); let result = await cloud.getTempFileURL({ fileList: [fileID], }) if (result && result.fileList && result.fileList[0] && result.fileList[0].tempFileURL) return result.fileList[0].tempFileURL; return ''; } async function getTempFileURL(tempFileList, isValid = false) { if (!tempFileList || tempFileList.length == 0) return []; const cloud = cloudBase.getCloud(); let result = await cloud.getTempFileURL({ fileList: tempFileList, }) console.log(result); let list = result.fileList; let outList = []; for (let i = 0; i < list.length; i++) { let pic = {}; if (list[i].status == 0) { //获取到地址的 pic.url = list[i].tempFileURL; pic.cloudId = list[i].fileID; outList.push(pic) } else { //未获取到地址的(已经转换过的) if (!isValid) { pic.url = list[i].fileID; // fileID为URL, tempFileURL为空 pic.cloudId = list[i].fileID; outList.push(pic) } } } return outList; } async function handlerCloudFilesForForms(oldForms, newsForms) { let oldFiles = []; let newFiles = []; for (let k = 0; k < oldForms.length; k++) { if (oldForms[k].type == 'image') oldFiles = oldFiles.concat(oldForms[k].val); else if (oldForms[k].type == 'content') { let contentVal = oldForms[k].val; for (let n in contentVal) { if (contentVal[n].type == 'img') oldFiles.push(contentVal[n].val); } } } for (let j in newsForms) { if (newsForms[j].type == 'image') newFiles = newFiles.concat(newsForms[j].val); else if (newsForms[j].type == 'content') { let contentVal = newsForms[j].val; for (let m in contentVal) { if (contentVal[m].type == 'img') newFiles.push(contentVal[m].val); } } } await handlerCloudFiles(oldFiles, newFiles); } async function handlerCloudFiles(oldFiles, newFiles) { //if (oldFiles.length == 0 && newFiles.length == 0) return []; const cloud = cloudBase.getCloud(); for (let i = 0; i < oldFiles.length; i++) { let isDel = true; for (let j = 0; j < newFiles.length; j++) { if (oldFiles[i] == newFiles[j]) { // 从旧文件数组里 找到 新组 还存在的文件 ,则不删除 isDel = false; break; } } // 新组里不存在,直接删除 if (isDel && oldFiles[i]) { let result = await cloud.deleteFile({ fileList: [oldFiles[i]], }); console.log(result); } } return newFiles; } async function handlerCloudFilesByRichEditor(oldFiles, newFiles) { const cloud = cloudBase.getCloud(); for (let i = 0; i < oldFiles.length; i++) { let isDel = true; for (let j = 0; j < newFiles.length; j++) { if (oldFiles[i].type == 'img' && newFiles[j].type == 'img' && oldFiles[i].val == newFiles[j].val) { // 从旧文件数组里 找到 新组 还存在的图片文件, 保存cloudID //newFiles[j].cloudId = oldFiles[i].cloudId; isDel = false; break; } } // 新组里不存在,直接删除 if (isDel && oldFiles[i].type == 'img' && oldFiles[i].val) { let result = await cloud.deleteFile({ fileList: [oldFiles[i].val], }); } } return newFiles; } async function deleteFiles(list) { if (!list) return; if (!Array.isArray(list)) list = [list]; if (list.length == 0) return; const cloud = cloudBase.getCloud(); await cloud.deleteFile({ fileList: list, }); } module.exports = { log, getTempFileURL, getTempFileURLOne, deleteFiles, handlerCloudFiles, handlerCloudFilesByRichEditor, handlerCloudFilesForForms } ================================================ FILE: cloudfunctions/mcloud/framework/core/app_code.js ================================================ /** * Notes: 错误代码定义 * Ver : CCMiniCloud Framework 2.4.1 ALL RIGHTS RESERVED BY Cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ module.exports = { SUCC: 200, SVR: 500, // 服务器错误 LOGIC: 1600, //逻辑错误 DATA: 1301, // 数据校验错误 HEADER: 1302, // header 校验错误 //2000开始为业务错误代码, ADMIN_ERROR: 2401 //管理员错误 } ================================================ FILE: cloudfunctions/mcloud/framework/core/app_error.js ================================================ /** * Notes: 应用异常处理类 * Ver : CCMiniCloud Framework 2.5.1 ALL RIGHTS RESERVED BY cClinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const appCode = require('./app_code.js'); class AppError extends Error { constructor(message, code = appCode.LOGIC) { super(message); this.name = 'AppError'; this.code = code; } } module.exports = AppError; ================================================ FILE: cloudfunctions/mcloud/framework/core/app_other.js ================================================ /** * Notes: 云函数非标业务处理 * Ver : CCMiniCloud Framework 2.6.1 ALL RIGHTS RESERVED BY ccLinux@qq.com * Date: 2021-10-21 04:00:00 */ function handlerOther(event) { let isOther = false; if (!event) return { isOther, eventX }; // 公众号事件处理 if (event['FromUserName'] && event['MsgType']) { console.log('公众号事件处理'); let ret = { route: 'oa/serve', params: event } return { isOther: true, eventX: ret }; } return { isOther, eventX: event }; } module.exports = { handlerOther, } ================================================ FILE: cloudfunctions/mcloud/framework/core/app_util.js ================================================ /** * Notes: 云函数业务主逻辑函数 * Ver : CCMiniCloud Framework 2.7.1 ALL RIGHTS RESERVED BY cclinuX0730 (wechat) * Date: 2021-02-09 04:00:00 */ const appCode = require('./app_code.js'); function handlerBasic(code, msg = '', data = {}) { switch (code) { case appCode.SUCC: msg = (msg) ? msg + ':ok' : 'ok'; break; case appCode.SVR: msg = '服务器繁忙,请稍后再试'; break; case appCode.LOGIC: break; case appCode.DATA: break; /* default: msg = '服务器开小差了,请稍后再试'; break;*/ } return { code: code, msg: msg, data: data } } function handlerSvrErr(msg = '') { return handlerBasic(appCode.SVR, msg); } function handlerSucc(msg = '') { return handlerBasic(appCode.SUCC, msg); } function handlerAppErr(msg = '', code = appCode.LOGIC) { return handlerBasic(code, msg); } function handlerData(data, msg = '') { return handlerBasic(appCode.SUCC, msg, data); } module.exports = { handlerBasic, handlerData, handlerSucc, handlerSvrErr, handlerAppErr } ================================================ FILE: cloudfunctions/mcloud/framework/core/application.js ================================================ /** * Notes: 云函数业务主逻辑 * Ver : CCMiniCloud Framework 2.8.1 ALL RIGHTS RESERVED BY cclinUX0730 (wechat) * Date: 2020-09-05 04:00:00 */ const util = require('../utils/util.js'); const cloudBase = require('../cloud/cloud_base.js'); const timeUtil = require('../utils/time_util.js'); const appUtil = require('./app_util.js'); const appCode = require('./app_code.js'); const appOther = require('./app_other.js'); const config = require('../../config/config.js'); global.PID = 'unknown'; async function app(event, context) { // 非标业务处理 let { eventX, isOther } = appOther.handlerOther(event); event = eventX; // 取得openid const cloud = cloudBase.getCloud(); const wxContext = cloud.getWXContext(); let r = ''; let PID = ''; try { if (!util.isDefined(event.route)) { showEvent(event); console.error('Route Not Defined'); return appUtil.handlerSvrErr(); } r = event.route.toLowerCase(); if (!r.includes('/')) { showEvent(event); console.error('Route Format error[' + r + ']'); return appUtil.handlerSvrErr(); } PID = event.PID.trim(); if (!PID) { showEvent(event); console.error('PID Is NULL]'); return appUtil.handlerSvrErr(); } global.PID = PID; // 路由不存在 routes = require('project/' + PID + '/public/route.js'); if (!util.isDefined(routes[r])) { showEvent(event); console.error('Route [' + r + '] Is Not Exist'); return appUtil.handlerSvrErr(); } let routesArr = routes[r].split('@'); let controllerName = routesArr[0]; let actionName = routesArr[1]; // 事前处理 if (actionName.includes('#')) { let actionNameArr = actionName.split('#'); actionName = actionNameArr[0]; if (actionNameArr[1] && config.IS_DEMO) { console.log('### APP Before = ' + actionNameArr[1]); return beforeApp(actionNameArr[1]); } } console.log(''); console.log(''); let time = timeUtil.time('Y-M-D h:m:s'); let timeTicks = timeUtil.time(); let openId = wxContext.OPENID; console.log('▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤▤'); console.log(`【↘${time} ENV (${config.CLOUD_ID})】【Request Base↘↘↘】\n【↘Route =***${r}】\n【↘Controller = ${controllerName}】\n【↘Action = ${actionName}】\n【↘OPENID = ${openId}】\n【↘PID = ${global.PID}】`); // 测试模式 if (config.TEST_MODE) openId = config.TEST_TOKEN_ID; if (!openId) { console.error('OPENID is unfined'); return appUtil.handlerSvrErr(); } // 引入逻辑controller controllerName = controllerName.toLowerCase().trim(); const ControllerClass = require('project/'+PID +'/controller/' + controllerName + '.js'); const controller = new ControllerClass(r, PID + '^^^' + openId, event); // 调用方法 await controller['initSetup'](); let result = await controller[actionName](); // 返回值处理 if (isOther) { // 非标处理 return result; } else { if (!result) result = appUtil.handlerSucc(r); // 无数据返回 else result = appUtil.handlerData(result, r); // 有数据返回 } console.log('------'); time = timeUtil.time('Y-M-D h:m:s'); timeTicks = timeUtil.time() - timeTicks; console.log(`【${time}】【Return Base↗↗↗】\n【↗Route =***${r}】\n【↗Duration = ${timeTicks}ms】\n【↗↗OUT DATA】= `, result); console.log('▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦'); console.log(''); console.log(''); return result; } catch (ex) { const log = cloud.logger(); console.log('------'); time = timeUtil.time('Y-M-D h:m:s'); console.error(`【${time}】【Return Base↗↗↗】\n【↗Route = ${r}】\Exception MSG = ${ex.message}, CODE=${ex.code}`); // 系统级错误定位调试 if (config.TEST_MODE && ex.name != 'AppError') throw ex; console.log('▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦▦'); console.log(''); console.log(''); if (ex.name == 'AppError') { log.warn({ route: r, errCode: ex.code, errMsg: ex.message }); // 自定义error处理 return appUtil.handlerAppErr(ex.message, ex.code); } else { //console.log(ex); log.error({ route: r, errCode: ex.code, errMsg: ex.message, errStack: ex.stack }); // 系统error return appUtil.handlerSvrErr(); } } } // 事前处理 function beforeApp(method) { switch (method) { case 'demo': { return appUtil.handlerAppErr('本系统仅为用户体验演示,后台提交的操作均不生效!如有需要请联系作者微信cclinux0730', appCode.LOGIC); } } console.error('事前处理, Method Not Find = ' + method); } // 展示当前输入数据 function showEvent(event) { console.log(event); } module.exports = { app } ================================================ FILE: cloudfunctions/mcloud/framework/database/db_util.js ================================================ /** * Notes: 数据库基本操作 * Ver : CCMiniCloud Framework 2.9.1 ALL RIGHTS RESERVED BY CClinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const util = require('../utils/util.js'); const dataUtil = require('../utils/data_util.js'); const cloudBase = require('../cloud/cloud_base.js'); const MAX_RECORD_SIZE = 1000; const DEFAULT_RECORD_SIZE = 20; const cloud = cloudBase.getCloud(); const db = cloud.database(); const dbCmd = db.command; const dbAggr = dbCmd.aggregate; // 获得一个命令操作 function getCmd() { return dbCmd; } async function insertBatch(collectionName, data, size = 1000) { let dataArr = dataUtil.spArr(data, size); for (let k = 0; k < dataArr.length; k++) { await db.collection(collectionName).add({ data: dataArr[k] }); } //return query._id; } async function insert(collectionName, data) { let query = await db.collection(collectionName).add({ data }); return query._id; } async function edit(collectionName, where, data) { let query = await db.collection(collectionName); // 查询条件 if (util.isDefined(where)) { if (typeof (where) == 'string' || typeof (where) == 'number') query = await query.doc(where); else query = await query.where(fmtWhere(where)); } query = await query.update({ data }); return query.stats.updated; } async function inc(collectionName, where, field, val = 1) { let query = await db.collection(collectionName); // 查询条件 if (util.isDefined(where)) { if (typeof (where) == 'string' || typeof (where) == 'number') query = await query.doc(where); else query = await query.where(fmtWhere(where)); } query = await query.update({ data: { [field]: dbCmd.inc(val) } }); return query.stats.updated; } async function mul(collectionName, where, field, val = 1) { let query = await db.collection(collectionName); // 查询条件 if (util.isDefined(where)) { if (typeof (where) == 'string' || typeof (where) == 'number') query = await query.doc(where); else query = await query.where(fmtWhere(where)); } query = await query.update({ data: { [field]: dbCmd.mul(val) } }); return query.stats.updated; } async function del(collectionName, where) { let query = await db.collection(collectionName); // 查询条件 if (util.isDefined(where)) { if (typeof (where) == 'string' || typeof (where) == 'number') query = await query.doc(where); else query = await query.where(fmtWhere(where)); } query = await query.remove(); return query.stats.removed; } async function count(collectionName, where) { let query = await db.collection(collectionName); // 查询条件 if (typeof (where) == 'string' || typeof (where) == 'number') query = await query.doc(where); else query = await query.where(fmtWhere(where)); query = await query.count(); return query.total; } async function distinct(collectionName, where, field) { let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); query = await query.group({ _id: null, 'uniqueValues': dbAggr.addToSet('$' + field) }).end(); if (query && query.list && query.list[0] && query.list[0]['uniqueValues']) { return query.list[0]['uniqueValues']; } else return []; } async function distinctCnt(collectionName, where, field) { let data = await distinct(collectionName, where, field); return data.length; } async function groupSum(collectionName, where, groupField, fields) { let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); if (!Array.isArray(fields)) { fields = [fields]; } let node = {}; for (let k = 0; k < fields.length; k++) { node[fields[k]] = dbAggr.sum('$' + fields[k]); } query = await query.group({ _id: { [groupField]: '$' + groupField }, ...node }).end(); if (query && query.list) { let list = query.list; for (let k = 0; k < list.length; k++) { list[k][groupField] = list[k]['_id'][groupField]; delete list[k]['_id']; } return list; } else return []; } async function groupCount(collectionName, where, groupField) { let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); query = await query.group({ _id: '$' + groupField, total: dbAggr.sum(1) }).end(); if (query && query.list) { let list = query.list; let ret = {}; for (let k = 0; k < list.length; k++) { ret[groupField + '_' + list[k]['_id']] = list[k].total; } return ret; } else return null; } async function sum(collectionName, where, field) { // TODO 可扩展为支持多个字段同时统计 let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); query = await query.group({ _id: null, 'summ': dbAggr.sum('$' + field) }).end(); if (query && query.list && query.list[0] && query.list[0]['summ']) { return query.list[0]['summ']; } else return 0; } async function max(collectionName, where, field) { let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); query = await query.group({ _id: null, 'maxx': dbAggr.max('$' + field) }).end(); if (query && query.list && query.list[0] && query.list[0]['maxx']) { return query.list[0]['maxx']; } else return 0; } async function min(collectionName, where, field) { let query = await db.collection(collectionName); query = await query.aggregate(); // 查询条件 query = await query.match(fmtWhere(where)); query = await query.group({ _id: null, 'minx': dbAggr.min('$' + field) }).end(); if (query && query.list && query.list[0] && query.list[0]['minx']) { return query.list[0]['minx']; } else return 0; } async function clear(collectionName) { await db.collection(collectionName).where({ _id: dbCmd.neq(1) }).remove().then(res => { }); } async function isExistCollection(collectionName) { try { await getOne(collectionName, {}); return true; } catch (err) { return false; } } async function createCollection(collectionName) { try { await db.createCollection(collectionName); console.log('>> Create New Collection [' + collectionName + '] Succ, OVER.'); return true; } catch (err) { console.error('>> Create New Collection [' + collectionName + '] Failed, Code=' + err.errCode + '|' + err.errMsg); return false; } } async function rand(collectionName, where = {}, fields = '*', size = 1) { size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; let query = await db.collection(collectionName) .aggregate(); if (util.isDefined(where)) query = await query.match(fmtWhere(where)); if (util.isDefined(fields) && fields != '*') query = await query.project(fmtFields(fields)); query = await query.sample({ size }); query = await query.end(); if (size == 1) { if (query.list.length == 1) return query.list[0]; else return null; } else return query.list; } async function getListByArray(collectionName, arrField, where, fields, orderBy, page = 1, size = DEFAULT_RECORD_SIZE, isTotal = true, oldTotal = 0) { if (typeof (where) == 'string' || typeof (where) == 'number') { where = { _id: where, }; } page = Number(page); size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; data = { page: page, size: size } let offset = 0; //记录偏移量 防止新增数据列表重复 // 计算总页数 if (isTotal) { // 联表 let queryCnt = await db.collection(collectionName) .aggregate(); // 查询条件 if (util.isDefined(where)) queryCnt = await queryCnt.match(fmtWhere(where)); let total = await queryCnt.count('total').end(); if (!total.list.length) total = 0; else total = total.list[0].total; data.total = total; data.count = Math.ceil(total / size); if (page > 1 && oldTotal > 0) { offset = data.total - oldTotal if (offset < 0) offset = 0; } } // 拆分查询 let query = await db.collection(collectionName) .aggregate() .unwind('$' + arrField); // 查询条件 if (util.isDefined(where)) query = await query.match(fmtWhere(where)); // 取出特定字段 if (util.isDefined(fields) && fields != '*') query = await query.project(fmtFields(fields)); // 排序 if (util.isDefined(orderBy)) { query = await query.sort(fmtJoinSort(orderBy)); } // 分页 query = await query.skip((page - 1) * size + offset).limit(size); // 取数据 query = await query.end(); data.list = query.list; return data; } async function getListJoin(collectionName, joinParams, where, fields, orderBy, page = 1, size = DEFAULT_RECORD_SIZE, isTotal = true, oldTotal = 0, is2Many = false) { if (typeof (where) == 'string' || typeof (where) == 'number') { where = { _id: where, }; } page = Number(page); size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; data = { page: page, size: size } let offset = 0; //记录偏移量 防止新增数据列表重复 // 计算总页数 if (isTotal) { // 联表 let queryCnt = await db.collection(collectionName) .aggregate() .lookup(joinParams); // 查询条件 if (util.isDefined(where)) queryCnt = await queryCnt.match(fmtWhere(where)); let total = await queryCnt.count('total').end(); if (!total.list.length) total = 0; else total = total.list[0].total; data.total = total; data.count = Math.ceil(total / size); if (page > 1 && oldTotal > 0) { offset = data.total - oldTotal if (offset < 0) offset = 0; } } // 联表 let query = await db.collection(collectionName) .aggregate() .lookup(joinParams); /* query = await query.replaceRoot({ newRoot: $.mergeObjects([ $.arrayElemAt(['$USER_DETAIL', 0]), '$$ROOT' ]) })*/ // 查询条件 if (util.isDefined(where)) query = await query.match(fmtWhere(where)); // 取出特定字段 if (util.isDefined(fields) && fields != '*') query = await query.project(fmtFields(fields)); // 排序 if (util.isDefined(orderBy)) { query = await query.sort(fmtJoinSort(orderBy)); } // 分页 query = await query.skip((page - 1) * size + offset).limit(size); // 取数据 query = await query.end(); data.list = query.list; if (!is2Many) { for (let k = 0; k < data.list.length; k++) { if (util.isDefined(data.list[k][joinParams.as])) { if (Array.isArray(data.list[k][joinParams.as]) && data.list[k][joinParams.as].length > 0) data.list[k][joinParams.as] = data.list[k][joinParams.as][0]; else { data.list[k][joinParams.as] = {}; } } } } return data; } async function getListJoinCount(collectionName, joinParams, where) { if (typeof (where) == 'string' || typeof (where) == 'number') { where = { _id: where, }; } // 联表 let queryCnt = await db.collection(collectionName) .aggregate() .lookup(joinParams); // 查询条件 if (util.isDefined(where)) queryCnt = await queryCnt.match(fmtWhere(where)); let total = await queryCnt.count('total').end(); if (!total.list.length) total = 0; else total = total.list[0].total; return total; } async function getList(collectionName, where, fields = '*', orderBy = {}, page = 1, size = DEFAULT_RECORD_SIZE, isTotal = true, oldTotal = 0) { page = Number(page); size = Number(size); if (size > MAX_RECORD_SIZE || size == 0) size = MAX_RECORD_SIZE; let data = { page: page, size: size } let offset = 0; // 计算总页数 if (isTotal) { let total = await count(collectionName, where); data.total = total; data.count = Math.ceil(total / size); if (page > 1 && oldTotal > 0) { offset = data.total - oldTotal if (offset < 0) offset = 0; } } // 分页 let query = await db.collection(collectionName) .skip((page - 1) * size + offset) .limit(size); // 查询条件 if (util.isDefined(where) && where) query = await query.where(fmtWhere(where)); // 取出特定字段 if (util.isDefined(fields) && fields != '*') query = await query.field(fmtFields(fields)); // 排序 if (util.isDefined(orderBy)) { query = await fmtOrderBy(query, orderBy); } // 取数据 query = await query.get(); data.list = query.data; return data; } async function getAllBig(collectionName, where, fields = '*', orderBy, size = MAX_RECORD_SIZE) { size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; // 计算总数 let total = await await count(collectionName, where); // 页数 let page = Math.ceil(total / size); let list = []; for (let i = 1; i <= page; i++) { let data = await getList(collectionName, where, fields, orderBy, i, size, false); if (data && data.list) list = list.concat(data.list); } return list; } async function getAll(collectionName, where, fields = '*', orderBy, size = MAX_RECORD_SIZE) { size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; let query = await db.collection(collectionName).limit(size); // 查询条件 if (where) query = await query.where(fmtWhere(where)); // 取出特定字段 if (fields && fields != '*') query = await query.field(fmtFields(fields)); // 排序 if (orderBy) { query = await fmtOrderBy(query, orderBy); } // 取数据 query = await query.get(); return query.data; } async function getAllByArray(collectionName, arrField, where, fields = '*', orderBy, size = MAX_RECORD_SIZE) { size = Number(size); if (size > MAX_RECORD_SIZE) size = MAX_RECORD_SIZE; // 拆分 let query = await db.collection(collectionName).aggregate() .unwind('$' + arrField); // 查询条件 if (util.isDefined(where)) query = await query.match(fmtWhere(where)); // 取出特定字段 if (util.isDefined(fields) && fields != '*') query = await query.project(fmtFields(fields)); // 排序 if (util.isDefined(orderBy)) { query = await query.sort(fmtJoinSort(orderBy)); } // 取数据 query = await query.limit(size).end(); return query.list; } async function getOne(collectionName, where, fields = '*', orderBy = {}) { if (typeof (where) == 'string' || typeof (where) == 'number') { where = { _id: where }; } // 查询条件 let query = await db.collection(collectionName) .where(fmtWhere(where)) .limit(1); // 取出特定字段 if (fields != '*') query = await query.field(fmtFields(fields)); // 排序 if (orderBy) query = await fmtOrderBy(query, orderBy); // 取数据 query = await query.get(); if (query && query.data.length > 0) { return query.data[0]; } else return null; } async function fmtOrderBy(query, orderBy) { for (let key in orderBy) { query = await query.orderBy(key, orderBy[key].toLowerCase()) } return query; } function fmtJoinSort(sort) { for (let key in sort) { let v = sort[key]; if (typeof (v) == 'string') { v = v.toLowerCase(); if (v === 'asc') v = 1; else v = -1; } sort[key] = v; } return sort; } function fmtFields(fields) { if (typeof (fields) == 'string') { let obj = {}; fields = fields.replace(/,/g, ","); let arr = fields.split(','); for (let i = 0; i < arr.length; i++) { if (arr[i].trim().length > 0) obj[arr[i].trim()] = true; } return obj; } return fields; } function fmtWhere(where) { if (util.isDefined(where.and) || util.isDefined(where.or)) { let whereEx = null; if (util.isDefined(where.and)) whereEx = dbCmd.and(fmtWhere(where.and)); if (util.isDefined(where.or)) { if (whereEx) whereEx = whereEx.and(dbCmd.or(fmtWhere(where.or))); else whereEx = dbCmd.or(fmtWhere(where.or)); } //console.log(whereEx); return whereEx; } if (Array.isArray(where)) { for (let i = 0; i < where.length; i++) where[i] = fmtWhere(where[i]); } for (let key in where) { /* 判断是否有条件数组 INFO_EXPIRE_TIME: [ ['>=', 3], ['<=', 8], ['<>', 5], ['in', '6,7'] ], */ if (Array.isArray(where[key])) { let w = null; if (!Array.isArray(where[key][0]) && where[key][0].toLowerCase().trim() == 'between') { // 条件查询特殊处理 where[key] = [ ['>=', where[key][1]], ['<=', where[key][2]] ]; } if (!Array.isArray(where[key][0])) { // 一维数组 w = fmtWhereSimple(where[key]); } else { // 二维数组 for (let i = 0; i < where[key].length; i++) { let wTemp = fmtWhereSimple(where[key][i]); w = (w) ? w.and(wTemp) : wTemp; } } where[key] = w; } } return where; } function fmtWhereSimple(arr) { let sql = ''; let op = arr[0].toLowerCase().trim(); let val = arr[1]; let where = {}; switch (op) { case '=': where = dbCmd.eq(val); break; case '!=': case '<>': where = dbCmd.neq(val); break; case '<': where = dbCmd.lt(val); break; case '<=': where = dbCmd.lte(val); break; case '>': where = dbCmd.gt(val); break; case '>=': where = dbCmd.gte(val); break; case 'like': if (!util.isDefined(val) || !val) break; //无条件不搜索 where = { $regex: val, $options: 'i' } break; case 'in': val = dataUtil.str2Arr(val); where = dbCmd.in(val); break; case 'not in': val = dataUtil.str2Arr(val); where = dbCmd.nin(val); break; default: console.error('error where oprt=' + op); break; } return where; } module.exports = { getCmd, insert, insertBatch, edit, del, count, inc, sum, groupCount, groupSum, distinct, distinctCnt, max, min, mul, isExistCollection, createCollection, clear, rand, getOne, getAll, getAllBig, getAllByArray, getList, getListJoin, getListJoinCount, getListByArray, MAX_RECORD_SIZE, DEFAULT_RECORD_SIZE } ================================================ FILE: cloudfunctions/mcloud/framework/database/model.js ================================================ /** * Notes: 数据持久化与操作模块 * Ver : CCMiniCloud Framework 2.11.1 ALL RIGHTS RESERVED BY ccLinux0730 (wechat) * Date: 2020-09-04 04:00:00 */ const dbUtil = require('./db_util.js'); const util = require('../utils/util.js'); const timeUtil = require('../utils/time_util.js'); const dataUtil = require('../utils/data_util.js'); const AppError = require('../core/app_error.js'); const cloudBase = require('../cloud/cloud_base.js'); class Model { static async getOne(where, fields = '*', orderBy = {}) { return await dbUtil.getOne(this.CL, where, fields, orderBy); } static async edit(where, data) { if (this.UPDATE_TIME) { let editField = this.FIELD_PREFIX + 'EDIT_TIME'; if (!util.isDefined(data[editField])) data[editField] = timeUtil.time(); } if (this.UPDATE_IP) { let cloud = cloudBase.getCloud(); let ip = cloud.getWXContext().CLIENTIP; let editField = this.FIELD_PREFIX + 'EDIT_IP'; if (!util.isDefined(data[editField])) data[editField] = ip; } data = this.clearEditData(data); return await dbUtil.edit(this.CL, where, data); } static async count(where) { return await dbUtil.count(this.CL, where); } static async insert(data) { // 自动ID if (this.ADD_ID) { let idField = this.FIELD_PREFIX + 'ID'; if (!util.isDefined(data[idField])) data[idField] = dataUtil.makeID(); } // 更新时间 if (this.UPDATE_TIME) { let timestamp = timeUtil.time(); let addField = this.FIELD_PREFIX + 'ADD_TIME'; if (!util.isDefined(data[addField])) data[addField] = timestamp; let editField = this.FIELD_PREFIX + 'EDIT_TIME'; if (!util.isDefined(data[editField])) data[editField] = timestamp; } // 更新IP if (this.UPDATE_IP) { let cloud = cloudBase.getCloud(); let ip = cloud.getWXContext().CLIENTIP; let addField = this.FIELD_PREFIX + 'ADD_IP'; if (!util.isDefined(data[addField])) data[addField] = ip; let editField = this.FIELD_PREFIX + 'EDIT_IP'; if (!util.isDefined(data[editField])) data[editField] = ip; } // 数据清洗 data = this.clearCreateData(data); return await dbUtil.insert(this.CL, data); } static async insertOrUpdate(where, data) { let model = await dbUtil.getOne(this.CL, where, '_id'); if (model) { await this.edit(model._id, data); return model._id; } else { return await this.insert(Object.assign(data, where)); } } static async insertBatch(data = [], size = 1000) { if (this.ADD_ID) { let idField = this.FIELD_PREFIX + 'ID'; for (let k = 0; k < data.length; k++) { if (!util.isDefined(data[k][idField])) data[k][idField] = dataUtil.makeID(); } } if (this.UPDATE_TIME) { let timestamp = timeUtil.time(); let addField = this.FIELD_PREFIX + 'ADD_TIME'; let editField = this.FIELD_PREFIX + 'EDIT_TIME'; for (let k = 0; k < data.length; k++) { if (!util.isDefined(data[k][addField])) data[k][addField] = timestamp; if (!util.isDefined(data[k][editField])) data[k][editField] = timestamp; } } if (this.UPDATE_IP) { let cloud = cloudBase.getCloud(); let ip = cloud.getWXContext().CLIENTIP; let addField = this.FIELD_PREFIX + 'ADD_IP'; let editField = this.FIELD_PREFIX + 'EDIT_IP'; for (let k = 0; k < data.length; k++) { if (!util.isDefined(data[k][addField])) data[k][addField] = ip; if (!util.isDefined(data[k][editField])) data[k][editField] = ip; } } for (let k = 0; k < data.length; k++) { data[k] = this.clearCreateData(data[k]); } return await dbUtil.insertBatch(this.CL, data, size); } static async del(where) { return await dbUtil.del(this.CL, where); } static async inc(where, field, val = 1) { return await dbUtil.inc(this.CL, where, field, val); } static async mul(where, field, val = 1) { return await dbUtil.mul(this.CL, where, field, val); } static async groupSum(where, groupField, field) { return await dbUtil.groupSum(this.CL, where, groupField, field); } static async groupCount(where, groupField) { return await dbUtil.groupCount(this.CL, where, groupField); } static async sum(where, field) { return await dbUtil.sum(this.CL, where, field); } static async distinct(where, field) { return await dbUtil.distinct(this.CL, where, field); } static async distinctCnt(where, field) { return await dbUtil.distinctCnt(this.CL, where, field); } static async max(where, field) { return await dbUtil.max(this.CL, where, field); } static async min(where, field) { return await dbUtil.min(this.CL, where, field); } static async clear() { return await dbUtil.clear(this.CL); } static async rand(where = {}, fields = '*', size = 1) { return await dbUtil.rand(this.CL, where, fields, size); } static async getAll(where, fields, orderBy, size = 100) { return await dbUtil.getAll(this.CL, where, fields, orderBy, size); } static async getAllBig(where, fields, orderBy, size = 1000) { return await dbUtil.getAllBig(this.CL, where, fields, orderBy, size); } static async getAllByArray(arrField, where, fields, orderBy, size = 100) { return await dbUtil.getAllByArray(this.CL, arrField, where, fields, orderBy, size); } static async getList(where, fields, orderBy, page, size, isTotal, oldTotal) { return await dbUtil.getList(this.CL, where, fields, orderBy, page, size, isTotal, oldTotal); } static async getListJoin(joinParams, where, fields, orderBy, page = 1, size, isTotal = true, oldTotal = 0, is2Many = false) { return await dbUtil.getListJoin(this.CL, joinParams, where, fields, orderBy, page, size, isTotal, oldTotal, is2Many); } static async getListJoinCount(joinParams, where) { return await dbUtil.getListJoinCount(this.CL, joinParams, where); } static async getListByArray(arrField, where, fields, orderBy, page = 1, size, isTotal = true, oldTotal = 0) { return await dbUtil.getListByArray(this.CL, arrField, where, fields, orderBy, page, size, isTotal, oldTotal); } static converDBStructure(stru) { let newStru = {}; for (let key in stru) { newStru[key] = {}; let arr = stru[key].split('|'); for (let k = 0; k < arr.length; k++) { // 类型 let val = arr[k].toLowerCase().trim(); let orginal = arr[k]; let type = 'string'; if (val === 'float' || val === 'int' || val === 'string' || val === 'array' || val === 'object' || val === 'bool') { type = val; newStru[key]['type'] = type; continue; } // 是否必填 if (val === 'true' || val === 'false') { let required = (val === 'true') ? true : false; newStru[key]['required'] = required; continue; } // 默认值 if (val.startsWith('default=') && util.isDefined(newStru[key]['type'])) { let defVal = orginal.replace('default=', ''); switch (newStru[key]['type']) { case 'int': case 'float': defVal = Number(defVal); break; case 'bool': defVal = defVal.toLowerCase(); defVal = defVal == 'true' ? true : false; break; case 'object': defVal = defVal.replace('{', ''); defVal = defVal.replace('}', '').trim(); if (!defVal) defVal = {}; else { let arr = defVal.split(','); defVal = {}; for (let m = 0; m < arr.length; m++) { if (arr[m]) defVal[arr[m]] = ''; } } break; case 'array': defVal = defVal.replace('[', ''); defVal = defVal.replace(']', '').trim(); if (!defVal) defVal = []; else defVal = defVal.split(','); break; default: defVal = String(defVal); } newStru[key]['defVal'] = defVal; continue; } // 注释 if (val.startsWith('comment=')) { let comment = orginal.replace('comment=', ''); newStru[key]['comment'] = comment; continue; } // 长度 if (val.startsWith('length=')) { let length = orginal.replace('length=', ''); length = Number(length); newStru[key]['length'] = length; continue; } } // 如果非必填字段没有默认值,则主动赋予一个 if (!newStru[key]['required'] && !util.isDefined(newStru[key]['defVal'])) { let defVal = ''; switch (newStru[key]['type']) { case 'bool': defVal = false; break; case 'int': case 'float': defVal = Number(0); break; case 'array': defVal = []; break; case 'object': defVal = {}; break; default: defVal = String(''); } newStru[key]['defVal'] = defVal; } // 如果没有长度 if (!util.isDefined(newStru[key]['length'])) { let length = 20; switch (newStru[key]['type']) { case 'int': case 'float': length = 30; break; case 'array': case 'object': length = 1500; break; default: length = 300; } newStru[key]['length'] = length; } } return newStru; } static clearDirtyData(data) { for (let key in data) { if (!this.DB_STRUCTURE.hasOwnProperty(key) && !key.includes('.')) { console.error('脏数据:' + key); throw new AppError('脏数据'); } } } static converDataType(data, dbStructure) { for (let key in data) { if (dbStructure.hasOwnProperty(key)) { let type = dbStructure[key].type.toLowerCase(); // 字段类型转换 switch (type) { case 'string': data[key] = String(data[key]); break; case 'bool': //data[key] = data[key]; break; case 'float': case 'int': data[key] = Number(data[key]); break; case 'array': if (data[key].constructor != Array) data[key] = []; break; case 'object': if (data[key] === undefined || data[key] === null) { data[key] = {}; } else if (data[key].constructor != Object) data[key] = {}; //data[key] = dbUtil.getCmd().set(data[key]); // 指定字段等于一个对象 TODO break; default: console.error('字段类型错误:' + key + dbStructure[key].type); throw new AppError("字段类型错误"); } } } return data; } static clearCreateData(data) { let dbStructure = Model.converDBStructure(this.DB_STRUCTURE); for (let key in dbStructure) { // 数据类型 if (!util.isDefined(dbStructure[key].type)) { console.log('[数据填写错误1]字段类型未定义:' + key); throw new AppError('数据填写错误1'); } // 是否定义必填 if (!util.isDefined(dbStructure[key].required)) { console.log('[数据填写错误2]required未定义:' + key); throw new AppError('数据填写错误2'); } // 键值未赋值情况 if (!data.hasOwnProperty(key)) { // 必填 if (dbStructure[key].required) { if (util.isDefined(dbStructure[key].defVal)) // 必填且有缺省值 data[key] = dbStructure[key].defVal; else { // 必填且无缺省值 console.log('[数据填写错误3]字段未填写:' + key); throw new AppError('数据填写错误3 ' + key); } } else { // 非必填字段必须有缺省值 if (!util.isDefined(dbStructure[key].defVal)) { console.log('[数据填写错误4]非必填字段必须有缺省值:' + key); throw new AppError('数据填写错误4'); } data[key] = dbStructure[key].defVal; } } } // 去掉脏数据 this.clearDirtyData(data, dbStructure); data = this.converDataType(data, dbStructure); return data; } static clearEditData(data) { let dbStructure = Model.converDBStructure(this.DB_STRUCTURE); // 去掉脏数据 this.clearDirtyData(data, dbStructure); data = this.converDataType(data, dbStructure); return data; } static getDesc(enumName, val) { let baseEnum = this[enumName]; let descEnum = this[enumName + '_DESC'] let enumKey = ''; // 先找出KEY for (let key in baseEnum) { if (baseEnum[key] === val) { enumKey = key; break; } } if (enumKey == '') return 'unknown'; // 再从Desc里找出描述 return descEnum[enumKey]; } } // 集合名 collection Model.CL = 'no-collection'; // 集合结构 Model.DB_STRUCTURE = 'no-dbStructure'; // 字段前缀 Model.FIELD_PREFIX = 'NO_'; // 开关自带更新ADD_TIME,EDIT_TIME,DEL_TIME的操作 Model.UPDATE_TIME = true; // 开关自带更新ADD_IP,EDIT_IP,DEL_IP的操作 Model.UPDATE_IP = true; // 开关添加ID Model.ADD_ID = true; // 默认排序 Model.ORDER_BY = { _id: 'desc' } module.exports = Model; ================================================ FILE: cloudfunctions/mcloud/framework/database/multi_model.js ================================================ /** * Notes: 实体基类 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.12.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const Model = require('./model.js'); const util = require('../utils/util.js'); const dataUtil = require('../utils/data_util.js'); const config = require('../../config/config.js'); class MultiModel extends Model { static C(cl) { return config.COLLECTION_PRFIX + cl; } static _getWhere(where, mustPID = true) { if (mustPID) { if (typeof (where) == 'string' || typeof (where) == 'number') { where = { _id: where, _pid: util.getProjectId() }; } else where._pid = util.getProjectId(); } return where; } static async getOneField(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); let one = await super.getOne(where, field); if (!one) return null; else { let ret = one[field]; if (ret === undefined) return ''; else return one[field]; } } static async getOne(where, fields = '*', orderBy = {}, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getOne(where, fields, orderBy); } static async edit(where, data, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.edit(where, data); } static async editForms(where, formName, objName, hasImageForms, mustPID = true) { where = MultiModel._getWhere(where, mustPID); let forms = await this.getOneField(where, formName, mustPID); if (!forms) return; // 赋值 for (let k = 0; k < hasImageForms.length; k++) { for (let j in forms) { if ((forms[j].type == 'image' || forms[j].type == 'content') && forms[j].mark == hasImageForms[k].mark && forms[j].type == hasImageForms[k].type) { forms[j].val = hasImageForms[k].val; break; } } } let data = { [formName]: forms, [objName]: dataUtil.dbForms2Obj(forms) }; return await super.edit(where, data); } static async count(where, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.count(where); } static async insert(data, mustPID = true) { if (mustPID) data._pid = util.getProjectId(); return await super.insert(data); } static async insertBatch(data = [], size = 1000, mustPID = true) { if (mustPID) { for (let k = 0; k < data.length; k++) { data[k]._pid = util.getProjectId(); } } return await super.insertBatch(data, size); } static async insertOrUpdate(where, data, mustPID = true) { if (mustPID) { where._pid = util.getProjectId(); } return await super.insertOrUpdate(where, data); } static async del(where, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.del(where); } static async clear() { return await super.clear(); } static async inc(where, field, val = 1, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.inc(where, field, val); } static async mul(where, field, val = 1, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.mul(where, field, val); } static async groupSum(where, groupField, field, mustPID = true) { if (mustPID) where._pid = util.getProjectId(); return await super.groupSum(where, groupField, field); } static async groupCount(where, groupField, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.groupCount(where, groupField); } static async sum(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.sum(where, field); } static async distinct(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.distinct(where, field); } static async distinctCnt(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.distinctCnt(where, field); } static async max(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.max(where, field); } static async min(where, field, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.min(where, field); } static async rand(where, field, size = 1, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.rand(where, field, size); } static async getAll(where, fields, orderBy, size = 100, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getAll(where, fields, orderBy, size); } static async getAllBig(where, fields, orderBy, size = 1000, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getAllBig(where, fields, orderBy, size); } static async getAllByArray(arrField, where, fields, orderBy, size = 100, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getAllByArray(arrField, where, fields, orderBy, size); } static async getList(where, fields, orderBy, page, size, isTotal, oldTotal, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } static async getListJoin(joinParams, where, fields, orderBy, page = 1, size, isTotal = true, oldTotal = 0, is2Many = false, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getListJoin(joinParams, where, fields, orderBy, page, size, isTotal, oldTotal, is2Many); } static async getListJoinCount(joinParams, where, mustPID = true) { where = MultiModel._getWhere(where, mustPID); return await super.getListJoinCount(joinParams, where); } } module.exports = MultiModel; ================================================ FILE: cloudfunctions/mcloud/framework/lib/faker_lib.js ================================================ /** * Notes: 测试数据构造类 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-05-26 14:00:00 */ const timeUtil = require('../utils/time_util.js'); /** 随机获取数据 */ function getRnd(arr, isNullable = false, ex = '') { if (isNullable) { // 允许为空 let rd = getIntBetween(0, 1); if (rd % 2 == 0) return ''; } if (!Array.isArray(arr)) { arr = arr.replace(/ /g, '').replace(/,/g, ',').split(','); } let exArr = ex.replace(/ /g, '').replace(/,/g, ',').split(','); let ret = ''; let i = 0; while (true) { i++; if (i > 1000) return ''; ret = arr[Math.floor((Math.random() * arr.length))]; if (!exArr.includes(ret)) return ret; } } /** 省份 */ function getProvince(isNullable = false, ex = '') { let data = ['北京市', '天津市', '河北省', '山西省', '内蒙古自治区', '辽宁省', '吉林省', '黑龙江省', '上海市', '江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区', '海南省', '重庆市', '四川省', '贵州省', '云南省', '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区', '新疆维吾尔自治区', '香港特别行政区', '澳门特别行政区', '台湾省' ]; return getRnd(data, isNullable, ex); } function getProvinceAbbr(isNullable = false, ex = '') { let data = ['京', '皖', '渝', '闽', '甘', '粤', '桂', '黔', '琼', '冀', '豫', '黑', '鄂', '湘', '吉', '苏', '赣', '辽', '蒙', '宁', '青', '鲁', '晋', '陕', '沪', '川', '津', '藏', '新', '滇', '浙', '港', '澳', '台' ]; return getRnd(data, isNullable, ex); } /** 城市 */ function getCity(isNullable = false, ex = '') { let data = ['北京', '上海', '天津', '重庆', '哈尔滨', '长春', '沈阳', '呼和浩特', '石家庄', '乌鲁木齐', '兰州', '西宁', '西安', '银川', '郑州', '济南', '太原', '合肥', '武汉', '长沙', '南京', '成都', '贵阳', '昆明', '南宁', '拉萨', '杭州', '南昌', '广州', '福州', '海口', '香港', '澳门' ]; return getRnd(data, isNullable, ex); } /** 地区 */ function getArea(isNullable = false, ex = '') { let data = ['西夏区', '永川区', '秀英区', '高港区', '清城区', '兴山区', '锡山区', '清河区', '龙潭区', '华龙区', '海陵区', '滨城区', '东丽区', '高坪区', '沙湾区', '平山区', '城北区', '海港区', '沙市区', '双滦区', '长寿区', '山亭区', '南湖区', '浔阳区', '南长区', '友好区', '安次区', '翔安区', '沈河区', '魏都区', '西峰区', '萧山区', '金平区', '沈北新区', '孝南区', '上街区', '城东区', '牧野区', '大东区', '白云区', '花溪区', '吉利区', '新城区', '怀柔区', '六枝特区', '涪城区', '清浦区', '南溪区', '淄川区', '高明区', '金水区', '中原区', '高新开发区', '经济开发新区', '新区' ]; return getRnd(data, isNullable, ex); } /** 街道 */ function getStreet(isNullable = false, ex = '') { let data = '朱雀大街,太乙路,太白路,太华路,长乐坊,长樱路,案板街,竹笆市,骡马市,东木头市,西木头市,安仁坊,端履门,德福巷,洒金桥,冰窖巷,菊花园,下马陵,粉巷,索罗巷,后宰门,书院门,炭市街,马厂子,景龙池,甜水井,柏树林,桃花坞,人民路,解放路,黄河路,长江路,中山路,抚顺街,天津街,上海路,胜利路,西安路,长春路,太原街,沈阳路,鞍山路,五四路,唐山街,武汉街,延安路,朝阳街,鲁迅路,八一路,东北路,华南路,华北路,山东路,松江路,东方路,南沙街'; return getRnd(data, isNullable, ex); } /** 门牌地址 */ function getAddress() { return getProvince() + '' + getCity() + '市' + getArea() + '' + getStreet() + getIntBetween(1, 100) + '号'; } /** 国家 */ function getCountry(isNullable = false, ex = '') { let data = ['阿富汗', '阿拉斯加', '阿尔巴尼亚', '阿尔及利亚', '安道尔', '安哥拉', '安圭拉岛英', '安提瓜和巴布达', '阿根廷', '亚美尼亚', '阿鲁巴岛', '阿森松', '澳大利亚', '奥地利', '阿塞拜疆', '巴林', '孟加拉国', '巴巴多斯', '白俄罗斯', '比利时', '伯利兹', '贝宁', '百慕大群岛', '不丹', '玻利维亚', '波斯尼亚和黑塞哥维那', '博茨瓦纳', '巴西', '保加利亚', '布基纳法索', '布隆迪', '喀麦隆', '加拿大', '加那利群岛', '佛得角', '开曼群岛', '中非', '乍得', '智利', '圣诞岛', '科科斯岛', '哥伦比亚', '巴哈马国', '多米尼克国', '科摩罗', '刚果', '科克群岛', '哥斯达黎加', '克罗地亚', '古巴', '塞浦路斯', '捷克', '丹麦', '迪戈加西亚岛', '吉布提', '多米尼加共和国', '厄瓜多尔', '埃及', '萨尔瓦多', '赤道几内亚', '厄立特里亚', '爱沙尼亚', '埃塞俄比亚', '福克兰群岛', '法罗群岛', '斐济', '芬兰', '法国', '法属圭亚那', '法属波里尼西亚', '加蓬', '冈比亚', '格鲁吉亚', '德国', '加纳', '直布罗陀', '希腊', '格陵兰岛', '格林纳达', '瓜德罗普岛', '关岛', '危地马拉', '几内亚', '几内亚比绍', '圭亚那', '海地', '夏威夷', '洪都拉斯', '匈牙利', '冰岛', '印度', '印度尼西亚', '伊郎', '伊拉克', '爱尔兰', '以色列', '意大利', '科特迪瓦', '牙买加', '日本', '约旦', '柬埔塞', '哈萨克斯坦', '肯尼亚', '基里巴斯', '朝鲜', '韩国', '科威特', '吉尔吉斯斯坦', '老挝', '拉脱维亚', '黎巴嫩', '莱索托', '利比里亚', '利比亚', '列支敦士登', '立陶宛', '卢森堡', '马其顿', '马达加斯加', '马拉维', '马来西亚', '马尔代夫', '马里', '马耳他', '马里亚纳群岛', '马绍尔群岛', '马提尼克', '毛里塔尼亚', '毛里求斯', '马约特岛', '墨西哥', '密克罗尼西亚', '中途岛', '摩尔多瓦', '摩纳哥', '蒙古', '蒙特塞拉特岛', '摩洛哥', '莫桑比克', '缅甸', '纳米比亚', '瑙鲁', '尼泊尔', '荷兰', '荷属安的列斯群岛', '新喀里多尼亚群岛', '新西兰', '尼加拉瓜', '尼日尔', '尼日利亚', '纽埃岛', '诺福克岛', '挪威', '阿曼', '帕劳', '巴拿马', '巴布亚新几内亚', '巴拉圭', '秘鲁', '菲律宾', '波兰', '葡萄牙', '巴基斯坦', '波多黎各', '卡塔尔', '留尼汪岛', '罗马尼亚', '俄罗斯', '卢旺达', '东萨摩亚', '西萨摩亚', '圣马力诺', '圣皮埃尔岛及密克隆岛', '圣多美和普林西比', '沙特阿拉伯', '塞内加尔', '塞舌尔', '新加坡', '斯洛伐克', '斯洛文尼亚', '所罗门群岛', '索马里', '南非', '西班牙', '斯里兰卡', '圣克里斯托弗和尼维斯', '圣赫勒拿', '圣卢西亚', '圣文森特岛', '苏丹', '苏里南', '斯威士兰', '瑞典', '瑞士', '叙利亚', '塔吉克斯坦', '坦桑尼亚', '泰国', '阿拉伯联合酋长国', '多哥', '托克劳群岛', '汤加', '特立尼达和多巴哥', '突尼斯', '土耳其', '土库曼斯坦', '特克斯和凯科斯群岛(', '图瓦卢', '美国', '乌干达', '乌克兰', '英国', '乌拉圭', '乌兹别克斯坦', '瓦努阿图', '梵蒂冈', '委内瑞拉', '越南', '维尔京群岛', '维尔京群岛和圣罗克伊', '威克岛', '瓦里斯和富士那群岛', '西撒哈拉', '也门', '南斯拉夫', '扎伊尔', '赞比亚', '桑给巴尔', '津巴布韦', '中华人民共和国', '中国' ]; return getRnd(data, isNullable, ex); } /** 公司简称 */ function getCompanyPrefix(isNullable = false, ex = '') { let data = ['超艺', '和泰', '九方', '鑫博腾飞', '戴硕电子', '济南亿次元', '海创', '创联世纪', '凌云', '泰麒麟', '彩虹', '兰金电子', '晖来计算机', '天益', '恒聪百汇', '菊风公司', '惠派国际公司', '创汇', '思优', '时空盒数字', '易动力', '飞海科技', '华泰通安', '盟新', '商软冠联', '图龙信息', '易动力', '华远软件', '创亿', '时刻', '开发区世创', '明腾', '良诺', '天开', '毕博诚', '快讯', '凌颖信息', '黄石金承', '恩悌', '雨林木风计算机', '双敏电子', '维旺明', '网新恒天', '数字100', '飞利信', '立信电子', '联通时科', '中建创业', '新格林耐特', '新宇龙信息', '浙大万朋', 'MBP软件', '昂歌信息', '万迅电脑', '方正科技', '联软', '七喜', '南康', '银嘉', '巨奥', '佳禾', '国讯', '信诚致远', '浦华众城', '迪摩', '太极', '群英', '合联电子', '同兴万点', '襄樊地球村', '精芯', '艾提科信', '昊嘉', '鸿睿思博', '四通', '富罳', '商软冠联', '诺依曼软件', '东方峻景', '华成育卓', '趋势', '维涛', '通际名联' ]; return getRnd(data, isNullable, ex); } /** 公司类型 */ function getCompanyType(isNullable = false, ex = '') { let data = ['科技', '网络', '信息', '传媒', '集团', '控股', '投资', '制造']; return getRnd(data, isNullable, ex); } /** 公司名 */ function getCompany(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; return getCompanyPrefix(false, ex) + getCompanyType() + '有限公司'; } /** 内容 */ function getContent(size = 1, isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = [ '燕舞,燕舞,一曲歌来一片情。', '康师傅方便面,好吃看得见。', '不要太潇洒!', '让一亿人先聪明起来。', '共创美的前程,共度美的人生。', '省优,部优,葛优?', '喝孔府宴酒,做天下文章。', '健康成就未来。', '牙好,胃口就好,身体倍儿棒,吃嘛嘛香。', '永远的绿色,永远的秦池。', '坐红旗车,走中国路。', '要想皮肤好,早晚用大宝。', '孔府家酒,叫人想家。', '补钙新观念,吸收是要害。', '喝汇源果汁,走健康之路。', '爱的就是你!', '一种可以世袭的古典浪漫', '实力创造价值', '爱生活,爱拉芳!', '人类失去联想,世界将会怎样?', '做女人挺好!', '世界在你眼中?', '今天你有否亿唐?', '只溶在口,不溶在手。', '三千烦恼丝,健康新开始。', '维维豆奶,欢乐开怀。', '我们的光彩来自你的风采。', '钻石恒久远,一颗永流传。', '放我的真心在你的手心。', '小身材,大味道。', '牛奶香浓,丝般感受。', '聆听并不代表沉默,有时安静也是一种力量。', '滴滴香浓,意犹未尽。', '水晶之恋,一生不变。', '中国移动通信,沟通从心开始!', '网易,网聚人的力量!', '科技以人为本,诺基亚', '我们一直在努力!', '阳光总在风雨后', '男人对西服的要求,就是女人对男人的要求', '晚报,不晚报', '原来生活可以更美的', '明天的明天,你还会送我“水晶之恋”吗?', '卫浴出出进进的快感', '有家就有联合利华', '减脂减肥,其实是一种生活态度', '人头马一开,好事自然来。', '假如五指一样长,怎能满足用户不同需求?', '新飞广告做的好,不好新飞冰箱好', '传奇品质,百年张裕', '李宁:把出色留给自己', '一旦拥有,别无选择', '科技让你更轻松', '情系中国结,联通四海心', '海尔,中国造', 'SOHU:足迹生活每一天', '果冻我要喜之郎', '国宝大熊猫,心纯天自高', '世界因为不同', '放低偏见,你会有出色发现!', 'Just', '创意似金,敬业如牛', '不要让男人一手把握', '如同情人的手', '金窝银窝,不如自己的安乐窝。', '没有什么大不了的', '时间因我存在', '只要有梦想', '南方周末', '时间改变一切', '地球人都知道了', '众里寻他千百度,想要几度就几度', '您身边的银行,可信赖的银行', '三叶钢琴:学琴的孩子不会变坏', '柯达:串起生活每一刻', '大众甲克虫汽车:想想还是小的好', '一直被模拟,从未被超越', '幸福生活', '朗讯的创造力科技的原动力', '事事因你而出色', '运动之美,世界共享', '鹤舞白沙', '想知道“清嘴”的味道吗?', '弹指一挥间,世界皆互联', '更多选择、更多欢笑', '方太,让家的感觉更好', '世上仅此一件,今生与你结缘!', '白里透红与众不同', '没有蛀牙-佳洁士', '有线的价值', '享受快乐科技', '四海一家的解决之道', '娃哈哈纯净水:爱你等于爱自己', '农民山泉:有点甜', '博大精深,西门子', '一切尽在把握', '声声百思特,遥遥两相知', '一呼天下应', '让我们做得更好!', '暖和亲情,金龙鱼的大家庭。', '自然最健康,绿色好心情', '支起网络世界', '立邦漆:处处放光彩!', 'fm365:真情互动!', '庄重一生,吉祥一生。', '人人都为礼品愁,我送北极海狗油。', '假如说人生的离合是一场戏,那么百年的好合更是早有安排!', '一品黄山天高云淡', '上上下下的享受!', '我是、我行、我素', '让无力者有力,让悲观者前行', '金利来—-男人的世界!', '百衣百顺', '聪明何必绝顶,慧根长留', '水往高处流', '大石化小,小石化了!', '“闲”妻良母', '“口服”,“心服”!', '盛满青春的秘密!', '三十六计走为上', '为了她的节日,献上您纯金般的心!', '用我们的钓线,你可以在鱼儿发现你之前先找到它', '生活就是一场运动,喝下它。', '选择维聚阿尔,已经表明你心明眼亮。', '佳能,我们看得见你想表达什么。', '天天都是春天', '假如你不来,广告明星就是他', '享受黑夜中偷拍的快感!', '彩信发送动人一刻', '灵感点亮生活!', '聪明演绎,无处不在!', '事业我一定争取,对你我从未放弃!', '波导手机,手机中的战斗机', '鄂尔多斯羊绒衫暖和全世界', '洁婷245再大的动作也不要紧', '做光明的牛,产光明的奶', '假如你的汽车会游泳的话,请照直开,不必刹车。', '永远要让驾驶执照比你自己先到期。', '请记住,上帝并不是十全十美的,它给汽车预备了备件,而人没有。', '小别意酸酸,欢聚心甜甜。', '除钞票外,承印一切。', '更多欢乐,更多选择', '美由你做主', '由我天地宽', 'Sun是太阳,Java是月亮。', '不断创新,因为专心', '趁早下『斑』,请勿『痘』留。', '创新就是生活', '有一个漂亮的地方,万科四季花城', '建筑无限生活', '臭名远扬,香飘万里', '尝尝欢笑,经常麦当劳', '深入成就深度', '出色湖南,红网了然!', '因为网络,地球如村!', '一种质感', '恒久期盼', '繁荣民族文化', '不信,死给你看!', '天生的,强生的', '雪津啤酒,真情的味道!', '听世界,打天下', '雅芳比女人更了解女人', 'Sun是太阳,Java是月亮。', '中国网通', '无线你的无限', '家有三洋,冬暖夏凉', '倾诉冬日暖语', '谁让我心动?', '灵活,让篮球场不再是一个平面', '别吻我,我怕修。', '一呼四应!', '无所不包!', '当之无愧', '以帽取人!', '一毛不拔!', '自讨苦吃!', '成功与科技共辉映', '没有最', ]; if (size == 1) return getRnd(data, false, ex); else { ret = ''; for (let i = 0; i < size; i++) { ret += getRnd(data, false, ex) + ', '; } return ret; } } /** 获得一句话 */ function getWord(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let ret = getContent(1, false, ex); ret = ret.replace('。', '').replace('!', '').replace('?', '').replace('“', '”').replace(':', ''); return ret; } /** 星期 */ function getWeek(isNullable = false, ex = '') { let data = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; return getRnd(data, isNullable, ex); } /** 月份 */ function getMonth(isNullable = false, ex = '') { let data = ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']; return getRnd(data, isNullable, ex); } /** 获得姓名 */ function getFirstName(isNullable = false, ex = '') { let data = ['李', '王', '张', '刘', '陈', '杨', '赵', '黄', '周', '吴', '徐', '孙', '胡', '朱', '高', '林', '何', '郭', '马', '罗', '梁', '宋', '郑', '谢', '韩', '唐', '冯', '于', '董', '萧', '程', '曹', '袁', '邓', '许', '傅', '沉', '曾', '彭', '吕', '苏', '卢', '蒋', '蔡', '贾', '丁', '林', '薛', '叶', '阎', '余', '潘', '杜', '戴', '夏', '钟', '汪', '田', '任', '姜', '范', '方', '石', '姚', '谭', '廖', '邹', '熊', '金', '陆', '郝', '孔', '白', '崔', '康', '毛', '邱', '秦', '江', '史', '顾', '侯', '邵', '孟', '龙', '万', '段', '雷', '钱', '汤', '尹', '黎', '易', '常', '武', '乔', '贺', '赖', '龚', '文', '庞', '樊', '兰', '殷', '施', '陶', '洪', '翟', '安', '颜', '倪', '严', '牛', '温', '芦', '季', '俞', '章', '鲁', '葛', '伍', '韦', '申', '尤', '毕', '聂', '丛', '焦', '向', '柳', '邢', '路', '岳', '齐', '沿', '梅', '莫', '庄', '辛', '管', '祝', '左', '涂', '谷', '祁', '时', '舒', '耿', '牟', '卜', '路', '詹', '关', '苗', '凌', '费', '纪', '靳', '盛', '童', '欧', '甄', '项', '曲', '成', '游', '阳', '裴', '席', '卫', '查', '屈', '鲍', '位', '覃', '霍', '翁', '隋', '植', '甘', '景', '薄', '单', '包', '司', '柏', '宁', '柯', '阮', '桂', '闵', '欧阳', '解', '强', '柴', '华', '车', '冉', '房', '边', '辜', '吉', '饶', '刁', '瞿', '戚', '丘', '古', '米', '池', '滕', '晋', '苑', '邬', '臧', '畅', '宫', '来', '嵺', '苟', '全', '褚', '廉', '简', '娄', '盖', '符', '奚', '木', '穆', '党', '燕', '郎', '邸', '冀', '谈', '姬', '屠', '连', '郜', '晏', '栾', '郁', '商', '蒙', '计', '喻', '揭', '窦', '迟', '宇', '敖', '糜', '鄢', '冷', '卓', '花', '仇', '艾', '蓝', '都', '巩', '稽', '井', '练', '仲', '乐', '虞', '卞', '封', '竺', '冼', '原', '官', '衣', '楚', '佟', '栗', '匡', '宗', '应', '台', '巫', '鞠', '僧', '桑', '荆', '谌', '银', '扬', '明', '沙', '薄', '伏', '岑', '习', '胥', '保', '和', '蔺' ]; return getRnd(data, isNullable, ex); } /** 女生名 */ function getFemaleName(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = ['芳', '娜', '敏', '静', '敏静', '秀英', '丽', '洋', '艳', '娟', '文娟', '君', '文君', '珺', '霞', '明霞', '秀兰', '燕', '芬', '桂芬', '玲', '桂英', '丹', '萍', '华', '红', '玉兰', '桂兰', '英', '梅', '莉', '秀珍', '雪', '依琳', '旭', '宁', '婷', '馨予', '玉珍', '凤英', '晶', '欢', '玉英', '颖', '红梅', '佳', '倩', '琴', '兰英', '云', '洁', '爱华', '淑珍', '春梅', '海燕', '晨', '冬梅', '秀荣', '瑞', '桂珍', '莹', '秀云', '桂荣', '秀梅', '丽娟', '婷婷', '玉华', '琳', '雪梅', '淑兰', '丽丽', '玉', '秀芳', '欣', '淑英', '桂芳', '丽华', '丹丹', '桂香', '淑华', '秀华', '桂芝', '小红', '金凤', '文', '利', '楠', '红霞', '瑜', '桂花', '璐', '凤兰', '腊梅', '瑶', '嘉', '怡', '冰冰', '玉梅', '慧', '婕' ]; return getFirstName(false, ex) + getRnd(data, false, ex); } /** 男生名 */ function getMaleName(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = ['伟', '强', '磊', '洋', '勇', '军', '杰', '涛', '超', '明', '刚', '平', '辉', '鹏', '华', '飞', '鑫', '波', '斌', '宇', '浩', '凯', '健', '俊', '帆', '帅', '旭', '宁', '龙', '林', '欢', '阳', '建华', '亮', '成', '畅', '建', '峰', '建国', '建军', '晨', '瑞', '志强', '兵', '雷', '东', '欣', '博', '彬', '坤', '全安', '荣', '岩', '杨', '文', '利', '楠', '建平', '嘉俊', '晧', '建明', '子安', '新华', '鹏程', '学明', '博涛', '捷', '文彬', '楼', '鹰', '松', '伦', '超', '钟', '瑜', '振国', '洪', '毅', '昱然', '哲', '翔', '翼', '祥', '国庆', '哲彦', '正诚', '正豪', '正平', '正业', '志诚', '志新', '志勇', '志明', '志强', '志文', '致远', '智明', '智勇', '智敏', '智渊' ]; return getFirstName(false, ex) + getRnd(data, false, ex); } /** 随机获得姓名 */ function getName(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let rd = Math.round(Math.random()); return (rd % 2 == 0) ? getFemaleName(false, ex) : getMaleName(false, ex); } /** 身份证号码 */ function getIdCard(birthday = '', isNullable = false) { if (getNullable(isNullable)) return ''; let coefficientArray = ["7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"]; // 加权因子 let lastNumberArray = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]; // 校验码 let address = "420101"; // 住址 if (!birthday) birthday = "19810101"; // 生日 let s = Math.floor(Math.random() * 10).toString() + Math.floor(Math.random() * 10).toString() + Math.floor(Math.random() * 10).toString(); let array = (address + birthday + s).split(""); let total = 0; for (i in array) { total = total + parseInt(array[i]) * parseInt(coefficientArray[i]); } let lastNumber = lastNumberArray[parseInt(total % 11)]; let str = address + birthday + s + lastNumber; return str; } /** 手机号码 */ function getMobile(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = ['133', '149', '153', '173', '177', '180', '181', '189', '190', '191', '193', '199', '130', '131', '132', '145', '155', '156', '166', '167', '171', '175', '176', '185', '186', '196', '134', '135', '136', '137', '138', '139', '147', '148', '150', '151', '152', '157', '158', '159', '172', '178', '182', '183', '184', '187', '188', '195', '197', '198']; return getRnd(data, false, ex) + getInt(8); } /** 电话号码 */ function getPhone(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = ['010', '021', '022', '023', '020', '024', '025', '027', '028', '029', '0755', '0731', '0769']; return getRnd(data, false, ex) + '-' + getInt(8); } /** 常用英文单词 */ function getEnWord(isNullable = false, ex = '') { let data = 'earthday,org,suggests,that,every,household,take,time,this,earth,day,to,perform,a,plastic,audit,which,involves,counting,how,many,plastic,containers,wraps,bottles,and,bags,are,purchased,for,at,home,use,it,may,surprise,you,how,many,you,use,until,you,start,counting,while,were,not,saying,that,you,have,to,get,rid,of,every,single,ounce,of,plastic,in,your,home,it,is,important,to,be,aware,of,your,familys,plastic,usage,and,to,take,time,to,research,more,sustainable,products,and,start,to,incorporate,them,into,your,daily,life,simple,swaps2,like,glass,containers,instead,of,plastic,or,stainless3,steel,bottles,instead,of,single,use,plastics,can,go,a,long,way,to,making,a,difference'; return getRnd(data, isNullable, ex); } /** 常用域名 */ function getDomain(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = 'com,net,org,cn,hk,us,uk,jp,kr'; return '.' + getRnd(data, false, ex); } /** 常用邮箱 */ function getEmail(isNullable = false, ex = '') { if (getNullable(isNullable)) return ''; let data = 'qq.com,163.com,gmail.com,263.com,tom.com,163.net,189.cn,sina.com,sohu.com,360.com,tencent.com,china.com,netease.com,126.com,139.com'; return getEnWord() + '@' + getRnd(data, false, ex); } /** 获取时间戳 step 秒 */ function getTimestamp(step = 0) { return timeUtil.time() + step * 1000; } /** * 以当天为基点,获取随机时间戳,默认为当天 * @param {*} min 起始天 * @param {*} max 终止天 */ function getAddTimestamp(min = 0, max = 1) { let now = timeUtil.timestamp2Time(timeUtil.time(), 'Y-M-D'); //转为当天0点 now = timeUtil.time2Timestamp(now); return now + getIntBetween(min * 86400 * 1000, max * 86400 * 1000); } /** 生日 */ function getDate(start = 1900, end = 2020) { start = start + '-01-01 00:00:00'; start = timeUtil.time2Timestamp(start); end = end + '-12-31 23:59:59'; end = timeUtil.time2Timestamp(end); let time = getIntBetween(start, end); return timeUtil.timestamp2Time(time, 'Y-M-D'); } /** 整数 */ function getInt(size) { let t = ''; for (var i = 0; i < size; i++) { t += Math.floor(Math.random() * 10); } return t; } /** 随机数组 */ function getRdArr(arr) { return getRnd(arr); } /** 随机数 */ function getIntBetween(min, max) { return min + Math.floor(Math.random() * (max - min + 1)); } /** 随机字符串 */ function getStr(size) { let text = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let rdmIndex = text => Math.random() * text.length | 0; let rdmString = ''; for (; rdmString.length < size; rdmString += text.charAt(rdmIndex(text))); return rdmString; } /** 随机数字字符串 */ function getIntStr(size) { let text = '0123456789'; let rdmIndex = text => Math.random() * text.length | 0; let rdmString = ''; for (; rdmString.length < size; rdmString += text.charAt(rdmIndex(text))); return String(rdmString); } /** 随机字符串小写 */ function getStrLower(size) { return getStr(size).toLowerCase(); } /** 随机字符串大写 */ function getStrUpper(size) { return getStr(size).toUpperCase(); } function getUuid() { let s = []; let hexDigits = "0123456789abcdef"; for (var i = 0; i < 36; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); } s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 s[8] = s[13] = s[18] = s[23] = "-"; let uuid = s.join(""); return uuid; } /** 学院 */ function getCollege(isNullable = false, ex = '') { let data = '地球科学学院,环境科学与工程学院,化学与生物工程学院,材料科学与工程学院,土木与建筑工程学院,测绘地理信息学院,信息科学与工程学院,机械与控制工程学院,珠宝学院,马克思主义学院,公共管理与传媒学院,商学院,旅游与风景园林学院,艺术学院,外国语学院,理学院,文学与新闻传播学院,外国语学院,建筑与艺术学院,商学院,法学院,马克思主义学院,公共管理学院,数学与统计学院,物理与电子学院,化学化工学院,文学系,法学系,哲学系,医学系,力学系,理学系,数学系,物理系,化学系,计算机系,自动化系,口腔医学系,英语系,外语系,法语系,德语系,日语系,西班牙语系'; return getRnd(data, isNullable, ex); } /** 专业 */ function getItem(isNullable = false, ex = '') { let data = '音乐表演,音乐学,作曲与作曲技术理论,舞蹈表演,舞蹈学,舞蹈编导,舞蹈教育,航空服务艺术与管理,流行音乐,音乐治疗,流行舞蹈,表演,戏剧学,电影学,戏剧影视文学,广播电视编导,戏剧影视导演,戏剧影视美术设计,录音艺术,播音与主持艺术,动画,美术学,绘画,雕塑,摄影,书法学,中国画,实验艺术,跨媒体艺术,文物保护与修复,漫画,艺术设计学,视觉传达设计,环境设计,产品设计,服装与服饰设计,公共艺术,工艺美术,数字媒体艺术,艺术与科技,陶瓷艺术设计,新媒体设计,包装设计,教育学,科学教育,人文教育,教育技术学,艺术教育,学前教育,小学教育,特殊教育,华文教育,教育康复学,卫生教育,法学,知识产权,监狱学,信用风险管理与法律防控,国际经贸规则,司法警察学,社区矫正,工商管理,市场营销,会计学,财务管理,国际商务,人力资源管理,审计学,资产评估,物业管理,文化产业管理,劳动关系,体育经济与管理,财务会计教育,市场营销教育,零售业管理,农林经济管理,农村区域发展 ,公共事业管理,行政管理,劳动与社会保障,土地资源管理,城市管理,海关管理,交通管理,海事管理,公共关系学,健康服务与管理,海警后勤管理,数学与应用数学,信息与计算科学,数理基础科学,数据计算及应用 ,物理学,应用物理学,核物理,声学,系统科学与工程,地理科学,自然地理与资源环境,人文地理与城乡规划,地理信息科学 ,机械设计制造及其自动化,材料成型及控制工程,机械电子工程,工业设计,过程装备与控制工程,车辆工程,汽车服务工程,机械工艺技术,微机电系统工程,机电技术教育,汽车维修工程教育,智能制造工程,材料科学与工程材料物理,材料化学,冶金工程,金属材料工程,无机非金属材料工程,高分子材料与工程,复合材料与工程,粉体材料科学与工程,宝石及材料工艺学,焊接技术与工程,功能材料,纳米材料与技术,新能源材料与器件,材料设计科学与工程,光电信息科学与工程,信息工程,广播电视工程,水声工程,电子封装技术,集成电路设计与集成系统,医学信息工程,电磁场与无线技术,电波传播与天线,电子信息科学与技术,电信工程及管理,应用电子技术教育,数字媒体技术,智能科学与技术,空间信息与数字技术,电子与计算机工程,数据科学与大数据技术,网络空间安全,新媒体技术,电影制作,保密技术,服务科学与工程,虚拟现实技术,区块链工程,建筑环境与能源应用工程,给排水科学与工程,建筑电气与智能化,城市地下空间工程,道路桥梁与渡河工程,铁道工程,智能建造,土木、水利与海洋工程,土木、水利与交通工程,采矿工程,石油工程,矿物加工工程,油气储运工程,矿物资源工程,海洋油气工程 ,纺织工程,服装设计与工程,非织造材料与工程,服装设计与工艺教育,丝绸设计与工程'; return getRnd(data, isNullable, ex); } /** 行业 */ function getTrade(isNullable = false, ex = '') { let data = ['经营', '销售', '市场营销', '公关', '客户服务', '人力资源', '行政HR', '财务/审计/统计', '文职', '翻译', '计算机/IT', '电子/通讯', '设计', '工业/工厂', '金融/经济', '法律', '机械', '技工', '房地产/土建', '咨询/顾问', '医疗/护理/保健', '服务业', '政府机关', '事业单位', '学生/研究生', '化工', '冶金/地质']; return getRnd(data, isNullable, ex); } /** 学历 */ function getEdu(isNullable = false, ex = '') { let data = '中学,高职,大专,本科,硕士,博士,博士后,其他'; return getRnd(data, isNullable, ex); } /** 职位 */ function getDuty(isNullable = false, ex = '') { let data = 'CTO,CEO,CFO,研发,销售,采购,董事长,老板,自由自由者,中层领导,部门经理,大区经理'; return getRnd(data, isNullable, ex); } /** 资源 */ function getResource(isNullable = false, ex = '') { let data = '法律咨询,管理咨询,企业辅导,上市辅导,创业交流,投资融资,医疗咨询,教育交流,开发技术交流,研发交流,未来探讨,大宗商品,销售网络共享,艺术品鉴赏,供应链共享,进修交流,财会督导,审计辅导,企业治理,工程监理,硬件生产,小商品生产,电商,二类电商,早教,公考,艺术设计,人力资源,地质勘探,招工招聘,游戏开发,销售采购,市场营销,电子通讯,经济探讨,机械制造,产业经理,轻工业,化工化学,海外电商,企业出海,翻译,心理咨询,餐饮酒店,民宿,旅游自驾,服务业,租车,自媒体新媒体行业,文职人员,军迷,学习共勉,体育活动,打球约饭,户外旅行,文艺青年,小镇青年,斜杠青年,交通运输,民航机票,系统集成,售前服务,维修'; return getRnd(data, isNullable, ex); } /** 自我介绍 */ function getMotto(isNullable = false, ex = '') { let data = '生无一锥土,常有四海心 ,志在山顶的人,不会贪念山腰的风景 ,人之所以能,是相信能 ,卒子过河,意在吃帅 ,心志要坚,意趣要乐 ,贫困教会贫困者一切 ,欲望以提升热忱,毅力以磨平高山 ,人生不得行胸怀,虽寿百岁犹为无也 ,人之所以异于禽者,唯志而已矣!,每一发奋努力的背后,必有加倍的赏赐 ,治天下者必先立其志 ,以天下为己任 ,一人立志,万夫莫敌 ,志高山峰矮,路从脚下伸 ,鹰爱高飞,鸦栖一枝 ,莫为一身之谋,而有天下之志 ,人之所以能,是相信能,励志短语,没有天生的信心,只有不断培养的信心 ,世上没有绝望的处境,只有对处境绝望的人 ,人格的完善是本,财富的确立是末 ,在年轻人的颈项上,没有什么东西能比事业心这颗灿烂的宝珠 ,壮志与毅力是事业的双翼 ,心有多大,舞台就有多大 ,志正则众邪不生 ,母鸡的理想不过是一把糠 ,死犹未肯输心去,贫亦其能奈我何!,鸟贵有翼,人贵有志 ,有志登山顶,无志站山脚 ,没有一种不通过蔑视忍受和奋斗就可以征服的命运 ,远大的希望造就伟大的人物 ,志不立,天下无可成之事 ,有志者能使石头长出青草来 ,莫找借口失败,只找理由成功 ,男子千年志,吾生未有涯 ,鱼跳龙门往上游 ,有志者,事竟成 ,强行者有志 ,心随朗月高,志与秋霜洁 ,与其当一辈子乌鸦,莫如当一次鹰 ,石看纹理山看脉,人看志气树看材 ,志当存高远 ,任何的限制,都是从自己的内心开始的 ,志,气之帅也 ,一个人如果胸无大志,既使再有壮丽的举动也称不上是伟人 ,立志是事业的大门,工作是登门入室的旅程 ,志气和贫困是患难兄弟,世人常见他们伴在一起 ,失败是成功之母 ,对的,坚持;错的,放弃!,丈夫志不大,何以佐乾坤 ,鸭仔无娘也长大,几多白手也成家 ,我走得很慢,但是我从来不会后退,面对太阳,阴影将落在你的背后,困境之中,饱含机遇,执着于理想,纯粹于当下,不要轻言放弃,否则对不起自己,含泪播种的人一定能含笑收获,日益努力,而后风生水起,若要梦想实现,先从梦中醒来,今天比昨天好,就是希望,希望叫醒你的不是闹钟而是理想,坚定信念的人都是英雄,欲戴皇冠,必承其重,昨日之深渊,来日之浅谈,天越黑,星星越亮,岂能尽如人意,但求无愧我心,世上没什么运气,只有努力去挑战,日出之美便在于它脱胎于最深的黑暗,不要等待机会,而要创造机会,成功的秘诀在于对目标的执着追求,我把苦难挫折当作自己生存的最好导师,黑夜无论怎样悠长,白昼总会到来,海到无边天作岸,山登绝顶我为峰,除了放弃尝试以外没有失败,有梦就别怕痛,想赢就别喊停, 与其羡慕别人,不如自己努力,努力就能成功,坚持确保胜利,永不言败,是成功者的最佳品格,人生没有彩排,每天都是现场直播,火把倒下,火焰依然向上,低头哭过别忘了抬头继续走,有种脾气叫不放弃,风乍起,合当奋意向人生,莫问收获,但问耕耘,即使身在生活,也要做你理想的卧底,我只身前行,却仿佛带着一万雄兵,熬过一切,星光璀璨,没有人帮你,说明你一个人可以,让理想生活的样子清晰可见,趁我们头脑发热,我们要不顾一切,念念不忘,必有回响,一生很短,你要大胆,容易走的路,一般都很拥挤,那些杀不死我们的,终将让我们更强大,你利用时间的方式,就是塑造自己的方式,每一个不曾起舞的日子,都是对生命的辜负,猛兽总是独行,牛羊才成群结队,你迷茫的原因在于读书太少而想的太多,对未来真正的慷慨,是把一切献给现在,没有一点儿疯狂,生活就不值得过,生活在阴沟里,但仍有人仰望星空,怕输的人已经输了,不要忘记人生是要战斗到死, 抱怨身处黑暗,不如提灯前行,患难困苦,是磨炼人格之高等学校,失败不是悲剧,放弃才是,画工须画云中龙,为人须为人中雄,博观而约取,厚积而薄发,志在山顶的人,不会贪恋山腰的风景,别为失败找理由,要为成功找方法,迷失的时候,选择更艰辛的那条路,命是弱者的借口,运是强者的谦词,如果今天不走的话,明天就要跑,今天度过的一天明天就找不回来了,生活绝不会因为你胆小怯懦而饶过你,最可怕的敌人,就是没有坚强的信念,梦想一旦被付诸行动,就会变得神圣,寄言燕雀莫相唣,自有云霄万里高,人若有志,万事可为,志不可一日坠,人不可一日放,苦难,是化了妆的祝福,没有实力的愤怒毫无意义,在避风的港湾里,找不到昂扬的帆,大胆的尝试只等于成功了一半,天才就是无止境刻苦勤奋的能力,你是自己人生的设计师,苦想没盼头,苦干有奔头,世界会向那些有目标和远见的人让路,挫折其实就是迈向成功所应缴的学费,欲望以提升热忱,毅力以磨平高山,用行动祈祷比用言语更能够使上帝了解,志不立,天下无可成之事,志向和热爱是伟大行为的双翼,水激石则鸣,人激志则宏,雄心壮志是茫茫黑夜中的北斗星,贫而懒惰乃真穷,贱而无志乃真贱,目标越接近,困难越增加,绳锯木断,水滴石穿,男儿不展风云志,空负天生八尺躯,天才就是无止境刻苦勤奋的能力,苦难是人生的老师,成功的秘诀,在永不改变既定的目的,平凡的脚步也可以走完伟大的行程,如果你有梦想的话,就要去捍卫它,永远要面对眼前的这些困境,如果我放弃,就是向那些错看我的人屈服,运气,就是机会碰巧撞到了你的努力,哪有什么胜利可言,挺住就意味着一切,过去属于死神,未来属于你自己,失败是坚忍的最后考验,流水在碰到底处时才会释放活力'; return getRnd(data, isNullable, ex); } /** 用户头像 */ function getAvatar(isNullable) { if (getNullable(isNullable)) return ''; return 'https://7265-release-7g51ulsq6451a0a6-1304820041.tcb.qcloud.la/mini/user_pic/' + getIntBetween(1, 200) + '.jpg'; } /** 是否为空 */ function getNullable(isNullable) { if (!isNullable) return false; let rd = getIntBetween(0, 1); if (rd % 2 == 0) return true; else return false; } module.exports = { getUuid, getRnd, getIdCard, getProvince, getProvinceAbbr, getCity, getArea, getCountry, getStreet, getAddress, getCompany, getCompanyPrefix, getResource, getMotto, getContent, getWord, getWeek, getMonth, getTimestamp, getAddTimestamp, getFirstName, getFemaleName, getMaleName, getName, getInt, getRdArr, getIntBetween, getIntStr, getStr, getStrLower, getStrUpper, getMobile, getPhone, getEnWord, getEmail, getDomain, getDate, getItem, getCollege, getTrade, getEdu, getDuty, getAvatar } ================================================ FILE: cloudfunctions/mcloud/framework/lib/md5_lib.js ================================================ /** * Notes: MD5类库 * Ver : CCMiniCloud Framework 2.15.1 ALL RIGHTS RESERVED BY cClinux0730 (wechat) * Date: 2021-03-01 14:00:00 */ function safe_add(x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF) var msw = (x >> 16) + (y >> 16) + (lsw >> 16) return (msw << 16) | (lsw & 0xFFFF) } /* * Bitwise rotate a 32-bit number to the left. */ function rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)) } /* * These functions implement the four basic operations the algorithm uses. */ function cmn(q, a, b, x, s, t) { return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b) } function ff(a, b, c, d, x, s, t) { return cmn((b & c) | ((~b) & d), a, b, x, s, t) } function gg(a, b, c, d, x, s, t) { return cmn((b & d) | (c & (~d)), a, b, x, s, t) } function hh(a, b, c, d, x, s, t) { return cmn(b ^ c ^ d, a, b, x, s, t) } function ii(a, b, c, d, x, s, t) { return cmn(c ^ (b | (~d)), a, b, x, s, t) } /* * Calculate the MD5 of an array of little-endian words, producing an array * of little-endian words. */ function coreMD5(x) { var a = 1732584193 var b = -271733879 var c = -1732584194 var d = 271733878 for (var i = 0; i < x.length; i += 16) { var olda = a var oldb = b var oldc = c var oldd = d a = ff(a, b, c, d, x[i + 0], 7, -680876936) d = ff(d, a, b, c, x[i + 1], 12, -389564586) c = ff(c, d, a, b, x[i + 2], 17, 606105819) b = ff(b, c, d, a, x[i + 3], 22, -1044525330) a = ff(a, b, c, d, x[i + 4], 7, -176418897) d = ff(d, a, b, c, x[i + 5], 12, 1200080426) c = ff(c, d, a, b, x[i + 6], 17, -1473231341) b = ff(b, c, d, a, x[i + 7], 22, -45705983) a = ff(a, b, c, d, x[i + 8], 7, 1770035416) d = ff(d, a, b, c, x[i + 9], 12, -1958414417) c = ff(c, d, a, b, x[i + 10], 17, -42063) b = ff(b, c, d, a, x[i + 11], 22, -1990404162) a = ff(a, b, c, d, x[i + 12], 7, 1804603682) d = ff(d, a, b, c, x[i + 13], 12, -40341101) c = ff(c, d, a, b, x[i + 14], 17, -1502002290) b = ff(b, c, d, a, x[i + 15], 22, 1236535329) a = gg(a, b, c, d, x[i + 1], 5, -165796510) d = gg(d, a, b, c, x[i + 6], 9, -1069501632) c = gg(c, d, a, b, x[i + 11], 14, 643717713) b = gg(b, c, d, a, x[i + 0], 20, -373897302) a = gg(a, b, c, d, x[i + 5], 5, -701558691) d = gg(d, a, b, c, x[i + 10], 9, 38016083) c = gg(c, d, a, b, x[i + 15], 14, -660478335) b = gg(b, c, d, a, x[i + 4], 20, -405537848) a = gg(a, b, c, d, x[i + 9], 5, 568446438) d = gg(d, a, b, c, x[i + 14], 9, -1019803690) c = gg(c, d, a, b, x[i + 3], 14, -187363961) b = gg(b, c, d, a, x[i + 8], 20, 1163531501) a = gg(a, b, c, d, x[i + 13], 5, -1444681467) d = gg(d, a, b, c, x[i + 2], 9, -51403784) c = gg(c, d, a, b, x[i + 7], 14, 1735328473) b = gg(b, c, d, a, x[i + 12], 20, -1926607734) a = hh(a, b, c, d, x[i + 5], 4, -378558) d = hh(d, a, b, c, x[i + 8], 11, -2022574463) c = hh(c, d, a, b, x[i + 11], 16, 1839030562) b = hh(b, c, d, a, x[i + 14], 23, -35309556) a = hh(a, b, c, d, x[i + 1], 4, -1530992060) d = hh(d, a, b, c, x[i + 4], 11, 1272893353) c = hh(c, d, a, b, x[i + 7], 16, -155497632) b = hh(b, c, d, a, x[i + 10], 23, -1094730640) a = hh(a, b, c, d, x[i + 13], 4, 681279174) d = hh(d, a, b, c, x[i + 0], 11, -358537222) c = hh(c, d, a, b, x[i + 3], 16, -722521979) b = hh(b, c, d, a, x[i + 6], 23, 76029189) a = hh(a, b, c, d, x[i + 9], 4, -640364487) d = hh(d, a, b, c, x[i + 12], 11, -421815835) c = hh(c, d, a, b, x[i + 15], 16, 530742520) b = hh(b, c, d, a, x[i + 2], 23, -995338651) a = ii(a, b, c, d, x[i + 0], 6, -198630844) d = ii(d, a, b, c, x[i + 7], 10, 1126891415) c = ii(c, d, a, b, x[i + 14], 15, -1416354905) b = ii(b, c, d, a, x[i + 5], 21, -57434055) a = ii(a, b, c, d, x[i + 12], 6, 1700485571) d = ii(d, a, b, c, x[i + 3], 10, -1894986606) c = ii(c, d, a, b, x[i + 10], 15, -1051523) b = ii(b, c, d, a, x[i + 1], 21, -2054922799) a = ii(a, b, c, d, x[i + 8], 6, 1873313359) d = ii(d, a, b, c, x[i + 15], 10, -30611744) c = ii(c, d, a, b, x[i + 6], 15, -1560198380) b = ii(b, c, d, a, x[i + 13], 21, 1309151649) a = ii(a, b, c, d, x[i + 4], 6, -145523070) d = ii(d, a, b, c, x[i + 11], 10, -1120210379) c = ii(c, d, a, b, x[i + 2], 15, 718787259) b = ii(b, c, d, a, x[i + 9], 21, -343485551) a = safe_add(a, olda) b = safe_add(b, oldb) c = safe_add(c, oldc) d = safe_add(d, oldd) } return [a, b, c, d] } /* * Convert an array of little-endian words to a hex string. */ function binl2hex(binarray) { var hex_tab = "0123456789abcdef" var str = "" for (var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF) } return str } /* * Convert an array of little-endian words to a base64 encoded string. */ function binl2b64(binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" var str = "" for (var i = 0; i < binarray.length * 32; i += 6) { str += tab.charAt(((binarray[i >> 5] << (i % 32)) & 0x3F) | ((binarray[i >> 5 + 1] >> (32 - i % 32)) & 0x3F)) } return str } /* * Convert an 8-bit character string to a sequence of 16-word blocks, stored * as an array, and append appropriate padding for MD4/5 calculation. * If any of the characters are >255, the high byte is silently ignored. */ function str2binl(str) { var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks var blks = new Array(nblk * 16) for (var i = 0; i < nblk * 16; i++) blks[i] = 0 for (var i = 0; i < str.length; i++) blks[i >> 2] |= (str.charCodeAt(i) & 0xFF) << ((i % 4) * 8) blks[i >> 2] |= 0x80 << ((i % 4) * 8) blks[nblk * 16 - 2] = str.length * 8 return blks } /* * Convert a wide-character string to a sequence of 16-word blocks, stored as * an array, and append appropriate padding for MD4/5 calculation. */ function strw2binl(str) { var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks var blks = new Array(nblk * 16) for (var i = 0; i < nblk * 16; i++) blks[i] = 0 for (var i = 0; i < str.length; i++) blks[i >> 1] |= str.charCodeAt(i) << ((i % 2) * 16) blks[i >> 1] |= 0x80 << ((i % 2) * 16) blks[nblk * 16 - 2] = str.length * 16 return blks } /* * External interface */ function hexMD5(str) { return binl2hex(coreMD5(str2binl(str))) } function hexMD5w(str) { return binl2hex(coreMD5(strw2binl(str))) } function b64MD5(str) { return binl2b64(coreMD5(str2binl(str))) } function b64MD5w(str) { return binl2b64(coreMD5(strw2binl(str))) } /* Backward compatibility */ function calcMD5(str) { return binl2hex(coreMD5(str2binl(str))) } module.exports = { md5: hexMD5 } ================================================ FILE: cloudfunctions/mcloud/framework/lib/mini_lib.js ================================================ /** * Notes: 小程序封装类库 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cClinux0730 (wechat) * Date: 2020-09-06 14:00:00 */ const cloudBase = require('../cloud/cloud_base.js'); const cloudUtil = require('../cloud/cloud_util.js'); const config = require('../../config/config'); // 消息长度截取 function fmtThing(str) { //20个以内字符,可汉字、数字、字母或符号组合 return str.substr(0, 20); } function fmtCharacterString(str) { //32位以内数字、字母或符号 return str.substr(0, 32); } function fmtPhrase(str) { //5个以内汉字 return str.substr(0, 5); } /** * 发送一次性消息 * @param {*} body * @param {*} key */ async function sendMiniOnceTempMsg(body, key = '') { // console.log('##sendOnceTempMsg[' + key + ']', body); let cloud = cloudBase.getCloud(); try { // 默认参数 body.lang = 'zh_CN'; body.miniprogramState = 'formal'; await cloud.openapi.subscribeMessage.send(body); } catch (err) { cloudUtil.log('##sendOnceTempMsg[' + key + ']', err); } } module.exports = { sendMiniOnceTempMsg, fmtThing, fmtCharacterString, fmtPhrase } ================================================ FILE: cloudfunctions/mcloud/framework/platform/controller/base_admin_controller.js ================================================ /** * Notes: 后台管理控制器模块 * Ver : CCMiniCloud Framework 2.0.3 ALL RIGHTS RESERVED BY cclinuX0730 (wechat) * Date: 2022-05-26 19:20:00 */ const BaseController = require('./base_controller.js'); const BaseAdminService = require('../service/base_admin_service.js'); const LogModel = require('../model/log_model.js'); const timeUtil = require('../../../framework/utils/time_util.js'); class BaseAdminController extends BaseController { constructor(route, openId, event) { super(route, openId, event); // 当前时间戳 this._timestamp = timeUtil.time(); this._admin = null; this._adminId = '0'; } /** 是否管理员 */ async isAdmin() { // 判断是否管理员 let service = new BaseAdminService(); let admin = await service.isAdmin(this._token); this._admin = admin; this._adminId = admin._id; } /** 是否超级管理员 */ async isSuperAdmin() { // 判断是否管理员 let service = new BaseAdminService(); let admin = await service.isSuperAdmin(this._token); this._admin = admin; this._adminId = admin._id; } /** 记录日志 */ async log(content, type) { let service = new BaseAdminService(); await service.insertLog(content, this._admin, type); } async logSys(content) { await this.log(content, LogModel.TYPE.SYS); } async logUser(content) { await this.log(content, LogModel.TYPE.USER); } async logOther(content) { await this.log(content, LogModel.TYPE.OTHER); } async logNews(content) { await this.log(content, LogModel.TYPE.NEWS); } } module.exports = BaseAdminController; ================================================ FILE: cloudfunctions/mcloud/framework/platform/controller/base_controller.js ================================================ /** * Notes: 基础控制器 * Ver : CCMiniCloud Framework 2.0.4 ALL RIGHTS RESERVED BY cclinUx0730 (wechat) * Date: 2020-09-05 04:00:00 */ const config = require('../../../config/config.js'); const timeUtil = require('../../utils/time_util.js'); const util = require('../../utils/util.js'); const dataCheck = require('../../validate/data_check.js'); const AppError = require('../../core/app_error.js'); const appCode = require('../../core/app_code.js'); class BaseController { constructor(route, openId, event) { this._route = route; // 路由 this._openId = openId; //用户身份 this._event = event; // 所有参数 this._request = event.params; //数据参数 if (!openId) { console.error('OPENID is unfined'); throw new AppError('OPENID is unfined', appCode.SVR); } let userId = openId; this._token = event.token || ''; this._userId = userId; // 当前时间戳 this._timestamp = timeUtil.time(); let time = timeUtil.time('Y-M-D h:m:s'); console.log('------------------------'); console.log(`【${time}】【Request -- ↘↘↘】\n【↘Token = ${this._token}】\n【↘USER-ID = ${userId}】\n【↘↘IN DATA】=\n`, JSON.stringify(this._request, null, 4)); } /** * 数据校验 * @param {*} rules */ validateData(rules = {}) { let input = this._request; return dataCheck.check(input, rules); } // 取得某个具体的参数值 getParameter(name) { let input = this._request; if (util.isDefined(input[name])) return input[name]; else return ''; } } module.exports = BaseController; ================================================ FILE: cloudfunctions/mcloud/framework/platform/model/admin_model.js ================================================ /** * Notes: 系统管理员实体 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.5 ALL RIGHTS RESERVED BY CCLINUX0730 (wechat) */ const BaseModel = require('./base_model.js'); class AdminModel extends BaseModel { } // 集合名 AdminModel.CL = BaseModel.C('admin'); AdminModel.DB_STRUCTURE = { _pid: 'string|true', ADMIN_ID: 'string|true', ADMIN_NAME: 'string|true', ADMIN_DESC: 'string|true', ADMIN_PHONE: 'string|false|comment=手机', ADMIN_PASSWORD: 'string|true|comment=密码', ADMIN_STATUS: 'int|true|default=1|comment=状态:0=禁用 1=启用', ADMIN_LOGIN_CNT: 'int|true|default=0|comment=登录次数', ADMIN_LOGIN_TIME: 'int|true|default=0|comment=最后登录时间', ADMIN_TYPE: 'int|true|default=0|comment=类型 0=普通管理员 1=超级管理员', ADMIN_TOKEN: 'string|false|comment=当前登录token', ADMIN_TOKEN_TIME: 'int|true|default=0|comment=当前登录token time', ADMIN_ADD_TIME: 'int|true', ADMIN_EDIT_TIME: 'int|true', ADMIN_ADD_IP: 'string|false', ADMIN_EDIT_IP: 'string|false', }; // 字段前缀 AdminModel.FIELD_PREFIX = "ADMIN_"; module.exports = AdminModel; ================================================ FILE: cloudfunctions/mcloud/framework/platform/model/base_model.js ================================================ /** * Notes: 实体基类 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.6 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const MultiModel = require('../../../framework/database/multi_model.js'); class BaseModel extends MultiModel { } module.exports = BaseModel; ================================================ FILE: cloudfunctions/mcloud/framework/platform/model/log_model.js ================================================ /** * Notes: 后台操作日志实体 * Ver : CCMiniCloud Framework 2.0.7 ALL RIGHTS RESERVED BY cclinuX0730 (wechat) * Date: 2020-10-16 19:20:00 */ const BaseModel = require('./base_model.js'); class LogModel extends BaseModel { } // 集合名 LogModel.CL = BaseModel.C('log'); LogModel.DB_STRUCTURE = { _pid: 'string|true', LOG_ID: 'string|true', LOG_ADMIN_ID: 'string|true|comment=管理员', LOG_ADMIN_DESC: 'string|false', LOG_ADMIN_NAME: 'string|true', LOG_CONTENT: 'string|true', LOG_TYPE: 'int|true|comment=日志类型 ', LOG_ADD_TIME: 'int|true', LOG_EDIT_TIME: 'int|true', LOG_ADD_IP: 'string|false', LOG_EDIT_IP: 'string|false', }; // 字段前缀 LogModel.FIELD_PREFIX = "LOG_"; LogModel.TYPE = { SYS: 0, USER: 1, NEWS: 2, OTHER: 99, } LogModel.TYPE_DESC = { SYS: '系统', USER: '用户', NEWS: '文章', OTHER: '其他', } module.exports = LogModel; ================================================ FILE: cloudfunctions/mcloud/framework/platform/service/base_admin_service.js ================================================ /** * Notes: 后台管理模块业务基类 * Date: 2021-03-15 07:48:00 * Ver : CCMiniCloud Framework 2.0.8 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseService = require('./base_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); const appCode = require('../../../framework/core/app_code.js'); const config = require('../../../config/config.js'); const AdminModel = require('../model/admin_model.js'); const LogModel = require('../model/log_model.js'); class BaseAdminService extends BaseService { /** 是否管理员 */ async isAdmin(token) { if (config.IS_DEMO) { // 演示版本 let admin = {}; admin.ADMIN_NAME = 'demo-admin'; admin.ADMIN_DESC = '体验用户'; admin.ADMIN_ID = '1'; admin.ADMIN_PHONE = '13900000000'; admin.ADMIN_LOGIN_CNT = 0; admin.ADMIN_LOGIN_TIME = ''; admin.ADMIN_TYPE = 0; admin.ADMIN_STATUS = 1; return admin; } let where = { ADMIN_TOKEN: token, ADMIN_TOKEN_TIME: ['>', timeUtil.time() - config.ADMIN_LOGIN_EXPIRE * 1000], // token有效时间 ADMIN_STATUS: 1, } let admin = await AdminModel.getOne(where, 'ADMIN_ID,ADMIN_PHONE,ADMIN_NAME,ADMIN_TYPE,ADMIN_DESC'); if (!admin) this.AppError('管理员不存在', appCode.ADMIN_ERROR); return admin; } /** 是否超级管理员 */ async isSuperAdmin(token) { let where = { ADMIN_TOKEN: token, ADMIN_TOKEN_TIME: ['>', timeUtil.time() - config.ADMIN_LOGIN_EXPIRE * 1000], // token有效时间 ADMIN_STATUS: 1, ADMIN_TYPE: 1 } let admin = await AdminModel.getOne(where, 'ADMIN_ID,ADMIN_PHONE,ADMIN_NAME,ADMIN_TYPE'); if (!admin) this.AppError('超级管理员不存在', appCode.ADMIN_ERROR); return admin; } /** 写入日志 */ async insertLog(content, admin, type) { if (!admin) return; let data = { LOG_CONTENT: content, LOG_ADMIN_ID: admin._id, LOG_ADMIN_NAME: admin.ADMIN_NAME, LOG_ADMIN_DESC: admin.ADMIN_DESC, LOG_TYPE: type } await LogModel.insert(data); } } module.exports = BaseAdminService; ================================================ FILE: cloudfunctions/mcloud/framework/platform/service/base_service.js ================================================ /** * Notes: 基础业务逻辑 * Ver : CCMiniCloud Framework 2.0.9 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-04-24 04:00:00 */ const AppError = require('../../core/app_error.js'); const appCode = require('../../core/app_code.js'); const timeUtil = require('../../utils/time_util.js'); class BaseService { constructor() { // 当前时间戳 this._timestamp = timeUtil.time(); } /** * 抛出异常 * @param {*} msg * @param {*} code */ AppError(msg, code = appCode.LOGIC) { throw new AppError(msg, code); } /** 时期范围处理 */ fmtSearchDate(where, search, field) { if (!search || search.length != 21 || !search.includes('#')) return where; let arr = search.split('#'); let start = arr[0]; let end = arr[1]; where[field] = ['between', start, end]; return where; } /* 数据库字段排序处理 */ fmtOrderBySort(sortVal, defaultSort) { let orderBy = { [defaultSort]: 'desc' }; if (sortVal.includes('|')) { let field = sortVal.split('|')[0]; let order = sortVal.split('|')[1]; orderBy = { [field]: order, }; if (defaultSort != field) orderBy[defaultSort] = 'desc'; } return orderBy; } } module.exports = BaseService; ================================================ FILE: cloudfunctions/mcloud/framework/utils/constant.js ================================================ /** * Notes: 通用常量定义 * Ver : CCMiniCloud Framework 2.32.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ module.exports = { } ================================================ FILE: cloudfunctions/mcloud/framework/utils/data_util.js ================================================ /** * Notes: 字符相关操作函数 * Ver : CCMiniCloud Framework 2.33.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const timeUtil = require('./time_util.js'); /** * 生成一个特定范围内的随机数 */ const genRandomNum = (min, max) => (Math.random() * (max - min + 1) | 0) + min; // 生成一个随机的数字字母字符串 const genRandomString = len => { const text = 'abcdefghijklmnopqrstuvwxyz0123456789'; const rdmIndex = text => Math.random() * text.length | 0; let rdmString = ''; for (; rdmString.length < len; rdmString += text.charAt(rdmIndex(text))); return rdmString; } // 生成一个随机的数字字符串 const genRandomIntString = len => { const text = '0123456789'; const rdmIndex = text => Math.random() * text.length | 0; let rdmString = ''; for (; rdmString.length < len; rdmString += text.charAt(rdmIndex(text))); return rdmString; } // 生成一个随机的字母字符串 const genRandomAlpha = len => { const text = 'abcdefghijklmnopqrstuvwxyz'; const rdmIndex = text => Math.random() * text.length | 0; let rdmString = ''; for (; rdmString.length < len; rdmString += text.charAt(rdmIndex(text))); return rdmString; } // 根据数据库自定义表单提取导出表格标题 function getTitleByForm(arr) { let formTitle = []; for (let k = 0; k < arr.length; k++) { if (arr.type == 'image' || arr.type == 'content') continue; formTitle.push({ column: arr[k].title, wch: 30 }); } return formTitle; } // 根据数据库自定义表单提取数据 function getValByForm(arr, mark, title) { for (let k = 0; k < arr.length; k++) { if (arr[k].mark == mark || arr[k].title == title) { if (arr[k].type == 'image') return '图片'; if (arr[k].type == 'content') return '图文内容'; if (arr[k].type == 'switch') { if (arr[k].val === true) return '是'; else return '否'; } return arr[k].val; } } return ''; } // 数据库自定义表单forms值修正 function dbFormsFix(forms) { for (let k = 0; k < forms.length; k++) { if (forms[k].type == 'number' || forms[k].type == 'digit') { forms[k].val = Number(forms[k].val); if (isNaN(forms[k].val)) forms[k].val = null; } } return forms; } // 数据库自定义表单forms转为obj function dbForms2Obj(forms, excludeContent = false) { forms = dbFormsFix(forms); //数据类型修正 if (forms.length == 0) return { 'no': 'none' }; let obj = {}; for (let k = 0; k < forms.length; k++) { if (excludeContent && forms[k].type == 'content') continue; obj[forms[k].mark] = forms[k].val; } return obj; } // 构造当前ID function makeID() { let id = timeUtil.time('YMDhms') + ''; //秒 //毫秒3位 let miss = timeUtil.time() % 1000 + ''; if (miss.length == 0) miss = '000'; else if (miss.length == 1) miss = '00' + miss; else if (miss.length == 2) miss = '0' + miss; return id + miss; } // 拆分一维数组为二维数组 function spArr(arr, size) { if (!arr || !Array.isArray(arr) || arr.length == 0) return arr; let newArray = []; let index = 0; while (index < arr.length) { newArray.push(arr.slice(index, index += size)); } return newArray; } /** * 把字符串格式化为数组 * @param {*} str * @param {*} sp */ function str2Arr(str, sp = ',') { if (str && Array.isArray(str)) return str; str = str.replace(/,/g, sp); let arr = str.split(sp); for (let i = 0; i < arr.length; i++) { arr[i] = arr[i].trim(); if (isNumber(arr[i])) { arr[i] = Number(arr[i]); } } return arr; } /** * 校验只要是数字(包含正负整数,0以及正负浮点数)就返回true * @param {*} val * @returns bool */ function isNumber(val) { var reg = /^[0-9]+.?[0-9]*$/; if (reg.test(val)) { return true; } else { return false; } } /** * 提取对象数组的某个属性数组,如[{'x':1},{'x':2}] 提取 x得到[1,2] * @param {*} arr * @param {*} key * @returns [] */ function getArrByKey(arr, key) { if (!Array.isArray(arr)) return; return arr.map((item) => { return item[key] }); } /** * 提取对象数组的多个属性数组, * 如 [{'x':1,'y':11,'z':111},{'x':2,'y':22,'z':222}] * 提取 ['x','y'] 得到[{'x':1,'y':11},{'x':2,'y':22}] * @param {*} arr * @param {*} keys * @returns [] */ function getArrByKeyMulti(arr, keys = []) { if (!Array.isArray(arr)) return; if (!Array.isArray(keys)) return; let ret = []; for (let k = 0; k < arr.length; k++) { let node = {}; for (let j in keys) { node[keys[j]] = arr[k][keys[j]]; } ret.push(node); } return ret; } /** * 提取对象数组某个键值等于某值的对象数据 * @param {*} arr * @param {*} key * @param {*} val * @returns object {} */ function getDataByKey(arr, key, val) { if (!Array.isArray(arr)) return null; for (let k = 0; k < arr.length; k++) { if (arr[k][key] == val) return arr[k]; } return null; } /** * 文本内容格式化处理 * @param {*} content * @param {*} len 截取长度 -1不截取 */ function fmtText(content, len = -1) { if (!content) return content; let str = content.replace(/[\r\n]/g, ""); //去掉回车换行 if (len > 0) { str = str.substr(0, len); } return str.trim(); } // 下划线转换驼峰 function toHump(name) { name = name.replace(/\_(\w)/g, function (all, letter) { return letter.toUpperCase(); }); // 首字母大写 let firstChar = name.charAt(0).toUpperCase(); return firstChar + name.slice(1); } // 驼峰转换下划线 function toLine(name) { name = name.replace(/([A-Z])/g, "_$1").toLowerCase(); //如果首字符为下划线,干掉 if (name.charAt(0) === '_') return name.slice(1); else return name; } // 金额格式化 dot为金额每隔三位用","或" "间隔 function fmtMoney(s, dot = ',', prefix = '¥') { if (s === '' || s === null || s === undefined) s = 0; s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(2) + ""; var l = s.split(".")[0].split("").reverse(), r = s.split(".")[1]; t = ""; for (i = 0; i < l.length; i++) { t += l[i] + ((i + 1) % 3 == 0 && (i + 1) != l.length ? dot : ""); } return prefix + t.split("").reverse().join("") + "." + r; } /** *简单数组转对象数组 * @param {*} arr [1,2,3] * @param {*} key [x1,x2,x3] * @returns [{x1:1,x2:1,x3:1},{x1:2,x2:2,x3:2},{x1:3,x2:3,x3:3}] */ function arr2ObjectArr(arr, key1, key2, key3) { let ret = []; for (let k = 0; k < arr.length; k++) { let obj = {}; if (key1) obj[key1] = arr[k]; if (key2) obj[key2] = arr[k]; if (key3) obj[key3] = arr[k]; ret.push(obj); } return ret; } /** * property * @param {*} property 排序属性 * @returns 排序好的数组 * 用法 arr.sort(compare('age')) */ function objArrSortAsc(property) { return function (a, b) { var value1 = a[property]; var value2 = b[property]; if (value1 < value2) return -1; else if (value1 > value2) return 1; else return 0; } } /** * property * @param {*} property 排序属性 * @returns 排序好的数组 * 用法 arr.sort(compare('age')) */ function objArrSortDesc(property) { return function (a, b) { var value1 = a[property]; var value2 = b[property]; if (value1 < value2) return 1; else if (value1 > value2) return -1; else return 0; } } /** * 数组有则减少,无则增加 * @param {*} arr * @param {*} data * @param {*} sort 排序方式 asc/desc */ function arrAddDel(arr, data, sort = 'asc') { if (!arr) return arr; if (!Array.isArray(arr)) return arr; let idx = arr.indexOf(data); if (idx > -1) arr.splice(idx, 1); else arr.push(data) if (sort == 'asc') return arr.sort(); else return arr.reverse(); } //数据深度拷贝 function deepClone(data) { if (data === null || typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || typeof data === 'undefined') { return data; } return JSON.parse(JSON.stringify(data)); } function padLeft(str, len, charStr) { if (!str) str = ''; else str = str + ''; return new Array(len - str.length + 1).join(charStr || '') + str; } function padRight(str, len, charStr) { if (!str) str = ''; else str = str + ''; return str + new Array(len - str.length + 1).join(charStr || ''); } // 选项表单处理 function getSelectOptions(str) { if (!str) return []; else if (str.includes('=')) { let arr = str.split(','); for (let k = 0; k < arr.length; k++) { let node = arr[k].split('='); arr[k] = {}; arr[k].label = node[1]; arr[k].val = node[0]; } return arr; } else { return str.split(','); } } // 数组元素交换位置 index1和index2分别是两个数组的索引值 function arraySwap(arr, index1, index2) { arr[index1] = arr.splice(index2, 1, arr[index1])[0]; return arr; } // 数组置顶 function arrayTop(arr, idx) { let node = arr.splice(idx, 1)[0]; arr.unshift(node); return arr; } // 数组置底 function arrayBottom(arr, idx) { let node = arr.splice(idx, 1)[0]; arr.push(node); return arr; } /** * 把某个值/对象按key插到某个对象数组 * @param {*} arr 目标数组 * @param {*} key 键 * @param {*} val 判断值 * @param {*} obj 插入对象{} */ function insertObjArrByKey(arr, key, val, obj) { if (!arr) return arr; for (let k = 0; k < arr.length; k++) { if (arr[k][key] == val) { // 发现存在 arr[k].list.push(obj); return arr; } } // 不存在 let newObj = { [key]: val, list: [obj] } arr.push(newObj); return arr; } /** * 从对象数组中, 根据某个键值 获取满足的对象 * @param {*} arr * @param {*} key * @param {*} val */ function getValFromArr(arr, key = 'val', val = '') { if (!Array.isArray(arr)) return null; for (let k = 0; k < arr.length; k++) { if (arr[k][key] == val) return arr[k]; } return null; } // 把字符串按关键字转为数组 function splitTextByKey(txt, key) { if (txt === null || txt === undefined) return []; if (key === null || key === undefined || key.trim() == '') return [String(txt)]; key = String(key).trim(); txt = String(txt); let arr = txt.split(key); let ret = []; for (let i = 0; i < arr.length; i++) { if (arr[i] !== '') ret.push(arr[i]); if (i != (arr.length - 1)) ret.push(key); } return ret; } module.exports = { arrayTop, arraySwap, arrayBottom, getTitleByForm, getValByForm, dbForms2Obj, dbFormsFix, getValFromArr, getArrByKey, getArrByKeyMulti, //提取对象数组的多个属性数组 spArr, //拆分一维数组为二维 getDataByKey, str2Arr, arr2ObjectArr, insertObjArrByKey, arrAddDel, objArrSortAsc, objArrSortDesc, splitTextByKey, arrAddDel, isNumber, padLeft, padRight, makeID, genRandomString, // 随机字符串 genRandomIntString, genRandomAlpha, genRandomNum, // 随机数字 fmtText, // 文本内容格式化处理 fmtMoney, //金额格式化 toHump, toLine, getSelectOptions, //选项表单处理 deepClone } ================================================ FILE: cloudfunctions/mcloud/framework/utils/export_util.js ================================================ /** * Notes: 导出相关函数 * Ver : CCMiniCloud Framework 2.0.14 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-05-25 04:00:00 */ const cloudBase = require('../../framework/cloud/cloud_base.js'); const cloudUtil = require('../../framework/cloud/cloud_util.js'); const timeUtil = require('../../framework/utils/time_util.js'); const util = require('../../framework/utils/util.js'); const md5Lib = require('../../framework/lib/md5_lib.js'); const config = require('../../config/config.js'); const setupUtil = require('../utils/setup/setup_util.js'); // 获得当前导出链接 async function getExportDataURL(key) { let url = ''; let time = ''; let expData = await setupUtil.get(key); if (!expData) url = ''; else { url = expData.EXPORT_CLOUD_ID; url = await cloudUtil.getTempFileURLOne(url) + '?rd=' + timeUtil.time(); time = timeUtil.timestamp2Time(expData.EXPORT_ADD_TIME); } return { url, time } } // 删除数据文件 async function deleteDataExcel(key) { console.log('[deleteExcel] BEGIN... , key=' + key) // 取出数据 let expData = await setupUtil.get(key); if (!expData) return; // 文件路径 let xlsPath = expData.EXPORT_CLOUD_ID; console.log('[deleteExcel] path = ' + xlsPath); const cloud = cloudBase.getCloud(); await cloud.deleteFile({ fileList: [xlsPath], }).then(async res => { console.log(res.fileList); if (res.fileList && res.fileList[0] && res.fileList[0].status == -503003) { console.log('[deleteUserExcel] ERROR = ', res.fileList[0].status + ' >> ' + res.fileList[0].errMsg); this.AppError('文件不存在或者已经删除'); } // 删除导出数据记录 await setupUtil.remove(key); console.log('[deleteExcel] OVER.'); }).catch(error => { if (error.name != 'AppError') { console.log('[deleteExcel] ERROR = ', error); this.AppError('操作失败,请重新删除'); } else throw error; }); } // 导出数据 async function exportDataExcel(key, title, total, data, options = {}) { // 删除导出表 await setupUtil.remove(key); let fileName = key + '_' + md5Lib.md5(key + config.CLOUD_ID); let xlsPath = util.getProjectId() + '/' + 'export/' + fileName + '.xlsx'; // 操作excel用的类库 const xlsx = require('node-xlsx'); // 把数据保存到excel里 let buffer = await xlsx.build([{ name: title + timeUtil.time('Y-M-D'), data, options }]); // 把excel文件保存到云存储里 console.log('[ExportData] Save to ' + xlsPath); const cloud = cloudBase.getCloud(); let upload = await cloud.uploadFile({ cloudPath: xlsPath, fileContent: buffer, //excel二进制文件 }); if (!upload || !upload.fileID) return; // 入导出表 let dataExport = { EXPORT_ADD_TIME: timeUtil.time(), EXPORT_KEY: key, EXPORT_CLOUD_ID: upload.fileID } //console.log(dataExport) await setupUtil.set(key, dataExport, 'export'); console.log('[ExportData] OVER.') return { total } } module.exports = { getExportDataURL, deleteDataExcel, exportDataExcel } ================================================ FILE: cloudfunctions/mcloud/framework/utils/log_util.js ================================================ /** * Notes: 日志操作函数 * Ver : CCMiniCloud Framework 2.34.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-06-12 04:00:00 */ const timeUtil = require('./time_util.js'); class LogUtil { constructor(level = 'info') { this.logOut = ''; // 输出日志内容 level = level.toLowerCase(); if (level == 'err') level = 'error'; switch (level) { case 'debug': level = LogUtil.LEVEL.DEBUG; break; case 'info': level = LogUtil.LEVEL.INFO; break; case 'warn': level = LogUtil.LEVEL.WARN; break; case 'error': level = LogUtil.LEVEL.ERROR; break; case 'fatal': level = LogUtil.LEVEL.FATAL; break; case 'none': level = LogUtil.LEVEL.NONE; break; default: level = LogUtil.LEVEL.INFO; } this.level = level; } debug(str, ex = '') { if (this.level > LogUtil.LEVEL.DEBUG) return; console.debug('[' + this._getTime() + '] DEBUG: ' + str, ex); this.logOut += "######" + '[' + this._getTime() + '] DEBUG: ' + str + (ex ? JSON.stringify(ex) : ''); } info(str, ex = '') { if (this.level > LogUtil.LEVEL.INFO) return; console.log('[' + this._getTime() + '] INFO: ' + str, ex); this.logOut += "######" + '[' + this._getTime() + '] INFO: ' + str + (ex ? JSON.stringify(ex) : ''); } warn(str, ex = '') { if (this.level > LogUtil.LEVEL.WARN) return; console.warn('[' + this._getTime() + '] WARN: ' + str, ex); this.logOut += "######" + '[' + this._getTime() + '] WARN: ' + str + (ex ? JSON.stringify(ex) : ''); } error(str, ex = '') { if (this.level > LogUtil.LEVEL.ERROR) return; console.error('[' + this._getTime() + '] ERROR: ' + str, ex); this.logOut += "######" + '[' + this._getTime() + '] ERROR: ' + str + (ex ? JSON.stringify(ex) : ''); } fatal(str, ex = '') { if (this.level > LogUtil.LEVEL.FATAL) return; console.error('[' + this._getTime() + '] FATAL: ' + str, ex); this.logOut += "######" + '[' + this._getTime() + '] FATAL: ' + str + (ex ? JSON.stringify(ex) : ''); } _getTime() { return timeUtil.time('Y-M-D h:m:s'); } err(str) { error(str); } getLogOut() { return this.logOut; } } LogUtil.LEVEL = { DEBUG: 10, INFO: 20, WARN: 30, ERROR: 40, FATAL: 50, NONE: 100, }; module.exports = LogUtil; ================================================ FILE: cloudfunctions/mcloud/framework/utils/math_util.js ================================================ /** * Notes: 数学计算相关操作函数 * Ver : CCMiniCloud Framework 2.35.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-10-04 04:00:00 */ /** 获取百分比, 保留2位小数 */ function percent(num1, num2) { return Math.round(num1 / num2 * 10000) / 100.00; } /** 数组对象排序 */ function arrayObjecSortAsc(property) { return function (a, b) { var value1 = a[property]; var value2 = b[property]; return value1 - value2; } } /** 数组对象排序 */ function arrayObjecSortDesc(property) { return function (a, b) { var value1 = a[property]; var value2 = b[property]; return value2 - value1; } } module.exports = { percent, // 百分比,保留2位小数 arrayObjecSortAsc, // 数组对象排序 arrayObjecSortDesc, // 数组对象排序 } ================================================ FILE: cloudfunctions/mcloud/framework/utils/setup/setup_model.js ================================================ /** * Notes: 系统设置实体 * Ver : CCMiniCloud Framework 2.0.15 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-11-05 19:20:00 */ const MultiModel = require('../../database/multi_model.js'); class SetupModel extends MultiModel { } // 集合名 SetupModel.CL = MultiModel.C('setup'); SetupModel.DB_STRUCTURE = { _pid: 'string|true', SETUP_ID: 'string|true', SETUP_TYPE: 'string|false', //content/cache/vouch SETUP_KEY: 'string|true', SETUP_VALUE: 'object|true', // {val:} SETUP_ADD_TIME: 'int|true', SETUP_EDIT_TIME: 'int|true', SETUP_ADD_IP: 'string|false', SETUP_EDIT_IP: 'string|false', }; // 字段前缀 SetupModel.FIELD_PREFIX = "SETUP_"; module.exports = SetupModel; /* ### 富文本 [{"type":"text","val":"xxx"},{"type":"img","val":"cloudId://xxxx"}] ### 导出 {"EXPORT_CLOUD_ID":"","EXPORT_EDIT_TIME":""} */ ================================================ FILE: cloudfunctions/mcloud/framework/utils/setup/setup_util.js ================================================ /** * Notes: 系统设置相关函数 * Ver : CCMiniCloud Framework 2.31.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-05-25 04:00:00 */ const SetupModel = require('./setup_model.js'); /** * 设置 * key 键key * val 值value * t 秒 */ async function set(key, val, type = '') { if (!key) return null; let where = { SETUP_KEY: key } let data = { SETUP_TYPE: type, SETUP_VALUE: { val }, } await SetupModel.insertOrUpdate(where, data); } /** * 获取 * k 键key * def 默认值 */ async function get(key) { if (!key) return null; let where = { SETUP_KEY: key } let setup = await SetupModel.getOne(where, 'SETUP_VALUE'); if (!setup) return null; let res = setup.SETUP_VALUE.val; if (res === undefined) { return null; } else { return res; } } async function get(key) { if (!key) return null; let where = { SETUP_KEY: key } let setup = await SetupModel.getOne(where, 'SETUP_VALUE'); if (!setup) return null; let res = setup.SETUP_VALUE.val; if (res === undefined) { return null; } else { return res; } } async function remove(key, fuzzy = false) { if (!key) return; let where = { SETUP_KEY: key } if (fuzzy) { where.SETUP_KEY = { $regex: '.*' + key, $options: 'i' }; } await SetupModel.del(where); } module.exports = { set, get, remove } ================================================ FILE: cloudfunctions/mcloud/framework/utils/time_util.js ================================================ /** * Notes: 时间相关函数 * Ver : CCMiniCloud Framework 2.36.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const util = require('./util.js'); /** 日期简化,去掉多余的前缀0 */ function simpleDate(date) { let arr = date.split('-'); if (arr.length < 3) return date; let month = arr[1]; if (month.indexOf('0') == 0) month = month.replace('0', ''); let day = arr[2]; if (day.indexOf('0') == 0) day = day.replace('0', ''); return arr[0] + '-' + month + '-' + day; } /** 时间格式化为年月日点分 */ function fmtDateCHN(date, fmt = 'Y-M-D') { if (!date) return ''; if (fmt == 'hh:mm' && date.includes(':')) { if (date.includes(' ')) date = date.split(' ')[1]; let arr = date.split(':'); return Number(arr[0]) + '点' + arr[1] + '分'; } else if (fmt == 'Y-M-D hh:mm') { let arr = date.split(' '); if (arr.length != 2) return date; return fmtDateCHN(arr[0], 'Y-M-D') + fmtDateCHN(arr[1], 'hh:mm'); } else if (fmt == 'M-D hh:mm') { let arr = date.split(' '); if (arr.length != 2) return date; return fmtDateCHN(arr[0], 'M-D') + ' ' + fmtDateCHN(arr[1], 'hh:mm'); } else { if (date.includes(' ')) date = date.split(' ')[0]; let arr = date.split('-'); if (fmt == 'Y-M') //年月 return arr[0] + '年' + Number(arr[1]) + '月'; else if (fmt == 'M-D') //月日 return arr[1] + '月' + Number(arr[2]) + '日'; else if (fmt == 'Y') //年 return arr[0] + '年'; else return arr[0] + '年' +Number(arr[1]) + '月' + Number(arr[2]) + '日'; } } /** * 毫秒时间戳转时间格式 * @param {*} unixtime 毫秒 * @param {*} format Y-M-D h:m:s * @param {*} diff 时区差异 毫秒 */ function timestamp2Time(unixtime, format = 'Y-M-D h:m:s', diff = 0) { unixtime = Number(unixtime); let formateArr = ['Y', 'M', 'D', 'h', 'm', 's']; let returnArr = []; let date = new Date(unixtime + diff); returnArr.push(date.getFullYear()); returnArr.push(formatNumber(date.getMonth() + 1)); returnArr.push(formatNumber(date.getDate())); returnArr.push(formatNumber(date.getHours())); returnArr.push(formatNumber(date.getMinutes())); returnArr.push(formatNumber(date.getSeconds())); for (let i in returnArr) { format = format.replace(formateArr[i], returnArr[i]); } return format; } function timestame2Ago(dateTimeStamp, fmt = 'Y-M-D', diff = 0) { //dateTimeStamp是一个时间毫秒,注意时间戳是秒的形式,在这个毫秒的基础上除以1000,就是十位数的时间戳。13位数的都是时间毫秒。 let minute = 1000 * 60; //把分,时,天,周,半个月,一个月用毫秒表示 let hour = minute * 60; let day = hour * 24; let week = day * 7; let month = day * 30; let now = new Date().getTime(); //获取当前时间毫秒 let diffValue = now - dateTimeStamp; //时间差 if (diffValue < 0) { return; } let minC = diffValue / minute; //计算时间差的分,时,天,周,月 let hourC = diffValue / hour; let dayC = diffValue / day; let result = ''; let weekC = diffValue / week; let monthC = diffValue / month; if (monthC >= 1 && monthC <= 3) { result = ' ' + parseInt(monthC) + '月前' } else if (weekC >= 1 && weekC <= 3) { result = ' ' + parseInt(weekC) + '周前' } else if (dayC >= 1 && dayC <= 6) { result = ' ' + parseInt(dayC) + '天前' } else if (hourC >= 1 && hourC <= 23) { result = ' ' + parseInt(hourC) + '小时前' } else if (minC >= 1 && minC <= 59) { result = ' ' + parseInt(minC) + '分钟前' } else if (diffValue >= 0 && diffValue <= minute) { result = '刚刚' } else { result = timestamp2Time(dateTimeStamp, fmt, diff); } return result; } function formatNumber(n) { n = n.toString() return n[1] ? n : '0' + n } /** * 时间转时间戳 * @param {*} date 支持 Y-M-D h:m:s / Y-M-D */ function time2Timestamp(date) { if (date.length < 10) { let arr = date.split('-'); if (arr[1].length == 1) arr[1] = '0' + arr[1]; if (arr[2].length == 1) arr[2] = '0' + arr[2]; date = arr[0] + '-' + arr[1] + '-' + arr[2]; } if (date.length == 10) date = date + ' 00:00:00'; let d = new Date(date.replace(/-/g, '/')); return d.getTime(); } /** * 获取当前时间戳/时间Y-M-D h:m:s * @param {*} 时间格式 Y-M-D h:m:s * @param {int} 时间步长 (秒) */ function time(fmt, step = 0) { let t = 0; if (util.isDefined(fmt)) { let t = new Date().getTime() + step * 1000; return timestamp2Time(t, fmt); } return new Date().getTime() + t * 1000; } // 获取某天0点 function getDayFirstTimestamp(timestamp) { if (!timestamp) timestamp = time(); return time2Timestamp(timestamp2Time(timestamp, 'Y-M-D')); } /** * 根据出生日期计算年龄周岁 传参格式为1996-06-08 * @param {*} birth */ function getAge(birth, isMonth = false) { var returnAge = ''; var mouthAge = ''; var arr = birth.split('-'); var birthYear = arr[0]; var birthMonth = arr[1]; var birthDay = arr[2]; var d = new Date(); var nowYear = d.getFullYear(); var nowMonth = d.getMonth() + 1; var nowDay = d.getDate(); if (nowYear == birthYear) { // returnAge = 0; //同年 则为0岁 var monthDiff = nowMonth - birthMonth; //月之差 if (monthDiff < 0) {} else { mouthAge = monthDiff + '个月'; } } else { var ageDiff = nowYear - birthYear; //年之差 if (ageDiff > 0) { if (nowMonth == birthMonth) { var dayDiff = nowDay - birthDay; //日之差 if (dayDiff < 0) { returnAge = ageDiff - 1 + '岁'; } else { returnAge = ageDiff + '岁'; } } else { var monthDiff = nowMonth - birthMonth; //月之差 if (monthDiff < 0) { returnAge = ageDiff - 1 + '岁'; } else { mouthAge = monthDiff + '个月'; returnAge = ageDiff + '岁'; } } } else { returnAge = -1; //返回-1 表示出生日期输入错误 晚于今天 } } if (isMonth) return returnAge + mouthAge; //返回周岁年龄+月份 else return returnAge; } /** * 日期计算周几 * @param {*} day 日期为输入日期,格式为 2013-03-10 */ function week(day) { if (!day || !day.includes('-')) return ''; let arys1 = new Array(); arys1 = day.split('-'); let ssdate = new Date(arys1[0], parseInt(arys1[1] - 1), arys1[2]); let week1 = String(ssdate.getDay()).replace("0", "日").replace("1", "一").replace("2", "二").replace("3", "三").replace("4", "四").replace("5", "五").replace("6", "六") //就是你要的星期几 return "周" + week1; //就是你要的星期几 } /** 获取某天所在某月第一天时间戳 */ function getMonthFirstTimestamp(timestamp) { let inDate = new Date(timestamp); let year = inDate.getFullYear(); let month = inDate.getMonth(); return new Date(year, month, 1).getTime(); } /** 获取某天所在某月最后一天时间戳 */ function getMonthLastTimestamp(timestamp) { let inDate = new Date(timestamp); let year = inDate.getFullYear(); let month = inDate.getMonth(); return new Date(year, month + 1, 1).getTime() - 1; } // 取得分钟时间戳 function getNowMinTimestamp() { let min = time('Y-M-D h:m') + ':00'; let timestamp = time2Timestamp(min); return { min, timestamp } } // 获取当前日期所在周一 输入和返回格式=yyyy-mm-dd function getFirstOfWeek(date) { let now = new Date(date); let nowTime = now.getTime(); let day = now.getDay(); if (day == 0) day = 7; let oneDayTime = 24 * 60 * 60 * 1000; let mondayTime = nowTime - (day - 1) * oneDayTime; return timestamp2Time(mondayTime, 'Y-M-D'); } // 获取当前日期所在周一 输入和返回格式=yyyy-mm-dd function getLastOfWeek(date) { let now = new Date(date); let nowTime = now.getTime(); let day = now.getDay(); if (day == 0) day = 7; let oneDayTime = 24 * 60 * 60 * 1000; let sundayTime = nowTime + (7 - day) * oneDayTime; return timestamp2Time(sundayTime, 'Y-M-D'); } // 获取当前日期所在月第一天 输入和返回格式=yyyy-mm-dd function getFirstOfMonth(date) { let arr = date.split('-'); return arr[0] + '-' + arr[1] + '-01'; } // 获取当前日期所在月最后一天 输入和返回格式=yyyy-mm-dd function getLastOfMonth(date) { let now = new Date(date); let y = now.getFullYear(); let m = now.getMonth(); let lastDay = new Date(y, m + 1, 0).getTime(); return timestamp2Time(lastDay, 'Y-M-D'); } /** * 取倒计时(天时分秒) 支持时间戳或者Y-M-D/Y-M-D h:m:s * @param {*} datetimeTo * @param {*} flag 1=正 -1=负 */ function getTimeLeft(datetimeTo, flag = 1) { let time1 = datetimeTo; if (String(datetimeTo).includes('-')) { datetimeTo = String(datetimeTo); if (!datetimeTo.includes(':')) datetimeTo += ' 00:00:00'; time1 = new Date(datetimeTo).getTime(); } let time2 = new Date().getTime(); let mss = time1 - time2; // 将时间差(毫秒)格式为:天时分秒 let days = parseInt(mss / (1000 * 60 * 60 * 24)); let hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); let minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60)); let seconds = parseInt((mss % (1000 * 60)) / 1000); if (mss < 0 && mss < -86400 * 1000) { (days != 0) ? days = -flag * days + "天": days = ''; return days + "前"; } else if (mss < 0) { return "今天"; } else { (days != 0) ? days = flag * days + "天": days = ''; (hours != 0) ? hours = flag * hours + "时": hours = ''; (minutes != 0) ? minutes = flag * minutes + "分": minutes = ''; return days + hours + minutes + flag * seconds + "秒" } } module.exports = { fmtDateCHN, simpleDate, getTimeLeft, getNowMinTimestamp, getMonthFirstTimestamp, getMonthLastTimestamp, getDayFirstTimestamp, timestamp2Time, timestame2Ago, time2Timestamp, time, getAge, week, //星期 getFirstOfWeek, getLastOfWeek, getFirstOfMonth, getLastOfMonth } ================================================ FILE: cloudfunctions/mcloud/framework/utils/util.js ================================================ /** * Notes: 通用工具函数 * Ver : CCMiniCloud Framework 2.38.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ function getProjectId() { if (global.PID) return global.PID; else return 'ONE'; } /** * 判断变量,参数,对象属性是否定义 * @param {*} val */ function isDefined(val) { // == 不能判断是否为null if (val === undefined) return false; else return true; } /** * 判断对象是否为空 * @param {*} obj */ function isObjectNull(obj) { return (Object.keys(obj).length == 0); } /** * 休眠时间,配合await使用 * @param {*} time 毫秒 */ function sleep(time) { return new Promise((resolve) => setTimeout(resolve, time)); }; module.exports = { getProjectId, isDefined, //判断变量,参数,对象属性是否定义 sleep, isObjectNull, } ================================================ FILE: cloudfunctions/mcloud/framework/validate/content_check.js ================================================ /** * Notes: 内容审核 * Ver : CCMiniCloud Framework 2.39.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-05 04:00:00 */ const AppError = require('../core/app_error.js'); const cloudBase = require('../cloud/cloud_base.js'); const config = require('../../config/config.js'); /** * 前台校验 * @param {*} imgData * @param {*} mine */ async function checkImgClient(imgData, mine) { if (!config.CLIENT_CHECK_CONTENT) return; return await checkImg(imgData, mine); } /** * 后台校验 * @param {*} imgData * @param {*} mine */ async function checkImgAdmin(imgData, mine) { if (!config.ADMIN_CHECK_CONTENT) return; return await checkImg(imgData, mine); } /** * 校验图片信息 * @param {*} 图片流buffer */ async function checkImg(imgData, mine) { let cloud = cloudBase.getCloud(); try { const result = await cloud.openapi.security.imgSecCheck({ media: { contentType: 'image/' + mine, value: Buffer.from(imgData, 'base64') // 这里必须要将小程序端传过来的进行Buffer转化,否则就会报错,接口异常 } }) console.log('imgcheck', result); if (!result || result.errCode !== 0) { throw new AppError('图片内容不合适,请修改'); } } catch (err) { console.log('imgcheck ex', err); throw new AppError('图片内容不合适,请修改'); } } /** * 后台把输入数据里的文本数据提交内容审核 * @param {*} input */ async function checkTextMultiAdmin(input) { if (!config.ADMIN_CHECK_CONTENT) return; return checkTextMulti(input); } /** * 前台把输入数据里的文本数据提交内容审核 * @param {*} input */ async function checkTextMultiClient(input) { if (!config.CLIENT_CHECK_CONTENT) return; return checkTextMulti(input); } /** * 把输入数据里的文本数据提交内容审核 * @param {*} input */ async function checkTextMulti(input) { let txt = ''; for (let key in input) { if (typeof (input[key]) === 'string') txt += input[key]; else if (typeof (input[key]) === 'object') //包括数组和对象 txt += JSON.stringify(input[key]); } await checkText(txt); } /** * 后台校验文字信息 * @param {*} */ async function checkTextAdmin(txt) { if (!config.ADMIN_CHECK_CONTENT) return; return checkText(txt); } /** * 前台校验文字信息 * @param {*} */ async function checkTextClient(txt) { if (!config.CLIENT_CHECK_CONTENT) return; return checkText(txt); } /** * 校验文字信息 * @param {*} */ async function checkText(txt) { if (!txt) return; let cloud = cloudBase.getCloud(); try { const result = await cloud.openapi.security.msgSecCheck({ content: txt }) if (!result || result.errCode !== 0) { throw new AppError('文字内容不合适,请修改或者重试'); } } catch (err) { console.log('checkText ex', err); throw new AppError('文字内容不合适,请修改或者重试'); } } module.exports = { checkImg, checkImgClient, checkImgAdmin, checkTextMulti, checkTextMultiClient, checkTextMultiAdmin, checkText, checkTextClient, checkTextAdmin } ================================================ FILE: cloudfunctions/mcloud/framework/validate/data_check.js ================================================ /** * Notes: 数据校验类库 * Ver : CCMiniCloud Framework 2.21.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-01-07 07:48:00 * */ const AppError = require('../core/app_error.js'); const appCode = require('../core/app_code.js'); const CHECK_OPEN = true; const CHECK_SOURCE = 'admin'; //client/admin /** * 判断变量,参数,对象属性是否定义 * @param {*} val */ function isDefined(val) { // == 不能判断是否为null if (val === undefined) return false; else return true; } function isNull(value) { if (value === null || value === undefined) return true; if (getDataType(value) == String && value === '') return true; return false; } function isStrAndArrNull(value) { if (value === null || value === undefined) return true; let type = getDataType(value); if (type == String && value === '') return true; if (type == Array && value.length == 0) return true; return false; } function isRealNull(value) { if (value === null || value === undefined) return true; let type = getDataType(value); if (type == String && value === '') return true; if (type == Array && value.length == 0) return true; if (type == Object && JSON.stringify(value) == '{}') return true; return false; } function getDataType(value) { if (value === null || value === undefined) return value; return value.constructor; } // 是否必填 function checkRequired(value, desc = '') { switch (getDataType(value)) { case Object: if (JSON.stringify(value) == '{}') return desc + '不能为空obj'; break; case Array: if (value.length == 0) return desc + '不能为空arr'; break; case String: if (value.length == 0) return desc + '不能为空'; break; case null: case undefined: return desc + '不能为空'; } } // 校验字符/数组长度,校验数字大小 function checkMin(value, min, desc = '') { if (isStrAndArrNull(value)) return; min = Number(min); switch (getDataType(value)) { case Array: if (value.length < min) return desc + '不能少于' + min + '项'; break; case String: if (value.length < min) return desc + '不能少于' + min + '位'; break; case Number: if (value < min) return desc + '不能小于' + min; break; } }; // 校验字符/数组长度,校验数字大小 function checkMax(value, max, desc = '') { if (isStrAndArrNull(value)) return; max = Number(max); switch (getDataType(value)) { case Array: if (value.length > max) return desc + '不能多于' + max + '项'; break; case String: if (value.length > max) return desc + '不能多于' + max + '位'; break; case Number: if (value > max) return desc + '不能大于' + max; break; } }; // 校验字符/数组长度 function checkLen(value, len, desc = '') { if (isStrAndArrNull(value)) return; len = Number(len); switch (getDataType(value)) { case Array: if (value.length != len) return desc + '必须为' + len + '项'; break; case String: if (value.length != len) return desc + '必须为' + len + '位'; break; } }; function checkMobile(value, desc = '') { if (isNull(value)) return; if (!/(^1[1|2|3|4|5|6|7|8|9][0-9]{9}$)/.test(value)) return desc + '格式不正确'; } function checkInt(value, desc = '') { if (isNull(value)) return; if (!/^[0-9]+$/.test(value)) return desc + '必须为数字'; } function checkDigit(value, desc = '') { if (isNull(value)) return; if (!/^\d+(\.\d+)?$/.test(value)) return desc + '必须为数字或小数'; } function checkLetter(value, desc = '') { if (isNull(value)) return; if (!/^[A-Za-z]+$/.test(value)) return desc + '必须为字母'; } function checkMoney(value, desc = '') { if (isNull(value)) return; if (!/(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(value)) return desc + '必须为金额格式,例如2.00'; } function checkLetterNum(value, desc = '') { if (isNull(value)) return; if (!/^\w+$/.test(value)) return desc + '必须为字母,数字和下划线'; } function checkId(value, desc = '', min = 1, max = 100) { if (isNull(value)) return; min = Number(min); max = Number(max); if (getDataType(value) != String) return desc + '必须为ID字符串格式'; if (value.length < min || value.length > max) return desc + '必须为ID格式'; /*if (!/^\w+$/.test(value)) return desc + '必须为ID格式';*/ } // 邮箱 function checkEmail(value, desc = '') { if (isNull(value)) return; let reg = /^[A-Za-z0-9+]+[A-Za-z0-9\.\_\-+]*@([A-Za-z0-9\-]+\.)+[A-Za-z0-9]+$/; if (!reg.test(value)) return desc + '必须为邮箱格式'; } // 短日期,形如 (yyyy-mm-dd 2008-07-22) function checkDate(value, desc = '') { if (isNull(value)) return; let hint = '请选择' + desc; if (value.length != 10) return hint; let r = value.match(/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/); if (r == null) return hint; let d = new Date(r[1], r[3] - 1, r[4]); let chk = d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4]; if (!chk) return hint; } // 年份,形如 (yyyy 2008) function checkYear(value, desc = '') { if (isNull(value)) return; let hint = '请选择' + desc; if (value.length != 4) return hint; value += '-01-01'; return checkDate(value, desc); } // 年月,形如 (yyyy-mm 2008-01) function checkYearMonth(value, desc = '') { if (isNull(value)) return; let hint = '请选择' + desc; if (value.length != 7) return hint; value += '-01'; return checkDate(value, desc); } // 短时间(时分秒),形如 (13:04:06) function checkTime(value, desc = '') { if (isNull(value)) return; let hint = desc + '必须为时间格式'; if (value.length != 8) return hint; let a = value.match(/^(\d{1,2})(:)?(\d{1,2})\2(\d{1,2})$/); if (a == null) return hint; if (a[1] > 23 || a[3] > 59 || a[4] > 59) return hint; } // 短时间(时分),形如 (hh:mm 13:04) function checkHourMinute(value, desc = '') { if (isNull(value)) return; let hint = desc + '必须为时分时间格式'; if (value.length != 5) return hint; value += ':01'; return checkTime(value, desc); } // 长时间,形如 (2008-07-22 13:04:06) function checkDatimeTime(value, desc = '') { if (isNull(value)) return; let hint = desc + '必须为完整时间格式'; if (value.length != 19) return hint; var reg = /^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/; var r = value.match(reg); if (r == null) return hint; var d = new Date(r[1], r[3] - 1, r[4], r[5], r[6], r[7]); let chk = d.getFullYear() == r[1] && (d.getMonth() + 1) == r[3] && d.getDate() == r[4] && d.getHours() == r[5] && d.getMinutes() == r[6] && d.getSeconds() == r[7]; if (!chk) return hint; } function checkArray(value, desc = '') { if (!Array.isArray(value)) return desc + '填写错误arr'; } function checkObject(value, desc = '') { if (value.constructor != Object) return desc + '填写错误obj'; } function checkBoolean(value, desc = '') { if (value.constructor != Boolean) return desc + '填写错误bool'; } // 枚举 ref=1,2,3,4格式 function checkIn(value, ref, desc = '') { if (isNull(value)) return; let type = getDataType(value); if (type != String && type != Number) return desc + '填写范围错误'; let arr = String(ref).split(','); if (!arr.includes(value) && !arr.includes(value + '')) return desc + '填写范围错误'; } function checkIds(value, desc) {} function checkString(value, desc) { if (value.constructor != String) return desc + '填写错误'; } function check(data, rules, that) { let returnData = {}; for (let key in rules) { let arr = rules[key].split('|'); let desc = key; // 字段说明 let defVal = undefined; // 缺省值 let dataType = 'String'; //数据类型 if (!CHECK_OPEN) { // 不校验 // 取值 let val = data[formName]; returnData[key] = val; continue; } // 小循环获取规则 for (let i = 0; i < arr.length; i++) { // 数据项说明 if (arr[i].startsWith('name=')) { desc = '「' + arr[i].replace('name=', '') + '」'; continue; } // 缺省值 if (arr[i].startsWith('default=')) { defVal = arr[i].replace('default=', '').trim(); continue; } // 数据类型 switch (arr[i].toLowerCase()) { case 'int': case 'digit': dataType = 'Number'; break; case 'array': case 'arr': dataType = 'Array'; break; case 'object': case 'obj': dataType = 'Object'; break; case 'bool': case 'boolean': dataType = 'Boolean'; break; } } // 校验 let formName = (CHECK_SOURCE == 'admin') ? key : arr[0]; // 表单名 admin/client // 取值 let val = data[formName]; switch (dataType) { case 'Array': { if (defVal !== undefined) { try { defVal = JSON.parse(defVal); if (getDataType(defVal) != Array) return _showError(desc + '默认值数组格式错误', formName, that); } catch (ex) { return _showError(desc + '默认值数组格式错误', formName, that); } } if (val === null || val === undefined) val = defVal; if (val !== undefined && getDataType(val) != Array) return _showError(desc + '数组格式错误', formName, that); break; } case 'Object': { if (defVal !== undefined) { try { defVal = JSON.parse(defVal); if (getDataType(defVal) != Object) return _showError(desc + '默认值对象格式错误', formName, that); } catch (ex) { return _showError(desc + '默认值对象格式错误', formName, that); } } if (val === null || val === undefined) val = defVal; if (val !== undefined && getDataType(val) != Object) return _showError(desc + '对象格式错误', formName, that); break; } case 'Boolean': { if (defVal !== undefined) { try { defVal = JSON.parse(defVal); if (getDataType(defVal) != Boolean) return _showError(desc + '默认值布尔格式错误', formName, that); } catch (ex) { return _showError(desc + '默认值布尔格式错误'); } } if (val === null || val === undefined) val = defVal; if (val !== undefined && getDataType(val) != Boolean) return _showError(desc + '布尔格式错误', formName, that); break; } case 'Number': { if (checkDigit(defVal, desc + '默认值')) return _showError(desc + '默认值格式错误', formName, that); if (val === null || val === undefined) val = defVal; if (val === undefined) break; if (val === '') //数字不能为空 return _showError(desc + '不能为空', formName, that); let dataType = getDataType(val); if (dataType == Object || dataType == Boolean || dataType == Array) return _showError(desc + '必须为数字格式', formName, that); // 数字格式校验 let result = checkDigit(val, desc); if (result) return _showError(result, formName, that); val = Number(val); break; } case 'String': { let dataType = getDataType(val); if (dataType == Object || dataType == Boolean || dataType == Array) return _showError(desc + '必须为字符串格式', formName, that); if (val === null || val === undefined) val = defVal; if (val === undefined) break; try { val = String(val).trim(); // 数字会被转为字符串 } catch (ex) { return _showError(desc + '必须为字符串格式', formName, that); } break; } } returnData[key] = val; let fromStep = (CHECK_SOURCE == 'admin') ? 0 : 1; //admin/client for (let i = fromStep; i < arr.length; i++) { let result = ''; let rules = arr[i].split(':'); let ruleName = rules[0]; // 空 且非必填的 不校验 if (ruleName != 'must' && val === undefined) continue; switch (ruleName) { case 'must': result = checkRequired(val, desc); break; case 'str': case 'string': result = checkString(val, desc); break; case 'arr': case 'array': result = checkArray(val, desc); break; case 'obj': case 'object': result = checkObject(val, desc); break; case 'bool': case 'boolean': result = checkBoolean(val, desc); break; case 'money': result = checkMoney(val, desc); break; case 'year': result = checkYear(val, desc); break; case 'yearmonth': result = checkYearMonth(val, desc); break; case 'date': result = checkDate(val, desc); break; case 'time': result = checkTime(val, desc); break; case 'hourminute': result = checkHourMinute(val, desc); break; case 'datetime': result = checkDatimeTime(val, desc); break; case 'min': result = checkMin(val, Number(rules[1]), desc); break; case 'max': result = checkMax(val, Number(rules[1]), desc); break; case 'len': result = checkLen(val, Number(rules[1]), desc); break; case 'in': result = checkIn(val, rules[1], desc); break; case 'email': result = checkEmail(val, desc); break; case 'mobile': result = checkMobile(val, desc); break; case 'int': // 正整数 result = checkInt(val, desc); break; case 'digit': // 正小整数 result = checkDigit(val, desc); break; case 'id': result = checkId(val, desc); break; case 'letter': result = checkLetter(val, desc); break; case 'letter_num': result = checkLetterNum(val, desc); break; } if (result) { _showError(result, formName, that); return false; } else { if (that) { if (CHECK_SOURCE == 'client') { // 删除原有的自动聚焦 //admin/client if (isDefined(that.data[formName + 'Focus'])) { that.setData({ //TODO delete? [formName + 'Focus']: false }); } } } } } } return returnData; } function _showError(result, formName, that) { //admin/client if (CHECK_SOURCE == 'client') { wx.showModal({ title: '温馨提示', content: result, showCancel: false, success(res) { // 自动聚焦 if (that) { pageHelper.anchor(formName, that); that.setData({ [formName + 'Focus']: result, }); } } }); } else { throw new AppError(result, appCode.DATA); } } module.exports = { check, checkString, checkArray, checkObject, checkMoney, checkYear, checkYearMonth, checkDate, checkTime, checkHourMinute, checkDatimeTime, checkMin, checkMax, checkLen, checkIn, checkEmail, checkMobile, checkInt, // 正小整数 checkDigit, checkId, checkLetter, checkLetterNum, } ================================================ FILE: cloudfunctions/mcloud/index.js ================================================ const application = require('./framework/core/application.js'); // 云函数入口函数 exports.main = async (event, context) => { return await application.app(event, context); } ================================================ FILE: cloudfunctions/mcloud/package.json ================================================ { "name": "cloud", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "date-utils": "^1.2.21", "mysql": "^2.18.1", "node-xlsx": "^0.16.1", "wx-server-sdk": "~2.1.2" } } ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_album_controller.js ================================================ /** * Notes: 相册模块后台管理-控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminAlbumService = require('../../service/admin/admin_album_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); const AlbumModel = require('../../model/album_model.js'); class AdminAlbumController extends BaseProjectAdminController { /** 置顶与排序设定 */ async sortAlbum() { await this.isAdmin(); let rules = { id: 'must|id', sort: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminAlbumService(); await service.sortAlbum(input.id, input.sort); } /** 首页设定 */ async vouchAlbum() { await this.isAdmin(); let rules = { id: 'must|id', vouch: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminAlbumService(); await service.vouchAlbum(input.id, input.vouch); } /** 状态修改 */ async statusAlbum() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', status: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminAlbumService(); await service.statusAlbum(input.id, input.status); } /** 列表 */ async getAdminAlbumList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminAlbumService(); let result = await service.getAdminAlbumList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].ALBUM_ADD_TIME = timeUtil.timestamp2Time(list[k].ALBUM_ADD_TIME, 'Y-M-D h:m:s'); if (list[k].ALBUM_OBJ && list[k].ALBUM_OBJ.detail) delete list[k].ALBUM_OBJ.detail; } result.list = list; return result; } /** 发布 */ async insertAlbum() { await this.isAdmin(); // 数据校验 let rules = { title: 'must|string|min:2|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类名称', order: 'must|int|min:0|max:9999|name=排序号', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminAlbumService(); let result = await service.insertAlbum(input); this.logOther('添加了《' + input.title + '》'); return result; } /** 获取信息用于编辑修改 */ async getAlbumDetail() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminAlbumService(); return await service.getAlbumDetail(input.id); } /** 编辑 */ async editAlbum() { await this.isAdmin(); let rules = { id: 'must|id', title: 'must|string|min:2|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类名称', order: 'must|int|min:0|max:9999|name=排序号', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminAlbumService(); let result = service.editAlbum(input); this.logOther('修改了《' + input.title + '》'); return result; } /** 删除 */ async delAlbum() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let title = await AlbumModel.getOneField(input.id, 'ALBUM_TITLE'); let service = new AdminAlbumService(); await service.delAlbum(input.id); if (title) this.logOther('删除了《' + title + '》'); } /** 更新图片信息 */ async updateAlbumForms() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', hasImageForms: 'array' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminAlbumService(); return await service.updateAlbumForms(input); } } module.exports = AdminAlbumController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_home_controller.js ================================================ /** * Notes: 后台登录与首页模块 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-03-15 19:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminHomeService = require('../../service/admin/admin_home_service.js'); class AdminHomeController extends BaseProjectAdminController { // 管理首页 async adminHome() { await this.isAdmin(); // 数据校验 let rules = { }; // 取得数据 let input = this.validateData(rules); let service = new AdminHomeService(); return await service.adminHome(); } // 清除首页推荐 async clearVouchData() { await this.isAdmin(); // 数据校验 let rules = { }; // 取得数据 let input = this.validateData(rules); let service = new AdminHomeService(); return await service.clearVouchData(); } } module.exports = AdminHomeController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_meet_controller.js ================================================ /** * Notes: 预约模块后台管理-控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-08 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminMeetService = require('../../service/admin/admin_meet_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const MeetModel = require('../../model/meet_model.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); class AdminMeetController extends BaseProjectAdminController { // 计算可约天数 _getLeaveDay(days) { let now = timeUtil.time('Y-M-D'); let count = 0; for (let k = 0; k < days.length; k++) { if (days[k] >= now) count++; } return count; } async getDayList() { await this.isAdmin(); let rules = { meetId: 'must|id', start: 'must|date', end: 'must|date', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.getDayList(input.meetId, input.start, input.end); } /** 生成自助签到码 */ async genSelfCheckinQr() { await this.isAdmin(); let rules = { page: 'must|string', timeMark: 'must|string', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.genSelfCheckinQr(input.page, input.timeMark); } /** 管理员按钮核销 */ async checkinJoin() { await this.isAdmin(); let rules = { joinId: 'must|id', flag: 'must|in:0,1' }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); await service.checkinJoin(input.joinId, input.flag); } /** 管理员扫码核验 */ async scanJoin() { await this.isAdmin(); let rules = { meetId: 'must|id', code: 'must|string|len:15', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); await service.scanJoin(input.meetId, input.code); } /** 预约排序 */ async sortMeet() { // 数据校验 await this.isAdmin(); let rules = { meetId: 'must|id', sort: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); await service.sortMeet(input.meetId, input.sort); } /** 首页设定 */ async vouchMeet() { await this.isAdmin(); let rules = { id: 'must|id', vouch: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); await service.vouchMeet(input.id, input.vouch); } /** 预约状态修改 */ async statusMeet() { await this.isAdmin(); // 数据校验 let rules = { meetId: 'must|id', status: 'must|int|in:0,1,9,10', }; // 取得数据 let input = this.validateData(rules); let title = await MeetModel.getOneField(input.meetId, 'MEET_TITLE'); let service = new AdminMeetService(); await service.statusMeet(input.meetId, input.status); if (title) this.logOther('修改了预约《' + title + '》的状态为:' + MeetModel.getDesc('STATUS', input.status)); } /** 报名状态修改 */ async statusJoin() { await this.isAdmin(); // 数据校验 let rules = { joinId: 'must|id', status: 'must|int|in:0,1,8,9,10,98,99', reason: 'string|max:200', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.statusJoin(this._admin, input.joinId, input.status, input.reason); } /** 报名删除 */ async delJoin() { await this.isAdmin(); // 数据校验 let rules = { joinId: 'must|id' }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.delJoin(input.joinId); } /** 预约项目列表 */ async getAdminMeetList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int|default=10', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); let result = await service.getAdminMeetList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].MEET_ADD_TIME = timeUtil.timestamp2Time(list[k].MEET_ADD_TIME); list[k].MEET_EDIT_TIME = timeUtil.timestamp2Time(list[k].MEET_EDIT_TIME); list[k].leaveDay = this._getLeaveDay(list[k].MEET_DAYS); } result.list = list; return result; } /** 预约名单列表 */ async getJoinList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', meetId: 'must|id', mark: 'must|string', page: 'must|int|default=1', size: 'int|default=10', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); let result = await service.getJoinList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].JOIN_EDIT_TIME = timeUtil.timestamp2Time(list[k].JOIN_EDIT_TIME); //分解成数组,高亮显示 let forms = list[k].JOIN_FORMS; for (let j in forms) { forms[j].valArr = dataUtil.splitTextByKey(forms[j].val, input.search); } } result.list = list; return result; } /** 发布 */ async insertMeet() { await this.isAdmin(); let rules = { title: 'must|string|min:2|max:50|name=标题', typeId: 'must|id|name=分类', typeName: 'must|string|name=分类', order: 'must|int|min:0|max:9999|name=排序号', daysSet: 'must|array|name=预约时间设置', isShowLimit: 'must|int|in:0,1|name=是否显示可预约人数', formSet: 'must|array|name=用户资料设置', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMeetService(); let result = await service.insertMeet(this._adminId, input); this.logOther('创建了新预约《' + input.title + '》'); return result; } /** 获取预约信息用于编辑修改 */ async getMeetDetail() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); let detail = await service.getMeetDetail(input.id); return detail; } /** 编辑预约 */ async editMeet() { await this.isAdmin(); let rules = { id: 'must|id', title: 'must|string|min:2|max:50|name=标题', typeId: 'must|id|name=分类', typeName: 'must|string|name=分类', order: 'must|int|min:0|max:9999|name=排序号', daysSet: 'must|array|name=预约时间设置', isShowLimit: 'must|int|in:0,1|name=是否显示可预约人数', formSet: 'must|array|name=用户资料设置', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMeetService(); let result = service.editMeet(input); this.logOther('修改了预约《' + input.title + '》'); return result; } /** 删除预约 */ async delMeet() { await this.isAdmin(); // 数据校验 let rules = { meetId: 'must|id', }; // 取得数据 let input = this.validateData(rules); let title = await MeetModel.getOneField(input.meetId, 'MEET_TITLE'); let service = new AdminMeetService(); await service.delMeet(input.meetId); if (title) this.logOther('删除了预约《' + title + '》'); } /** * 更新富文本信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateMeetContent() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', content: 'array' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMeetService(); return await service.updateMeetContent(input); } /** * 更新封面设置 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateMeetStyleSet() { await this.isAdmin(); // 数据校验 let rules = { meetId: 'must|id', styleSet: 'object' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMeetService(); return await service.updateMeetStyleSet(input); } // 删除某时段预约记录 async cancelJoinByTimeMark() { await this.isAdmin(); // 数据校验 let rules = { meetId: 'must|id', timeMark: 'must|string', reason: 'string' }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.cancelJoinByTimeMark(this._admin, input.meetId, input.timeMark, input.reason); } /** 创建模板 */ async insertMeetTemp() { await this.isAdmin(); let rules = { name: 'must|string|min:1|max:20|name=名称', times: 'must|array|name=模板时段', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); let result = await service.insertMeetTemp(input); return result; } /** 编辑模板 */ async editMeetTemp() { await this.isAdmin(); let rules = { id: 'must|id', isLimit: 'must|bool|name=是否限制', limit: 'must|int|name=人数上限', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); let result = service.editMeetTemp(input); return result; } /** 模板列表 */ async getMeetTempList() { await this.isAdmin(); let service = new AdminMeetService(); let result = await service.getMeetTempList(); return result; } /** 删除模板 */ async delMeetTemp() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); await service.delMeetTemp(input.id); } /**************报名数据导出 BEGIN ********************* */ /** 当前是否有导出文件生成 */ async joinDataGet() { await this.isAdmin(); // 数据校验 let rules = { isDel: 'int|must', //是否删除已有记录 }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); if (input.isDel === 1) await service.deleteJoinDataExcel(); //先删除 return await service.getJoinDataURL(); } /** 导出数据 */ async joinDataExport() { await this.isAdmin(); // 数据校验 let rules = { meetId: 'id|must', startDay: 'date|must', endDay: 'date|must', status: 'int|must|default=1' }; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.exportJoinDataExcel(input); } /** 删除导出的报名数据文件 */ async joinDataDel() { await this.isAdmin(); // 数据校验 let rules = {}; // 取得数据 let input = this.validateData(rules); let service = new AdminMeetService(); return await service.deleteJoinDataExcel(); } } module.exports = AdminMeetController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_mgr_controller.js ================================================ /** * Notes: 管理员控制模块 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const LogModel = require('../../../../framework/platform/model/log_model.js'); const AdminMgrService = require('../../service/admin/admin_mgr_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); class AdminMgrController extends BaseProjectAdminController { // 管理员登录 async adminLogin() { // 数据校验 let rules = { name: 'must|string|min:5|max:30|name=管理员名', pwd: 'must|string|min:5|max:30|name=密码', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); return await service.adminLogin(input.name, input.pwd); } /** 删除管理员 */ async delMgr() { await this.isSuperAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); await service.delMgr(input.id, this._adminId); } /** 管理员状态修改 */ async statusMgr() { await this.isSuperAdmin(); // 数据校验 let rules = { id: 'must|id', status: 'must|int|in:0,1', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); await service.statusMgr(input.id, input.status, this._admin.ADMIN_PHONE); } /** 管理员列表 */ async getMgrList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int|default=10', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); let result = await service.getMgrList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].ADMIN_EDIT_TIME = timeUtil.timestamp2Time(list[k].ADMIN_EDIT_TIME); list[k].ADMIN_LOGIN_TIME = (list[k].ADMIN_LOGIN_TIME == 0) ? '未登录' : timeUtil.timestamp2Time(list[k].ADMIN_LOGIN_TIME); } result.list = list; return result; } /** 添加管理员 */ async insertMgr() { await this.isSuperAdmin(); // 数据校验 let rules = { name: 'must|string|min:5|max:30|name=账号', desc: 'must|string|max:30|name=姓名', phone: 'string|len:11|name=手机', password: 'must|string|min:6|max:30|name=密码', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMgrService(); await service.insertMgr(input); } /** 修改管理员 */ async editMgr() { await this.isSuperAdmin(); // 数据校验 let rules = { id: 'must|id|name=id', name: 'must|string|min:5|max:30|name=账号', desc: 'must|string|max:30|name=姓名', phone: 'string|len:11|name=手机', password: 'string|min:6|max:30|name=新密码', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMgrService(); await service.editMgr(input.id, input); } /** 修改自己的密码 */ async pwdMgr() { await this.isAdmin(); // 数据校验 let rules = { oldPassword: 'must|string|min:6|max:30|name=旧密码', password: 'must|string|min:6|max:30|name=新密码', password2: 'must|string|min:6|max:30|name=新密码再次填写', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminMgrService(); await service.pwdtMgr(this._adminId, input.oldPassword, input.password); } /** 获取管理员信息用于编辑修改 */ async getMgrDetail() { await this.isSuperAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); return await service.getMgrDetail(input.id); } async clearLog() { await this.isAdmin(); let service = new AdminMgrService(); return await service.clearLog(); } async getLogList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminMgrService(); let result = await service.getLogList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].LOG_TYPE_DESC = LogModel.getDesc('TYPE', list[k].LOG_TYPE); list[k].LOG_ADD_TIME = timeUtil.timestamp2Time(list[k].LOG_ADD_TIME); } result.list = list; return result; } } module.exports = AdminMgrController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_news_controller.js ================================================ /** * Notes: 资讯模块后台管理-控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminNewsService = require('../../service/admin/admin_news_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); const NewsModel = require('../../model/news_model.js'); class AdminNewsController extends BaseProjectAdminController { /** 置顶与排序设定 */ async sortNews() { await this.isAdmin(); let rules = { id: 'must|id', sort: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminNewsService(); await service.sortNews(input.id, input.sort); } /** 首页设定 */ async vouchNews() { await this.isAdmin(); let rules = { id: 'must|id', vouch: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminNewsService(); await service.vouchNews(input.id, input.vouch); } /** 资讯状态修改 */ async statusNews() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', status: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminNewsService(); await service.statusNews(input.id, input.status); } /** 资讯列表 */ async getAdminNewsList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminNewsService(); let result = await service.getAdminNewsList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].NEWS_ADD_TIME = timeUtil.timestamp2Time(list[k].NEWS_ADD_TIME, 'Y-M-D h:m'); list[k].NEWS_EDIT_TIME = timeUtil.timestamp2Time(list[k].NEWS_EDIT_TIME, 'Y-M-D h:m'); if (list[k].NEWS_OBJ && list[k].NEWS_OBJ.desc) delete list[k].NEWS_OBJ.desc; } result.list = list; return result; } /** * 更新富文本信息 */ async updateNewsContent() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', content: 'array' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminNewsService(); return await service.updateNewsContent(input); } /** 发布资讯信息 */ async insertNews() { await this.isAdmin(); // 数据校验 let rules = { title: 'must|string|min:4|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类名', order: 'must|int|min:0|max:9999|name=排序号', desc: 'must|string|min:10|max:200|name=简介', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminNewsService(); let result = await service.insertNews(input); this.logNews('添加了文章《' + input.title + '》'); return result; } /** 获取资讯信息用于编辑修改 */ async getNewsDetail() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminNewsService(); return await service.getNewsDetail(input.id); } /** 编辑资讯 */ async editNews() { await this.isAdmin(); let rules = { id: 'must|id', title: 'must|string|min:4|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类', order: 'must|int|min:0|max:9999|name=排序号', desc: 'string|min:10|max:200|name=简介', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminNewsService(); let result = service.editNews(input); this.logNews('修改了文章《' + input.title + '》'); return result; } /** 删除资讯 */ async delNews() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let title = await NewsModel.getOneField(input.id, 'NEWS_TITLE'); let service = new AdminNewsService(); await service.delNews(input.id); if (title) this.logNews('删除了文章《' + title + '》'); } /** * 更新图片信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateNewsPic() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', imgList: 'array' }; // 取得数据 let input = this.validateData(rules); let service = new AdminNewsService(); return await service.updateNewsPic(input); } /** 更新图片信息 */ async updateNewsForms() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', hasImageForms: 'array' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminNewsService(); return await service.updateNewsForms(input); } } module.exports = AdminNewsController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_product_controller.js ================================================ /** * Notes: 产品模块后台管理-控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminProductService = require('../../service/admin/admin_product_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); const ProductModel = require('../../model/product_model.js'); class AdminProductController extends BaseProjectAdminController { /** 置顶与排序设定 */ async sortProduct() { await this.isAdmin(); let rules = { id: 'must|id', sort: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminProductService(); await service.sortProduct(input.id, input.sort); } /** 首页设定 */ async vouchProduct() { await this.isAdmin(); let rules = { id: 'must|id', vouch: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminProductService(); await service.vouchProduct(input.id, input.vouch); } /** 状态修改 */ async statusProduct() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', status: 'must|int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminProductService(); await service.statusProduct(input.id, input.status); } /** 列表 */ async getAdminProductList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminProductService(); let result = await service.getAdminProductList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].PRODUCT_ADD_TIME = timeUtil.timestamp2Time(list[k].PRODUCT_ADD_TIME, 'Y-M-D h:m:s'); if (list[k].PRODUCT_OBJ && list[k].PRODUCT_OBJ.desc) delete list[k].PRODUCT_OBJ.desc; } result.list = list; return result; } /** 发布 */ async insertProduct() { await this.isAdmin(); // 数据校验 let rules = { title: 'must|string|min:2|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类名称', order: 'must|int|min:0|max:9999|name=排序号', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminProductService(); let result = await service.insertProduct(input); this.logOther('添加了《' + input.title + '》'); return result; } /** 获取信息用于编辑修改 */ async getProductDetail() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminProductService(); return await service.getProductDetail(input.id); } /** 编辑 */ async editProduct() { await this.isAdmin(); let rules = { id: 'must|id', title: 'must|string|min:2|max:50|name=标题', cateId: 'must|string|name=分类', cateName: 'must|string|name=分类名称', order: 'must|int|min:0|max:9999|name=排序号', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminProductService(); let result = service.editProduct(input); this.logOther('修改了《' + input.title + '》'); return result; } /** 删除 */ async delProduct() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let title = await ProductModel.getOneField(input.id, 'PRODUCT_TITLE'); let service = new AdminProductService(); await service.delProduct(input.id); if (title) this.logOther('删除了《' + title + '》'); } /** 更新图片信息 */ async updateProductForms() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', hasImageForms: 'array' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminProductService(); return await service.updateProductForms(input); } } module.exports = AdminProductController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_setup_controller.js ================================================ /** * Notes: 设置控制模块 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const AdminSetupService = require('../../service/admin/admin_setup_service.js'); const contentCheck = require('../../../../framework/validate/content_check.js'); class AdminSetupController extends BaseProjectAdminController { // 通用setup async setSetup() { await this.isAdmin(); // 数据校验 let rules = { key: 'must|string|name=KEY', content: 'name=内容', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminSetupService(); await service.setSetup(input.key, input.content); } // 富文本setup async setContentSetup() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|string|name=KEY', content: 'must|array|name=内容' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiAdmin(input); let service = new AdminSetupService(); await service.setSetup(input.id, input.content, 'content'); } async genMiniQr() { await this.isAdmin(); // 数据校验 let rules = { path: 'must|string', sc: 'string', }; // 取得数据 let input = this.validateData(rules); let service = new AdminSetupService(); return await service.genMiniQr(input.path, input.sc); } } module.exports = AdminSetupController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/admin_user_controller.js ================================================ /** * Notes: 用户控制模块 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-01-22 10:20:00 */ const BaseProjectAdminController = require('./base_project_admin_controller.js'); const UserModel = require('../../model/user_model.js'); const AdminUserService = require('../../service/admin/admin_user_service.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); class AdminUserController extends BaseProjectAdminController { /** 用户信息 */ async getUserDetail() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); let user = await service.getUser({ userId: input.id }); if (user) { // 显示转换 user.USER_ADD_TIME = timeUtil.timestamp2Time(user.USER_ADD_TIME); user.USER_LOGIN_TIME = user.USER_LOGIN_TIME ? timeUtil.timestamp2Time(user.USER_LOGIN_TIME) : '未登录'; } return user; } /** 用户列表 */ async getUserList() { await this.isAdmin(); // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', whereEx: 'object|name=附加查询条件', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); let result = await service.getUserList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].USER_STATUS_DESC = UserModel.getDesc('STATUS', list[k].USER_STATUS); list[k].USER_ADD_TIME = timeUtil.timestamp2Time(list[k].USER_ADD_TIME); list[k].USER_LOGIN_TIME = list[k].USER_LOGIN_TIME ? timeUtil.timestamp2Time(list[k].USER_LOGIN_TIME) : '未登录'; } result.list = list; return result; } /** 删除用户 */ async delUser() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let title = await UserModel.getOneField({ USER_MINI_OPENID: input.id }, 'USER_NAME'); let service = new AdminUserService(); await service.delUser(input.id); if (title) this.logUser('删除了用户「' + title + '」'); } async statusUser() { await this.isAdmin(); // 数据校验 let rules = { id: 'must|id', status: 'must|int', reason: 'string' }; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); await service.statusUser(input.id, input.status, input.reason); } /************** 用户数据导出 BEGIN ********************* */ /** 当前是否有导出文件生成 */ async userDataGet() { await this.isAdmin(); // 数据校验 let rules = { isDel: 'int|must', //是否删除已有记录 }; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); if (input.isDel === 1) await service.deleteUserDataExcel(); //先删除 return await service.getUserDataURL(); } /** 导出数据 */ async userDataExport() { await this.isAdmin(); // 数据校验 let rules = { condition: 'string|name=导出条件', fields: 'array', }; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); return await service.exportUserDataExcel(input.condition, input.fields); } /** 删除导出的用户数据 */ async userDataDel() { await this.isAdmin(); // 数据校验 let rules = {}; // 取得数据 let input = this.validateData(rules); let service = new AdminUserService(); return await service.deleteUserDataExcel(); } } module.exports = AdminUserController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/admin/base_project_admin_controller.js ================================================ /** * Notes: 后台管理控制模块 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-03-15 19:20:00 */ const BaseAdminController = require('../../../../framework/platform/controller/base_admin_controller.js'); const BaseProjectService = require('../../service/base_project_service.js'); class BaseProjectAdminController extends BaseAdminController { // TODO async initSetup() { let service = new BaseProjectService(); await service.initSetup(); } } module.exports = BaseProjectAdminController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/album_controller.js ================================================ /** * Notes: 相册模块控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-07 04:00:00 */ const BaseProjectController = require('./base_project_controller.js'); const AlbumService = require('../service/album_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); class AlbumController extends BaseProjectController { /** 列表 */ async getAlbumList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new AlbumService(); let result = await service.getAlbumList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].ALBUM_ADD_TIME = timeUtil.timestamp2Time(list[k].ALBUM_ADD_TIME, 'Y-M-D'); if (list[k].ALBUM_OBJ && list[k].ALBUM_OBJ.detail) delete list[k].ALBUM_OBJ.detail; } return result; } /** 浏览详细 */ async viewAlbum() { // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new AlbumService(); let album = await service.viewAlbum(input.id); if (album) { // 显示转换 album.ALBUM_ADD_TIME = timeUtil.timestamp2Time(album.ALBUM_ADD_TIME, 'Y-M-D'); } return album; } } module.exports = AlbumController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/base_project_controller.js ================================================ /** * Notes: 本业务基本控制器 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseController = require('../../../framework/platform/controller/base_controller.js'); const BaseProjectService = require('../service/base_project_service.js'); class BaseProjectController extends BaseController { // TODO async initSetup() { let service = new BaseProjectService(); await service.initSetup(); } } module.exports = BaseProjectController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/check_controller.js ================================================ /** * Notes: 内容检测控制器 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectController = require('./base_project_controller.js'); const contentCheck = require('../../framework/validate/content_check.js'); class CheckController extends BaseProjectController { /** * 图片校验 */ async checkImg() { // 数据校验 let rules = { img: 'name=img', mine: 'must|default=jpg', }; // 取得数据 let input = this.validateData(rules); return await contentCheck.checkImg(input.img, 'jpg'); } } module.exports = CheckController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/fav_controller.js ================================================ /** * Notes: 预约模块控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-10 04:00:00 */ const BaseProjectController = require('./base_project_controller.js'); const FavService = require('../service/fav_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); class FavController extends BaseProjectController { /** 更新某人收藏 */ async updateFav() { // 数据校验 let rules = { oid: 'id|must', title: 'string|must', type: 'string|must', path: 'string|must', }; // 取得数据 let input = this.validateData(rules); let service = new FavService(); return await service.updateFav(this._userId, input.oid, input.title, input.type, input.path); } /** 删除收藏 */ async delFav() { // 数据校验 let rules = { oid: 'id|must' }; // 取得数据 let input = this.validateData(rules); let service = new FavService(); return await service.updateFav(this._userId, input.oid); } /** 是否收藏 */ async isFav() { // 数据校验 let rules = { oid: 'id|must', }; // 取得数据 let input = this.validateData(rules); let service = new FavService(); return await service.isFav(this._userId, input.oid); } /** 我的收藏列表 */ async getMyFavList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new FavService(); let result = await service.getMyFavList(this._userId, input); // 数据格式化 let list = result.list; // 显示转换 for (let k = 0; k < list.length; k++) { list[k].FAV_ADD_TIME = timeUtil.timestamp2Time(list[k].FAV_ADD_TIME); } result.list = list; return result; } } module.exports = FavController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/home_controller.js ================================================ /** * Notes: 全局或者主页模块控制器 * Date: 2020-11-05 10:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectController = require('./base_project_controller.js'); const HomeService = require('../service/home_service.js'); class HomeController extends BaseProjectController { async getSetup() { // 数据校验 let rules = { key: 'must|string|name=KEY', }; // 取得数据 let input = this.validateData(rules); let service = new HomeService(); return await service.getSetup(input.key); } /** 首页推荐列表 */ async getHomeList() { let service = new HomeService(); return await service.getHomeList(); } } module.exports = HomeController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/meet_controller.js ================================================ /** * Notes: 预约模块控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-10 04:00:00 */ const BaseProjectController = require('./base_project_controller.js'); const MeetService = require('../service/meet_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); const JoinModel = require('../model/join_model.js'); class MeetController extends BaseProjectController { // 把列表转换为显示模式 transMeetList(list) { let ret = []; for (let k = 0; k < list.length; k++) { let node = {}; node.type = 'meet'; node.id = list[k]._id; node.title = list[k].MEET_TITLE; node.desc = list[k].MEET_STYLE_SET.desc; node.ext = list[k].openRule; node.pic = list[k].MEET_STYLE_SET.pic; ret.push(node); } return ret; } /** 按天获取预约项目 */ async getMeetListByDay() { // 数据校验 let rules = { day: 'must|date|name=日期', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let list = await service.getMeetListByDay(input.day); return list; } /** 获取从某天开始可预约的日期 */ async getHasDaysFromDay() { // 数据校验 let rules = { day: 'must|date|name=日期', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let list = await service.getHasDaysFromDay(input.day); return list; } /** 预约列表 */ async getMeetList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', typeId: 'string', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let result = await service.getMeetList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].openRule = this._getLeaveDay(list[k].MEET_DAYS) + '天可预约'; } result.list = this.transMeetList(list); return result; } /** 我的预约列表 */ async getMyJoinList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let result = await service.getMyJoinList(this._userId, input); // 数据格式化 let list = result.list; let now = timeUtil.time('Y-M-D h:m'); for (let k = 0; k < list.length; k++) { if (now > (list[k].JOIN_MEET_DAY + ' ' + list[k].JOIN_MEET_TIME_END)) list[k].isTimeout = 1; else list[k].isTimeout = 0; list[k].JOIN_MEET_DAY = timeUtil.fmtDateCHN(list[k].JOIN_MEET_DAY) + ' (' + timeUtil.week(list[k].JOIN_MEET_DAY) + ')'; list[k].JOIN_ADD_TIME = timeUtil.timestamp2Time(list[k].JOIN_ADD_TIME, 'Y-M-D h:m'); } result.list = list; return result; } /** 我的某日预约列表 */ async getMyJoinSomeday() { // 数据校验 let rules = { day: 'must|date|name=日期', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let list = await service.getMyJoinSomeday(this._userId, input.day); // 数据格式化 for (let k = 0; k < list.length; k++) { } return list; } /** 我的预约详情 */ async getMyJoinDetail() { // 数据校验 let rules = { joinId: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let join = await service.getMyJoinDetail(this._userId, input.joinId); if (join) { join.JOIN_STATUS_DESC = JoinModel.getDesc('STATUS', join.JOIN_STATUS); join.JOIN_ADD_TIME = timeUtil.timestamp2Time(join.JOIN_ADD_TIME); } return join; } /** 用户预约取消 */ async cancelMyJoin() { // 数据校验 let rules = { joinId: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); return await service.cancelMyJoin(this._userId, input.joinId); } /** 用户自助签到 */ async userSelfCheckin() { // 数据校验 let rules = { timeMark: 'must|string', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); return await service.userSelfCheckin(this._userId, input.timeMark); } /** 预约前获取关键信息 */ async detailForJoin() { // 数据校验 let rules = { meetId: 'must|meetId', timeMark: 'must|string', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let meet = await service.detailForJoin(this._userId, input.meetId, input.timeMark); if (meet) { // 显示转换 } return meet; } /** 浏览预约信息 */ async viewMeet() { // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); let meet = await service.viewMeet(input.id); if (meet) { // 显示转换 } return meet; } /** 预约前检测 */ async beforeJoin() { // 数据校验 let rules = { meetId: 'must|id', timeMark: 'must|string', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); return await service.beforeJoin(this._userId, input.meetId, input.timeMark); } /** 预约提交 */ async join() { // 数据校验 let rules = { meetId: 'must|id', timeMark: 'must|string', forms: 'must|array', }; // 取得数据 let input = this.validateData(rules); let service = new MeetService(); return await service.join(this._userId, input.meetId, input.timeMark, input.forms); } // 计算可约天数 _getLeaveDay(days) { let now = timeUtil.time('Y-M-D'); let count = 0; for (let k = 0; k < days.length; k++) { if (days[k] >= now) count++; } return count; } } module.exports = MeetController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/my_controller.js ================================================ /** * Notes: 用户中心模块控制器 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectController = require('./base_project_controller.js'); class MyController extends BaseProjectController { } module.exports = MyController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/news_controller.js ================================================ /** * Notes: 资讯模块控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-09-29 04:00:00 */ const BaseProjectController = require('./base_project_controller.js'); const NewsService = require('../service/news_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); class NewsController extends BaseProjectController { // 把列表转换为显示模式 transNewsList(list) { let ret = []; for (let k = 0; k < list.length; k++) { let node = {}; node.type = 'news'; node.id = list[k]._id; node.title = list[k].NEWS_TITLE; node.desc = list[k].NEWS_DESC; node.ext = list[k].NEWS_ADD_TIME; node.pic = list[k].NEWS_PIC[0]; ret.push(node); } return ret; } /** 资讯列表 */ async getNewsList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', cateId: 'string', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new NewsService(); let result = await service.getNewsList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].NEWS_ADD_TIME = timeUtil.timestamp2Time(list[k].NEWS_ADD_TIME, 'Y-M-D'); if (list[k].NEWS_OBJ && list[k].NEWS_OBJ.desc) delete list[k].NEWS_OBJ.desc; } result.list = this.transNewsList(list); return result; } /** 浏览资讯信息 */ async viewNews() { // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new NewsService(); let news = await service.viewNews(input.id); if (news) { // 显示转换 news.NEWS_ADD_TIME = timeUtil.timestamp2Time(news.NEWS_ADD_TIME, 'Y-M-D'); } return news; } } module.exports = NewsController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/passport_controller.js ================================================ /** * Notes: passport模块控制器 * Date: 2021-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectController = require('./base_project_controller.js'); const PassportService = require('../service/passport_service.js'); const contentCheck = require('../../../framework/validate/content_check.js'); class PassportController extends BaseProjectController { /** 取得我的用户信息 */ async getMyDetail() { let service = new PassportService(); return await service.getMyDetail(this._userId); } /** 获取手机号码 */ async getPhone() { // 数据校验 let rules = { cloudID: 'must|string|min:1|max:200|name=cloudID', }; // 取得数据 let input = this.validateData(rules); let service = new PassportService(); return await service.getPhone(input.cloudID); } /** 注册 */ async register() { // 数据校验 let rules = { name: 'must|string|min:1|max:30|name=昵称', mobile: 'must|mobile|name=手机', forms: 'array|name=表单', status: 'int|default=1' }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiClient(input); let service = new PassportService(); return await service.register(this._userId, input); } /** 修改用户资料 */ async editBase() { // 数据校验 let rules = { name: 'must|string|min:1|max:30|name=昵称', mobile: 'must|mobile|name=手机', forms: 'array|name=表单', }; // 取得数据 let input = this.validateData(rules); // 内容审核 await contentCheck.checkTextMultiClient(input); let service = new PassportService(); return await service.editBase(this._userId, input); } /** 登录 */ async login() { // 数据校验 let rules = {}; // 取得数据 let input = this.validateData(rules); let service = new PassportService(); return await service.login(this._userId); } } module.exports = PassportController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/product_controller.js ================================================ /** * Notes: 产品模块控制器 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-08 04:00:00 */ const BaseProjectController = require('./base_project_controller.js'); const ProductService = require('../service/product_service.js'); const timeUtil = require('../../../framework/utils/time_util.js'); const dataUtil = require('../../../framework/utils/data_util.js'); class ProductController extends BaseProjectController { /** 列表 */ async getProductList() { // 数据校验 let rules = { search: 'string|min:1|max:30|name=搜索条件', sortType: 'string|name=搜索类型', sortVal: 'name=搜索类型值', orderBy: 'object|name=排序', page: 'must|int|default=1', size: 'int', isTotal: 'bool', oldTotal: 'int', }; // 取得数据 let input = this.validateData(rules); let service = new ProductService(); let result = await service.getProductList(input); // 数据格式化 let list = result.list; for (let k = 0; k < list.length; k++) { list[k].PRODUCT_ADD_TIME = timeUtil.timestamp2Time(list[k].PRODUCT_ADD_TIME, 'Y-M-D'); list[k].PRODUCT_OBJ.desc = dataUtil.fmtText(list[k].PRODUCT_OBJ.desc, 100); list[k].PRODUCT_OBJ.star = (list[k].PRODUCT_OBJ.star); } return result; } /** 浏览详细 */ async viewProduct() { // 数据校验 let rules = { id: 'must|id', }; // 取得数据 let input = this.validateData(rules); let service = new ProductService(); let product = await service.viewProduct(input.id); if (product) { // 显示转换 product.PRODUCT_ADD_TIME = timeUtil.timestamp2Time(product.PRODUCT_ADD_TIME, 'Y-M-D'); } return product; } } module.exports = ProductController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/controller/test/test_controller.js ================================================ /** * Notes: 测试模块控制器 * Date: 2021-03-15 19:20:00 */ const BaseController = require('../../controller/base_project_controller.js'); const fakerLib = require('../../../../framework/lib/faker_lib.js'); const VoteModel = require('../../model/vote_model.js'); const VoteJoinModel = require('../../model/vote_join_model.js'); const VoteService = require('../../service/vote_service.js'); const EnrollModel = require('../../model/enroll_model.js'); const EnrollJoinModel = require('../../model/enroll_join_model.js'); const ActivityModel = require('../../model/activity_model.js'); const ActivityJoinModel = require('../../model/activity_join_model.js'); class TestController extends BaseController { async test() { console.log('TEST>>>>>>>'); //this.mockEnrollJoin(); //this.mockActivityJoin(); this.mockVoteJoin(); } async mockEnrollJoin() { console.log('mockEnrollJoin >>>>>>> Begin....'); let ENROLL_ID = 'b69f67c062d7d46b0bc4d2985c084775'; let enroll = await EnrollModel.getOne(ENROLL_ID); if (!enroll) return console.error('no enroll'); let join = {}; join.ENROLL_JOIN_ENROLL_ID = ENROLL_ID; join.ENROLL_JOIN_STATUS = 1; console.log('>>>>delete'); let delCnt = await EnrollJoinModel.del({ ENROLL_JOIN_ENROLL_ID: ENROLL_ID }); console.log('>>>>delete=' + delCnt); for (let k = 1; k <= 10; k++) { console.log('>>>>insert >' + k); join.ENROLL_JOIN_USER_ID = fakerLib.getUuid(); join.ENROLL_JOIN_LAST_TIME = fakerLib.getAddTimestamp(); join.ENROLL_JOIN_ADD_TIME = fakerLib.getAddTimestamp(); join.ENROLL_JOIN_FORMS = [ { mark: 'name', title: '姓名', type: 'text', val: fakerLib.getName() }, { mark: 'phone', title: '手机', type: 'mobile', val: fakerLib.getMobile() } ]; await EnrollJoinModel.insert(join); } console.log('>>>> STAT'); let cnt = await EnrollJoinModel.count({ ENROLL_JOIN_ENROLL_ID: ENROLL_ID }); await EnrollModel.edit(ENROLL_ID, { ENROLL_JOIN_CNT: cnt, ENROLL_MAX_CNT: cnt + 10 }); console.log('mockEnrollJoin >>>>>>> END'); } async mockActivityJoin() { console.log('mockActivityJoin >>>>>>> Begin....'); let ACTIVITY_ID = '0a4ec1f962d867481158b94f6441f613'; let activity = await ActivityModel.getOne(ACTIVITY_ID); if (!activity) return console.error('no activity'); let join = {}; join.ACTIVITY_JOIN_ACTIVITY_ID = ACTIVITY_ID; join.ACTIVITY_JOIN_STATUS = 1; console.log('>>>>delete'); let delCnt = await ActivityJoinModel.del({ ACTIVITY_JOIN_ACTIVITY_ID: ACTIVITY_ID }); console.log('>>>>delete=' + delCnt); for (let k = 1; k <= 10; k++) { console.log('>>>>insert >' + k); join.ACTIVITY_JOIN_USER_ID = fakerLib.getUuid(); join.ACTIVITY_JOIN_CODE = fakerLib.getStr(15); join.ACTIVITY_JOIN_ADD_TIME = fakerLib.getAddTimestamp(); join.ACTIVITY_JOIN_FORMS = [ { mark: 'name', title: '姓名', type: 'text', val: fakerLib.getName() }, { mark: 'phone', title: '手机', type: 'mobile', val: fakerLib.getMobile() } ]; await ActivityJoinModel.insert(join); } console.log('>>>> STAT'); let cnt = await ActivityJoinModel.count({ ACTIVITY_JOIN_ACTIVITY_ID: ACTIVITY_ID }); await ActivityModel.edit(ACTIVITY_ID, { ACTIVITY_JOIN_CNT: cnt, ACTIVITY_MAX_CNT: cnt + 10 }); console.log('mockActivityJoin >>>>>>> END'); } async mockVoteJoin() { console.log('mockVoteJoin >>>>>>> Begin....'); let VOTE_ID = 'b69f67c062c3a2b209da6ef133c9d874'; let vote = await VoteModel.getOne(VOTE_ID); if (!vote) return console.error('no vote'); let join = {}; join.VOTE_JOIN_VOTE_ID = VOTE_ID; console.log('>>>>delete'); let delCnt = await VoteJoinModel.del({ VOTE_JOIN_VOTE_ID: VOTE_ID }); console.log('>>>>delete=' + delCnt); for (let k = 1; k <= 10; k++) { console.log('>>>>insert >' + k); join.VOTE_JOIN_USER_ID = fakerLib.getUuid(); join.VOTE_JOIN_ADD_TIME = fakerLib.getAddTimestamp(); join.VOTE_JOIN_CNT = 1; join.VOTE_JOIN_SELECTED = [k % vote.VOTE_ITEM.length]; await VoteJoinModel.insert(join); } console.log('>>>> STAT'); let service = new VoteService(); service.statVoteItem(VOTE_ID); console.log('mockVoteJoin >>>>>>> END'); } } module.exports = TestController; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/album_model.js ================================================ /** * Notes: 相册实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-05 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class AlbumModel extends BaseProjectModel { } // 集合名 AlbumModel.CL = BaseProjectModel.C('album'); AlbumModel.DB_STRUCTURE = { _pid: 'string|true', ALBUM_ID: 'string|true', ALBUM_TITLE: 'string|true|comment=标题', ALBUM_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中', ALBUM_CATE_ID: 'string|true|default=0|comment=分类', ALBUM_CATE_NAME: 'string|false|comment=分类名冗余', ALBUM_ORDER: 'int|true|default=9999', ALBUM_VOUCH: 'int|true|default=0', ALBUM_FORMS: 'array|true|default=[]', ALBUM_OBJ: 'object|true|default={}', ALBUM_QR: 'string|false', ALBUM_VIEW_CNT: 'int|true|default=0', ALBUM_ADD_TIME: 'int|true', ALBUM_EDIT_TIME: 'int|true', ALBUM_ADD_IP: 'string|false', ALBUM_EDIT_IP: 'string|false', }; // 字段前缀 AlbumModel.FIELD_PREFIX = "ALBUM_"; /** * 状态 0=未启用,1=使用中 */ AlbumModel.STATUS = { UNUSE: 0, COMM: 1 }; module.exports = AlbumModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/base_project_model.js ================================================ /** * Notes: 实体ORM基类 * Date: 2022-03-15 19:20:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseModel = require('../../../framework/platform/model/base_model.js'); class BaseProjectModel extends BaseModel { } module.exports = BaseProjectModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/day_model.js ================================================ /** * Notes: 预约日期设置实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-01-25 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class DayModel extends BaseProjectModel { } // 集合名 DayModel.CL = BaseProjectModel.C('day'); DayModel.DB_STRUCTURE = { _pid: 'string|true', DAY_ID: 'string|true', DAY_MEET_ID: 'string|true', day: 'string|true|comment=日期 yyyy-mm-dd', dayDesc: 'string|true|comment=描述', times: 'array|true|comment=具体时间段', /* { 1. mark=唯一性标识, 2. start=开始时间点hh:mm ~, 3. end=结束时间点hh:mm, 4. isLimit=是否人数限制, 5. limit=报名上限, 6. status=状态 0/1 7. stat:{ //统计数据 succCnt=1预约成功*, cancelCnt=10已取消, adminCancelCnt=99后台取消 } }', */ DAY_ADD_TIME: 'int|true', DAY_EDIT_TIME: 'int|true', DAY_ADD_IP: 'string|false', DAY_EDIT_IP: 'string|false', }; // 字段前缀 DayModel.FIELD_PREFIX = "DAY_"; module.exports = DayModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/fav_model.js ================================================ /** * Notes: 收藏实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-05-24 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class FavModel extends BaseProjectModel { } // 集合名 FavModel.CL = BaseProjectModel.C('fav'); FavModel.DB_STRUCTURE = { _pid: 'string|true', FAV_ID: 'string|true', FAV_USER_ID: 'string|true', FAV_TITLE: 'string|true|comment=标题', FAV_TYPE: 'string|true|comment=类型', FAV_OID: 'string|true|comment=相关表主键', FAV_PATH: 'string|true|comment=路径', FAV_ADD_TIME: 'int|true', FAV_EDIT_TIME: 'int|true', FAV_ADD_IP: 'string|false', FAV_EDIT_IP: 'string|false', }; // 字段前缀 FavModel.FIELD_PREFIX = "FAV_"; module.exports = FavModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/join_model.js ================================================ /** * Notes: 报名实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-30 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class JoinModel extends BaseProjectModel { } // 集合名 JoinModel.CL = BaseProjectModel.C('join'); JoinModel.DB_STRUCTURE = { _pid: 'string|true', JOIN_ID: 'string|true', JOIN_EDIT_ADMIN_ID: 'string|false|comment=最近修改的管理员ID', JOIN_EDIT_ADMIN_NAME: 'string|false|comment=最近修改的管理员名', JOIN_EDIT_ADMIN_TIME: 'int|true|default=0|comment=管理员最近修改的时间', JOIN_EDIT_ADMIN_STATUS: 'int|false|comment=最近管理员修改为的状态 ', JOIN_IS_ADMIN: 'int|true|default=0|comment=是否管理员添加 0/1', JOIN_CODE: 'string|true|comment=核验码15位', JOIN_IS_CHECKIN: 'int|true|default=0|comment=是否签到 0/1 ', JOIN_USER_ID: 'string|true|comment=用户ID', JOIN_MEET_ID: 'string|true|comment=预约PK', JOIN_MEET_TITLE: 'string|true|comment=项目', JOIN_MEET_DAY: 'string|true|comment=日期', JOIN_MEET_TIME_START: 'string|true|comment=时段开始', JOIN_MEET_TIME_END: 'string|true|comment=时段结束', JOIN_MEET_TIME_MARK: 'string|true|comment=时段标识', JOIN_START_TIME: 'int|true|comment=开始时间戳', JOIN_FORMS: 'array|true|default=[]|comment=表单', /* title: mark: type: val: */ JOIN_STATUS: 'int|true|default=1|comment=状态 1=预约成功,10=已取消, 99=系统取消', JOIN_REASON: 'string|false|comment=审核拒绝或者取消理由', JOIN_ADD_TIME: 'int|true', JOIN_EDIT_TIME: 'int|true', JOIN_ADD_IP: 'string|false', JOIN_EDIT_IP: 'string|false', }; // 字段前缀 JoinModel.FIELD_PREFIX = "JOIN_"; /** * 状态 1=预约成功,10=已取消, 99=后台取消 */ JoinModel.STATUS = { SUCC: 1, CANCEL: 10, ADMIN_CANCEL: 99 }; JoinModel.STATUS_DESC = { SUCC: '预约成功', CANCEL: '已取消', ADMIN_CANCEL: '系统取消', }; module.exports = JoinModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/meet_model.js ================================================ /** * Notes: 预约实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-12-07 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class MeetModel extends BaseProjectModel { } // 集合名 MeetModel.CL = BaseProjectModel.C('meet'); MeetModel.DB_STRUCTURE = { _pid: 'string|true', MEET_ID: 'string|true', MEET_ADMIN_ID: 'string|true|comment=添加的管理员', MEET_TITLE: 'string|true|comment=标题', MEET_CONTENT: 'array|true|default=[]|comment=详细介绍', MEET_DAYS: 'array|true|default=[]|comment=最近一次修改保存的可用日期', MEET_TYPE_ID: 'string|true|comment=分类编号', MEET_TYPE_NAME: 'string|true|comment=分类冗余', MEET_IS_SHOW_LIMIT: 'int|true|default=1|comment=是否显示可预约人数', MEET_STYLE_SET: 'object|true|default={}|comment=样式设置', MEET_FORM_SET: 'array|true|default=[]|comment=表单字段设置', MEET_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中,9=停止预约,10=已关闭', MEET_ORDER: 'int|true|default=9999', MEET_VOUCH: 'int|true|default=0', MEET_QR: 'string|false', MEET_ADD_TIME: 'int|true', MEET_EDIT_TIME: 'int|true', MEET_ADD_IP: 'string|false', MEET_EDIT_IP: 'string|false', }; // 字段前缀 MeetModel.FIELD_PREFIX = "MEET_"; /** * 状态 0=未启用,1=使用中,9=停止预约,10=已关闭 */ MeetModel.STATUS = { UNUSE: 0, COMM: 1, OVER: 9, CLOSE: 10 }; MeetModel.STATUS_DESC = { UNUSE: '未启用', COMM: '使用中', OVER: '停止预约(可见)', CLOSE: '已关闭(不可见)' }; module.exports = MeetModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/news_model.js ================================================ /** * Notes: 资讯实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-10-28 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class NewsModel extends BaseProjectModel { } // 集合名 NewsModel.CL = BaseProjectModel.C('news'); NewsModel.DB_STRUCTURE = { _pid: 'string|true', NEWS_ID: 'string|true', NEWS_TITLE: 'string|false|comment=标题', NEWS_DESC: 'string|false|comment=描述', NEWS_STATUS: 'int|true|default=1|comment=状态 0/1', NEWS_CATE_ID: 'string|true|comment=分类编号', NEWS_CATE_NAME: 'string|true|comment=分类冗余', NEWS_ORDER: 'int|true|default=9999', NEWS_VOUCH: 'int|true|default=0', NEWS_CONTENT: 'array|true|default=[]|comment=内容', NEWS_QR: 'string|false', NEWS_VIEW_CNT: 'int|true|default=0|comment=访问次数', NEWS_PIC: 'array|false|default=[]|comment=封面图 [cloudId1,cloudId2,cloudId3...]', NEWS_FORMS: 'array|true|default=[]', NEWS_OBJ: 'object|true|default={}', NEWS_ADD_TIME: 'int|true', NEWS_EDIT_TIME: 'int|true', NEWS_ADD_IP: 'string|false', NEWS_EDIT_IP: 'string|false', }; // 字段前缀 NewsModel.FIELD_PREFIX = "NEWS_"; module.exports = NewsModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/product_model.js ================================================ /** * Notes: 套系实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-08 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class ProductModel extends BaseProjectModel { } // 集合名 ProductModel.CL = BaseProjectModel.C('product'); ProductModel.DB_STRUCTURE = { _pid: 'string|true', PRODUCT_ID: 'string|true', PRODUCT_TITLE: 'string|true|comment=标题', PRODUCT_STATUS: 'int|true|default=1|comment=状态 0=未启用,1=使用中', PRODUCT_CATE_ID: 'string|true|default=0|comment=分类', PRODUCT_CATE_NAME: 'string|false|comment=分类冗余', PRODUCT_ORDER: 'int|true|default=9999', PRODUCT_VOUCH: 'int|true|default=0', PRODUCT_FORMS: 'array|true|default=[]', PRODUCT_OBJ: 'object|true|default={}', PRODUCT_QR: 'string|false', PRODUCT_VIEW_CNT: 'int|true|default=0', PRODUCT_ADD_TIME: 'int|true', PRODUCT_EDIT_TIME: 'int|true', PRODUCT_ADD_IP: 'string|false', PRODUCT_EDIT_IP: 'string|false', }; // 字段前缀 ProductModel.FIELD_PREFIX = "PRODUCT_"; /** * 状态 0=未启用,1=使用中 */ ProductModel.STATUS = { UNUSE: 0, COMM: 1 }; module.exports = ProductModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/model/user_model.js ================================================ /** * Notes: 用户实体 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-10-14 19:20:00 */ const BaseProjectModel = require('./base_project_model.js'); class UserModel extends BaseProjectModel { } // 集合名 UserModel.CL = BaseProjectModel.C('user'); UserModel.DB_STRUCTURE = { _pid: 'string|true', USER_ID: 'string|true', USER_MINI_OPENID: 'string|true|comment=小程序openid', USER_STATUS: 'int|true|default=1|comment=状态 0=待审核,1=正常,8=审核未过,9=禁用', USER_CHECK_REASON: 'string|false|comment=审核未过的理由', USER_NAME: 'string|false|comment=用户昵称', USER_MOBILE: 'string|false|comment=联系电话', USER_FORMS: 'array|true|default=[]', USER_OBJ: 'object|true|default={}', USER_LOGIN_CNT: 'int|true|default=0|comment=登陆次数', USER_LOGIN_TIME: 'int|false|comment=最近登录时间', USER_ADD_TIME: 'int|true', USER_ADD_IP: 'string|false', USER_EDIT_TIME: 'int|true', USER_EDIT_IP: 'string|false', } // 字段前缀 UserModel.FIELD_PREFIX = "USER_"; /** * 状态 0=待审核,1=正常,2=审核未过,9=禁用 */ UserModel.STATUS = { UNUSE: 0, COMM: 1, UNCHECK: 8, FORBID: 9 }; UserModel.STATUS_DESC = { UNUSE: '待审核', COMM: '正常', UNCHECK: '未通过审核', FORBID: '禁用' }; module.exports = UserModel; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/public/constants.js ================================================ module.exports = { // 首页推荐 SETUP_HOME_VOUCH_KEY : 'SETUP_HOME_VOUCH_KEY', } ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/public/project_config.js ================================================ module.exports = { // ## 缓存相关 CACHE_CALENDAR_TIME: 60 * 30, //日历缓存 } ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/public/route.js ================================================ /** * Notes: 路由配置文件 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * User: CC * Date: 2020-10-14 07:00:00 */ module.exports = { 'test/test': 'test/test_controller@test', 'home/setup_get': 'home_controller@getSetup', 'passport/login': 'passport_controller@login', 'passport/phone': 'passport_controller@getPhone', 'passport/my_detail': 'passport_controller@getMyDetail', 'passport/register': 'passport_controller@register', 'passport/edit_base': 'passport_controller@editBase', // 收藏 'fav/update': 'fav_controller@updateFav', 'fav/del': 'fav_controller@delFav', 'fav/is_fav': 'fav_controller@isFav', 'fav/my_list': 'fav_controller@getMyFavList', 'admin/home': 'admin/admin_home_controller@adminHome', 'admin/clear_vouch': 'admin/admin_home_controller@clearVouchData', 'admin/login': 'admin/admin_mgr_controller@adminLogin', 'admin/mgr_list': 'admin/admin_mgr_controller@getMgrList', 'admin/mgr_insert': 'admin/admin_mgr_controller@insertMgr#demo', 'admin/mgr_del': 'admin/admin_mgr_controller@delMgr#demo', 'admin/mgr_detail': 'admin/admin_mgr_controller@getMgrDetail', 'admin/mgr_edit': 'admin/admin_mgr_controller@editMgr#demo', 'admin/mgr_status': 'admin/admin_mgr_controller@statusMgr#demo', 'admin/mgr_pwd': 'admin/admin_mgr_controller@pwdMgr#demo', 'admin/log_list': 'admin/admin_mgr_controller@getLogList', 'admin/log_clear': 'admin/admin_mgr_controller@clearLog#demo', 'admin/setup_set': 'admin/admin_setup_controller@setSetup#demo', 'admin/setup_set_content': 'admin/admin_setup_controller@setContentSetup#demo', 'admin/setup_qr': 'admin/admin_setup_controller@genMiniQr', // 用户 'admin/user_list': 'admin/admin_user_controller@getUserList', 'admin/user_detail': 'admin/admin_user_controller@getUserDetail', 'admin/user_del': 'admin/admin_user_controller@delUser#demo', 'admin/user_status': 'admin/admin_user_controller@statusUser#demo', 'admin/user_data_get': 'admin/admin_user_controller@userDataGet', 'admin/user_data_export': 'admin/admin_user_controller@userDataExport', 'admin/user_data_del': 'admin/admin_user_controller@userDataDel', // 内容 'home/list': 'home_controller@getHomeList', 'news/list': 'news_controller@getNewsList', 'news/view': 'news_controller@viewNews', 'admin/news_list': 'admin/admin_news_controller@getAdminNewsList', 'admin/news_insert': 'admin/admin_news_controller@insertNews#demo', 'admin/news_detail': 'admin/admin_news_controller@getNewsDetail', 'admin/news_edit': 'admin/admin_news_controller@editNews#demo', 'admin/news_update_forms': 'admin/admin_news_controller@updateNewsForms#demo', 'admin/news_update_pic': 'admin/admin_news_controller@updateNewsPic#demo', 'admin/news_update_content': 'admin/admin_news_controller@updateNewsContent#demo', 'admin/news_del': 'admin/admin_news_controller@delNews#demo', 'admin/news_sort': 'admin/admin_news_controller@sortNews#demo', 'admin/news_status': 'admin/admin_news_controller@statusNews#demo', 'admin/news_vouch': 'admin/admin_news_controller@vouchNews#demo', // 相册 'album/list': 'album_controller@getAlbumList', 'album/view': 'album_controller@viewAlbum', 'admin/album_list': 'admin/admin_album_controller@getAdminAlbumList', 'admin/album_insert': 'admin/admin_album_controller@insertAlbum#demo', 'admin/album_detail': 'admin/admin_album_controller@getAlbumDetail', 'admin/album_edit': 'admin/admin_album_controller@editAlbum#demo#demo', 'admin/album_update_forms': 'admin/admin_album_controller@updateAlbumForms#demo', 'admin/album_del': 'admin/admin_album_controller@delAlbum#demo', 'admin/album_sort': 'admin/admin_album_controller@sortAlbum#demo', 'admin/album_vouch': 'admin/admin_album_controller@vouchAlbum#demo', 'admin/album_status': 'admin/admin_album_controller@statusAlbum#demo', // 产品 'product/list': 'product_controller@getProductList', 'product/view': 'product_controller@viewProduct', 'admin/product_list': 'admin/admin_product_controller@getAdminProductList', 'admin/product_insert': 'admin/admin_product_controller@insertProduct#demo', 'admin/product_detail': 'admin/admin_product_controller@getProductDetail', 'admin/product_edit': 'admin/admin_product_controller@editProduct#demo', 'admin/product_update_forms': 'admin/admin_product_controller@updateProductForms#demo', 'admin/product_del': 'admin/admin_product_controller@delProduct#demo', 'admin/product_sort': 'admin/admin_product_controller@sortProduct#demo', 'admin/product_vouch': 'admin/admin_product_controller@vouchProduct#demo', 'admin/product_status': 'admin/admin_product_controller@statusProduct#demo', // 预约 'meet/list': 'meet_controller@getMeetList', 'meet/list_by_day': 'meet_controller@getMeetListByDay', 'meet/list_has_day': 'meet_controller@getHasDaysFromDay', 'meet/view': 'meet_controller@viewMeet', 'meet/detail_for_join': 'meet_controller@detailForJoin', 'meet/before_join': 'meet_controller@beforeJoin', 'meet/join': 'meet_controller@join', 'meet/my_join_list': 'meet_controller@getMyJoinList', 'meet/my_join_cancel': 'meet_controller@cancelMyJoin', 'meet/my_join_detail': 'meet_controller@getMyJoinDetail', 'meet/my_join_someday': 'meet_controller@getMyJoinSomeday', 'meet/my_join_checkin': 'meet_controller@userSelfCheckin', 'admin/meet_list': 'admin/admin_meet_controller@getAdminMeetList', 'admin/meet_join_list': 'admin/admin_meet_controller@getJoinList', 'admin/join_status': 'admin/admin_meet_controller@statusJoin#demo', 'admin/join_del': 'admin/admin_meet_controller@delJoin#demo', 'admin/meet_insert': 'admin/admin_meet_controller@insertMeet#demo', 'admin/meet_detail': 'admin/admin_meet_controller@getMeetDetail', 'admin/meet_edit': 'admin/admin_meet_controller@editMeet#demo', 'admin/meet_del': 'admin/admin_meet_controller@delMeet#demo', 'admin/meet_update_content': 'admin/admin_meet_controller@updateMeetContent#demo', 'admin/meet_update_style': 'admin/admin_meet_controller@updateMeetStyleSet#demo', 'admin/meet_sort': 'admin/admin_meet_controller@sortMeet#demo', 'admin/meet_vouch': 'admin/admin_meet_controller@vouchMeet#demo', 'admin/meet_status': 'admin/admin_meet_controller@statusMeet#demo', 'admin/meet_cancel_time_join': 'admin/admin_meet_controller@cancelJoinByTimeMark#demo', 'admin/join_scan': 'admin/admin_meet_controller@scanJoin', 'admin/join_checkin': 'admin/admin_meet_controller@checkinJoin', 'admin/self_checkin_qr': 'admin/admin_meet_controller@genSelfCheckinQr', 'admin/meet_day_list': 'admin/admin_meet_controller@getDayList', 'admin/meet_temp_insert': 'admin/admin_meet_controller@insertMeetTemp#demo', 'admin/meet_temp_list': 'admin/admin_meet_controller@getMeetTempList', 'admin/meet_temp_del': 'admin/admin_meet_controller@delMeetTemp#demo', 'admin/meet_temp_edit': 'admin/admin_meet_controller@editMeetTemp#demo', 'admin/join_data_get': 'admin/admin_meet_controller@joinDataGet', 'admin/join_data_export': 'admin/admin_meet_controller@joinDataExport', 'admin/join_data_del': 'admin/admin_meet_controller@joinDataDel', } ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_album_service.js ================================================ /** * Notes: 相册后台管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const util = require('../../../../framework/utils/util.js'); const cloudUtil = require('../../../../framework/cloud/cloud_util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const AlbumModel = require('../../model/album_model.js'); const AdminHomeService = require('../admin/admin_home_service.js'); class AdminAlbumService extends BaseProjectAdminService { /** 推荐首页SETUP */ async vouchAlbumSetup(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**添加 */ async insertAlbum({ title, cateId, cateName, order, forms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除数据 */ async delAlbum(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**获取信息 */ async getAlbumDetail(id) { let fields = '*'; let where = { _id: id } let album = await AlbumModel.getOne(where, fields); if (!album) return null; return album; } // 更新forms信息 async updateAlbumForms({ id, hasImageForms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**更新数据 */ async editAlbum({ id, title, cateId, // 二级分类 cateName, order, forms, }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**取得分页列表 */ async getAdminAlbumList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'ALBUM_ORDER': 'asc', 'ALBUM_ADD_TIME': 'desc' }; let fields = 'ALBUM_TITLE,ALBUM_CATE_ID,ALBUM_CATE_NAME,ALBUM_EDIT_TIME,ALBUM_ADD_TIME,ALBUM_ORDER,ALBUM_STATUS,ALBUM_VOUCH,ALBUM_QR,ALBUM_OBJ'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; if (util.isDefined(search) && search) { where.or = [ { ALBUM_TITLE: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'cateId': { where.and.ALBUM_CATE_ID = String(sortVal); break; } case 'status': { where.and.ALBUM_STATUS = Number(sortVal); break; } case 'vouch': { where.and.ALBUM_VOUCH = 1; break; } case 'top': { where.and.ALBUM_ORDER = 0; break; } case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'ALBUM_ADD_TIME'); break; } } } return await AlbumModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /**修改状态 */ async statusAlbum(id, status) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**置顶与排序设定 */ async sortAlbum(id, sort) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**首页设定 */ async vouchAlbum(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } } module.exports = AdminAlbumService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_home_service.js ================================================ /** * Notes: 后台HOME/登录模块 * Date: 2021-06-15 07:48:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const UserModel = require('../../model/user_model.js'); const MeetModel = require('../../model/meet_model.js'); const NewsModel = require('../../model/news_model.js'); const ProductModel = require('../../model/product_model.js'); const AlbumModel = require('../../model/album_model.js'); const constants = require('../../public/constants.js'); const setupUtil = require('../../../../framework/utils/setup/setup_util.js'); class AdminHomeService extends BaseProjectAdminService { /** * 首页数据归集 */ async adminHome() { let where = {}; let userCnt = await UserModel.count(where); let newsCnt = await NewsModel.count(where); let meetCnt = await MeetModel.count(where); let productCnt = await ProductModel.count(where); let albumCnt = await AlbumModel.count(where); return [ { title: '用户数', cnt: userCnt }, { title: '资讯数', cnt: newsCnt }, { title: '预约项目', cnt: meetCnt }, { title: '景点数', cnt: productCnt }, { title: '攻略数', cnt: albumCnt }, ] } // 用户数据清理 async clearUserData(userId) { } //##################首页推荐 // 首页推荐清理 async clearVouchData() { await setupUtil.remove(constants.SETUP_HOME_VOUCH_KEY); NewsModel.edit({}, { NEWS_VOUCH: 0 }); MeetModel.edit({}, { MEET_VOUCH: 0 }); AlbumModel.edit({}, { ALBUM_VOUCH: 0 }); ProductModel.edit({}, { PRODUCT_VOUCH: 0 }); } /**添加首页推荐 */ async updateHomeVouch(node) { if (node.ext) node.ext = '#' + node.ext; let key = constants.SETUP_HOME_VOUCH_KEY; let list = await setupUtil.get(key); if (!list || !Array.isArray(list)) list = []; // 重复性判断 for (let k = 0; k < list.length; k++) { if (list[k].id == node.id) { // 已存在 list[k] = node; return await setupUtil.set(key, list, 'vouch'); } } // 赋值 let data = node; list.unshift(data); await setupUtil.set(key, list, 'vouch'); } /**删除推荐数据 */ async delHomeVouch(id) { let key = constants.SETUP_HOME_VOUCH_KEY; let list = await setupUtil.get(key); if (!list || !Array.isArray(list)) return; let newList = []; for (let k = 0; k < list.length; k++) { if (list[k].id != id) { newList.push(list[k]); } } return await setupUtil.set(key, newList, 'vouch'); } } module.exports = AdminHomeService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_meet_service.js ================================================ /** * Notes: 预约后台管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-08 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const MeetService = require('../meet_service.js'); const AdminHomeService = require('../admin/admin_home_service.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const setupUtil = require('../../../../framework/utils/setup/setup_util.js'); const util = require('../../../../framework/utils/util.js'); const cloudUtil = require('../../../../framework/cloud/cloud_util.js'); const cloudBase = require('../../../../framework/cloud/cloud_base.js'); const MeetModel = require('../../model/meet_model.js'); const JoinModel = require('../../model/join_model.js'); const DayModel = require('../../model/day_model.js'); const exportUtil = require('../../../../framework/utils/export_util.js'); const SETUP_MEET_TEMP_KEY = 'SETUP_MEET_TEMP'; // 导出报名数据KEY const EXPORT_JOIN_DATA_KEY = 'EXPORT_JOIN_DATA'; class AdminMeetService extends BaseProjectAdminService { /** 推荐首页SETUP */ async vouchMeetSetup(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 预约数据列表 */ async getDayList(meetId, start, end) { let where = { DAY_MEET_ID: meetId, day: ['between', start, end] } let orderBy = { day: 'asc' } return await DayModel.getAllBig(where, 'day,times,dayDesc', orderBy); } // 按项目统计人数 async statJoinCntByMeet(meetId) { let today = timeUtil.time('Y-M-D'); let where = { day: ['>=', today], DAY_MEET_ID: meetId } let meetService = new MeetService(); let list = await DayModel.getAllBig(where, 'DAY_MEET_ID,times', {}, 1000); for (let k = 0; k < list.length; k++) { let meetId = list[k].DAY_MEET_ID; let times = list[k].times; for (let j in times) { let timeMark = times[j].mark; meetService.statJoinCnt(meetId, timeMark); } } } /** 自助签到码 */ async genSelfCheckinQr(page, timeMark) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 管理员按钮核销 */ async checkinJoin(joinId, flag) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 管理员扫码核销 */ async scanJoin(meetId, code) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** * 判断本日是否有预约记录 * @param {*} daySet daysSet的节点 */ checkHasJoinCnt(times) { if (!times) return false; for (let k = 0; k < times.length; k++) { if (times[k].stat.succCnt) return true; } return false; } // 判断含有预约的日期 getCanModifyDaysSet(daysSet) { let now = timeUtil.time('Y-M-D'); for (let k = 0; k < daysSet.length; k++) { if (daysSet[k].day < now) continue; daysSet[k].hasJoin = this.checkHasJoinCnt(daysSet[k].times); } return daysSet; } /** 取消某个时间段的所有预约记录 */ async cancelJoinByTimeMark(admin, meetId, timeMark, reason) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**添加 */ async insertMeet(adminId, { title, order, typeId, typeName, daysSet, isShowLimit, formSet, }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除数据 */ async delMeet(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**获取信息 */ async getMeetDetail(id) { let fields = '*'; let where = { _id: id } let meet = await MeetModel.getOne(where, fields); if (!meet) return null; let meetService = new MeetService(); meet.MEET_DAYS_SET = await meetService.getDaysSet(id, timeUtil.time('Y-M-D')); //今天及以后 return meet; } /** * 更新富文本详细的内容及图片信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateMeetContent({ id, content // 富文本数组 }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** * 更新封面内容及图片信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateMeetStyleSet({ meetId, styleSet }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 更新日期设置 */ async _editDays(meetId, nowDay, daysSetData) { // 删除指定日期之后的记录(含) this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**更新数据 */ async editMeet({ id, title, typeId, typeName, order, daysSet, isShowLimit, formSet }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**预约名单分页列表 */ async getJoinList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 meetId, mark, page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'JOIN_EDIT_TIME': 'desc' }; let fields = 'JOIN_IS_CHECKIN,JOIN_CODE,JOIN_ID,JOIN_REASON,JOIN_USER_ID,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_MEET_TIME_MARK,JOIN_FORMS,JOIN_STATUS,JOIN_EDIT_TIME'; let where = { JOIN_MEET_ID: meetId, JOIN_MEET_TIME_MARK: mark }; if (util.isDefined(search) && search) { where['JOIN_FORMS.val'] = { $regex: '.*' + search, $options: 'i' }; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'status': // 按类型 sortVal = Number(sortVal); if (sortVal == 1099) //取消的2种 where.JOIN_STATUS = ['in', [10, 99]] else where.JOIN_STATUS = Number(sortVal); break; case 'checkin': // 签到 where.JOIN_STATUS = JoinModel.STATUS.SUCC; if (sortVal == 1) { where.JOIN_IS_CHECKIN = 1; } else { where.JOIN_IS_CHECKIN = 0; } break; } } return await JoinModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /**预约项目分页列表 */ async getAdminMeetList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'MEET_ORDER': 'asc', 'MEET_ADD_TIME': 'desc' }; let fields = 'MEET_TYPE,MEET_TYPE_NAME,MEET_TITLE,MEET_STATUS,MEET_DAYS,MEET_ADD_TIME,MEET_EDIT_TIME,MEET_ORDER,MEET_VOUCH,MEET_QR'; let where = {}; if (util.isDefined(search) && search) { where.MEET_TITLE = { $regex: '.*' + search, $options: 'i' }; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'status': // 按类型 where.MEET_STATUS = Number(sortVal); break; case 'typeId': // 按类型 where.MEET_TYPE_ID = sortVal; break; case 'sort': // 排序 if (sortVal == 'view') { orderBy = { 'MEET_VIEW_CNT': 'desc', 'MEET_ADD_TIME': 'desc' }; } break; } } return await MeetModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /** 删除 */ async delJoin(joinId) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**修改报名状态 * 特殊约定 99=>正常取消 */ async statusJoin(admin, joinId, status, reason = '') { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**修改项目状态 */ async statusMeet(id, status) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**置顶排序设定 */ async sortMeet(id, sort) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**首页设定 */ async vouchMeet(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } //##################模板 /**添加模板 */ async insertMeetTemp({ name, times, }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**更新数据 */ async editMeetTemp({ id, limit, isLimit }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除数据 */ async delMeetTemp(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**模板列表 */ async getMeetTempList() { let list = await setupUtil.get(SETUP_MEET_TEMP_KEY); if (!list || !Array.isArray(list)) list = []; return list; } // #####################导出报名数据 /**获取报名数据 */ async getJoinDataURL() { return await exportUtil.getExportDataURL(EXPORT_JOIN_DATA_KEY); } /**删除报名数据 */ async deleteJoinDataExcel() { return await exportUtil.deleteDataExcel(EXPORT_JOIN_DATA_KEY); } /**导出报名数据 */ async exportJoinDataExcel({ meetId, startDay, endDay, status }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } } module.exports = AdminMeetService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_mgr_service.js ================================================ /** * Notes: 管理员管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const util = require('../../../../framework/utils/util.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const AdminModel = require('../../../../framework/platform/model/admin_model.js'); const LogModel = require('../../../../framework/platform/model/log_model.js'); const md5Lib = require('../../../../framework/lib/md5_lib.js'); class AdminMgrService extends BaseProjectAdminService { //**管理员登录 */ async adminLogin(name, password) { // 判断是否存在 let where = { ADMIN_STATUS: 1, ADMIN_NAME: name, ADMIN_PASSWORD: md5Lib.md5(password) } let fields = 'ADMIN_ID,ADMIN_NAME,ADMIN_DESC,ADMIN_TYPE,ADMIN_LOGIN_TIME,ADMIN_LOGIN_CNT'; let admin = await AdminModel.getOne(where, fields); if (!admin) this.AppError('管理员不存在或者已停用'); let cnt = admin.ADMIN_LOGIN_CNT; // 生成token let token = dataUtil.genRandomString(32); let tokenTime = timeUtil.time(); let data = { ADMIN_TOKEN: token, ADMIN_TOKEN_TIME: tokenTime, ADMIN_LOGIN_TIME: timeUtil.time(), ADMIN_LOGIN_CNT: cnt + 1 } await AdminModel.edit(where, data); let type = admin.ADMIN_TYPE; let last = (!admin.ADMIN_LOGIN_TIME) ? '尚未登录' : timeUtil.timestamp2Time(admin.ADMIN_LOGIN_TIME); // 写日志 this.insertLog('登录了系统', admin, LogModel.TYPE.SYS); return { token, name: admin.ADMIN_NAME, type, last, cnt } } async clearLog() { let where = {} await LogModel.del(where); } /** 取得日志分页列表 */ async getLogList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, oldTotal = 0 }) { orderBy = orderBy || { LOG_ADD_TIME: 'desc' }; let fields = '*'; let where = {}; if (util.isDefined(search) && search) { where.or = [{ LOG_CONTENT: ['like', search] }, { LOG_ADMIN_DESC: ['like', search] }, { LOG_ADMIN_NAME: ['like', search] }]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'type': // 按类型 where.LOG_TYPE = Number(sortVal); break; } } let result = await LogModel.getList(where, fields, orderBy, page, size, true, oldTotal); return result; } /** 获取所有管理员 */ async getMgrList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = { ADMIN_ADD_TIME: 'desc' } let fields = 'ADMIN_NAME,ADMIN_STATUS,ADMIN_PHONE,ADMIN_TYPE,ADMIN_LOGIN_CNT,ADMIN_LOGIN_TIME,ADMIN_DESC,ADMIN_EDIT_TIME,ADMIN_EDIT_IP'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; if (util.isDefined(search) && search) { where.or = [{ ADMIN_NAME: ['like', search] }, { ADMIN_PHONE: ['like', search] }, { ADMIN_DESC: ['like', search] } ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'status': // 按类型 where.and.ADMIN_STATUS = Number(sortVal); break; case 'type': // 按类型 where.and.ADMIN_TYPE = Number(sortVal); break; } } return await AdminModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /** 删除管理员 */ async delMgr(id, myAdminId) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 添加新的管理员 */ async insertMgr({ name, desc, phone, password }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 修改状态 */ async statusMgr(id, status, myAdminId) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 获取管理员信息 */ async getMgrDetail(id) { let fields = '*'; let where = { _id: id } let mgr = await AdminModel.getOne(where, fields); if (!mgr) return null; return mgr; } /** 修改管理员 */ async editMgr(id, { name, desc, phone, password }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** 修改自身密码 */ async pwdtMgr(adminId, oldPassword, password) { let where = { _id: adminId, ADMIN_PASSWORD: md5Lib.md5(oldPassword), } let admin = await AdminModel.getOne(where); if (!admin) this.AppError('旧密码错误'); let data = { ADMIN_PASSWORD: md5Lib.md5(password), } return await AdminModel.edit(adminId, data); } } module.exports = AdminMgrService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_news_service.js ================================================ /** * Notes: 资讯后台管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const AdminHomeService = require('../admin/admin_home_service.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const util = require('../../../../framework/utils/util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const cloudUtil = require('../../../../framework/cloud/cloud_util.js'); const NewsModel = require('../../model/news_model.js'); class AdminNewsService extends BaseProjectAdminService { /** 推荐首页SETUP */ async vouchNewsSetup(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**添加资讯 */ async insertNews({ title, cateId, //分类 cateName, order, desc = '', forms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除资讯数据 */ async delNews(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**获取资讯信息 */ async getNewsDetail(id) { let fields = '*'; let where = { _id: id } let news = await NewsModel.getOne(where, fields); if (!news) return null; return news; } // 更新forms信息 async updateNewsForms({ id, hasImageForms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** * 更新富文本详细的内容及图片信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateNewsContent({ id, content // 富文本数组 }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /** * 更新资讯图片信息 * @returns 返回 urls数组 [url1, url2, url3, ...] */ async updateNewsPic({ id, imgList // 图片数组 }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**更新资讯数据 */ async editNews({ id, title, cateId, //分类 cateName, order, desc = '', forms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**取得资讯分页列表 */ async getAdminNewsList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'NEWS_ORDER': 'asc', 'NEWS_ADD_TIME': 'desc' }; let fields = 'NEWS_TITLE,NEWS_DESC,NEWS_CATE_ID,NEWS_CATE_NAME,NEWS_EDIT_TIME,NEWS_ADD_TIME,NEWS_ORDER,NEWS_STATUS,NEWS_CATE2_NAME,NEWS_VOUCH,NEWS_QR,NEWS_OBJ'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; if (util.isDefined(search) && search) { where.or = [ { NEWS_TITLE: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'cateId': { where.and.NEWS_CATE_ID = String(sortVal); break; } case 'status': { where.and.NEWS_STATUS = Number(sortVal); break; } case 'vouch': { where.and.NEWS_VOUCH = 1; break; } case 'top': { where.and.NEWS_ORDER = 0; break; } case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'NEWS_ADD_TIME'); break; } } } return await NewsModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /**修改资讯状态 */ async statusNews(id, status) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**置顶与排序设定 */ async sortNews(id, sort) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**首页设定 */ async vouchNews(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } } module.exports = AdminNewsService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_product_service.js ================================================ /** * Notes: 产品后台管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-08 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const AdminHomeService = require('../admin/admin_home_service.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const util = require('../../../../framework/utils/util.js'); const cloudUtil = require('../../../../framework/cloud/cloud_util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const ProductModel = require('../../model/product_model.js'); class AdminProductService extends BaseProjectAdminService { /** 推荐首页SETUP */ async vouchProductSetup(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**添加 */ async insertProduct({ title, cateId, cateName, order, forms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除数据 */ async delProduct(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**获取信息 */ async getProductDetail(id) { let fields = '*'; let where = { _id: id } let product = await ProductModel.getOne(where, fields); if (!product) return null; return product; } // 更新forms信息 async updateProductForms({ id, hasImageForms }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**更新数据 */ async editProduct({ id, title, cateId, // 二级分类 cateName, order, forms, }) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**取得分页列表 */ async getAdminProductList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'PRODUCT_ORDER': 'asc', 'PRODUCT_ADD_TIME': 'desc' }; let fields = 'PRODUCT_TITLE,PRODUCT_CATE_ID,PRODUCT_CATE_NAME,PRODUCT_EDIT_TIME,PRODUCT_ADD_TIME,PRODUCT_ORDER,PRODUCT_STATUS,PRODUCT_VOUCH,,PRODUCT_QR,PRODUCT_OBJ'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; if (util.isDefined(search) && search) { where.or = [ { PRODUCT_TITLE: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'cateId': { where.and.PRODUCT_CATE_ID = String(sortVal); break; } case 'status': { where.and.PRODUCT_STATUS = Number(sortVal); break } case 'vouch': { where.and.PRODUCT_VOUCH = 1; break; } case 'top': { where.and.PRODUCT_ORDER = 0; break; } case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'PRODUCT_ADD_TIME'); break; } } } return await ProductModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } /**修改状态 */ async statusProduct(id, status) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**置顶与排序设定 */ async sortProduct(id, sort) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**首页设定 */ async vouchProduct(id, vouch) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } } module.exports = AdminProductService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_setup_service.js ================================================ /** * Notes: 设置管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-07-11 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const cloudBase = require('../../../../framework/cloud/cloud_base.js'); const cloudUtil = require('../../../../framework/cloud/cloud_util.js'); const setupUtil = require('../../../../framework/utils/setup/setup_util.js'); const config = require('../../../../config/config.js'); const md5Lib = require('../../../../framework/lib/md5_lib.js'); class AdminSetupService extends BaseProjectAdminService { // 通用setup async setSetup(key, val, type = '') { await setupUtil.set(key, val, type); } /** 小程序码 */ async genMiniQr(page, sc = 'qr') { //生成小程序qr buffer let cloud = cloudBase.getCloud(); if (page.startsWith('/')) page = page.substring(1); console.log('page=' + page, ', scene=' + sc); let color = ['0', '0', '0']; if (config.TEST_MODE == true && page.includes('default/index/default_index')) { // 首页且测试模式 let rd = PID; rd = rd.match(/\d+/g).join(''); rd = Number(rd) % 20; let colorArr = []; colorArr.push('0 238 238'); colorArr.push('47 79 79'); colorArr.push('105 139 105'); colorArr.push('119 136 153'); colorArr.push('100 149 237'); colorArr.push('0 205 0'); colorArr.push('176 196 222'); colorArr.push('205 190 112'); colorArr.push('255 20 147'); colorArr.push('139 90 0'); colorArr.push('205 16 118'); colorArr.push('255 174 185'); colorArr.push('108 166 205'); colorArr.push('0 0 139'); colorArr.push('130 130 130'); colorArr.push('205 150 205'); colorArr.push('205 102 0'); colorArr.push('139 101 8'); colorArr.push('72 209 204'); colorArr.push('176 196 222'); color = colorArr[rd].split(' '); } let result = await cloud.openapi.wxacode.getUnlimited({ scene: sc, width: 280, lineColor: { r: color[0], g: color[1], b: color[2], }, check_path: false, //env_version: 'trial', //release,trial,develop page }); let cloudPath = PID + '/' + 'setup/' + md5Lib.md5(page) + '.png'; let upload = await cloud.uploadFile({ cloudPath, fileContent: result.buffer, }); if (!upload || !upload.fileID) return; let ret = await cloudUtil.getTempFileURLOne(upload.fileID); return ret + '?rd=' + this._timestamp; } } module.exports = AdminSetupService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/admin_user_service.js ================================================ /** * Notes: 用户管理 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-01-22 07:48:00 */ const BaseProjectAdminService = require('./base_project_admin_service.js'); const util = require('../../../../framework/utils/util.js'); const exportUtil = require('../../../../framework/utils/export_util.js'); const timeUtil = require('../../../../framework/utils/time_util.js'); const dataUtil = require('../../../../framework/utils/data_util.js'); const UserModel = require('../../model/user_model.js'); const AdminHomeService = require('./admin_home_service.js'); // 导出用户数据KEY const EXPORT_USER_DATA_KEY = 'EXPORT_USER_DATA'; class AdminUserService extends BaseProjectAdminService { /** 获得某个用户信息 */ async getUser({ userId, fields = '*' }) { let where = { USER_MINI_OPENID: userId, } return await UserModel.getOne(where, fields); } /** 取得用户分页列表 */ async getUserList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 whereEx, //附加查询条件 page, size, oldTotal = 0 }) { orderBy = orderBy || { USER_ADD_TIME: 'desc' }; let fields = '*'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; if (util.isDefined(search) && search) { where.or = [{ USER_NAME: ['like', search] }, { USER_MOBILE: ['like', search] }, { USER_MEMO: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'status': where.and.USER_STATUS = Number(sortVal); break; case 'sort': // 排序 if (sortVal == 'newdesc') { //最新 orderBy = { 'USER_ADD_TIME': 'desc' }; } if (sortVal == 'newasc') { orderBy = { 'USER_ADD_TIME': 'asc' }; } } } let result = await UserModel.getList(where, fields, orderBy, page, size, true, oldTotal, false); // 为导出增加一个参数condition result.condition = encodeURIComponent(JSON.stringify(where)); return result; } async statusUser(id, status, reason) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } /**删除用户 */ async delUser(id) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } // #####################导出用户数据 /**获取用户数据 */ async getUserDataURL() { return await exportUtil.getExportDataURL(EXPORT_USER_DATA_KEY); } /**删除用户数据 */ async deleteUserDataExcel() { return await exportUtil.deleteDataExcel(EXPORT_USER_DATA_KEY); } /**导出用户数据 */ async exportUserDataExcel(condition, fields) { this.AppError('该功能暂不开放,如有需要请加作者微信:cclinux0730'); } } module.exports = AdminUserService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/admin/base_project_admin_service.js ================================================ /** * Notes: 后台管理模块 基类 * Date: 2021-03-15 07:48:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseAdminService = require('../../../../framework/platform/service/base_admin_service.js'); ; const util = require('../../../../framework/utils/util.js'); const cloudBase = require('../../../../framework/cloud/cloud_base.js'); class BaseProjectAdminService extends BaseAdminService { getProjectId() { return util.getProjectId(); } async genDetailQr(type, id) { let cloud = cloudBase.getCloud(); let page = `projects/${this.getProjectId()}/pages/${type}/detail/${type}_detail`; console.log('page=', page); let result = await cloud.openapi.wxacode.getUnlimited({ scene: id, width: 280, check_path: false, //env_version: 'trial', //release,trial,develop page }); let cloudPath = `${this.getProjectId()}/${type}/${id}/qr.png`; console.log('cloudPath=', cloudPath); let upload = await cloud.uploadFile({ cloudPath, fileContent: result.buffer, }); if (!upload || !upload.fileID) return; return upload.fileID; } } module.exports = BaseProjectAdminService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/album_service.js ================================================ /** * Notes: 相册模块业务逻辑 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-07 07:48:00 */ const BaseProjectService = require('./base_project_service.js'); const util = require('../../../framework/utils/util.js'); const AlbumModel = require('../model/album_model.js'); class AlbumService extends BaseProjectService { /** 浏览资讯信息 */ async viewAlbum(id) { let fields = '*'; let where = { _id: id, ALBUM_STATUS: AlbumModel.STATUS.COMM } let album = await AlbumModel.getOne(where, fields); if (!album) return null; AlbumModel.inc(id, 'ALBUM_VIEW_CNT', 1); return album; } /** 取得分页列表 */ async getAlbumList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'ALBUM_ORDER': 'asc', 'ALBUM_ADD_TIME': 'desc' }; let fields = 'ALBUM_OBJ,ALBUM_VIEW_CNT,ALBUM_TITLE,ALBUM_CATE_ID,ALBUM_ADD_TIME,ALBUM_ORDER,ALBUM_STATUS,ALBUM_CATE_NAME'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; where.and.ALBUM_STATUS = AlbumModel.STATUS.COMM; // 状态 if (util.isDefined(search) && search) { where.or = [ { ALBUM_TITLE: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'cateId': { if (sortVal) where.and.ALBUM_CATE_ID = String(sortVal); break; } case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'ALBUM_ADD_TIME'); break; } } } return await AlbumModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } } module.exports = AlbumService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/base_project_service.js ================================================ /** * Notes: 业务基类 * Date: 2021-03-15 04:00:00 */ const dbUtil = require('../../../framework/database/db_util.js'); const util = require('../../../framework/utils/util.js'); const AdminModel = require('../../../framework/platform/model/admin_model.js'); const NewsModel = require('../model/news_model.js'); const MeetModel = require('../model/meet_model.js'); const AlbumModel = require('../model/album_model.js'); const ProductModel = require('../model/product_model.js'); const BaseService = require('../../../framework/platform/service/base_service.js'); class BaseProjectService extends BaseService { getProjectId() { return util.getProjectId(); } async initSetup() { let F = (c) => 'bx_' + c; const INSTALL_CL = 'setup_trip1'; const COLLECTIONS = ['setup', 'admin', 'day', 'join', 'log', 'meet', 'news', 'product', 'album', 'fav', 'user']; const CONST_PIC = '/images/cover.gif'; const NEWS_CATE = '1=本景区动态,2=美食,3=特产'; const MEET_TYPE = '1=景点预约,2=停车预约'; const ALBUM_CATE = '1=线路,2=吃喝,3=住宿,4=购物,5=其他'; const PRODUCT_CATE = '1=仙山贡水,2=伍家台,3=狮子关,4=其他景点'; if (await dbUtil.isExistCollection(F(INSTALL_CL))) { return; } console.log('### initSetup...'); let arr = COLLECTIONS; for (let k = 0; k < arr.length; k++) { if (!await dbUtil.isExistCollection(F(arr[k]))) { await dbUtil.createCollection(F(arr[k])); } } if (await dbUtil.isExistCollection(F('admin'))) { let adminCnt = await AdminModel.count({}); if (adminCnt == 0) { let data = {}; data.ADMIN_NAME = 'admin'; data.ADMIN_PASSWORD = 'e10adc3949ba59abbe56e057f20f883e'; data.ADMIN_DESC = '超管'; data.ADMIN_TYPE = 1; await AdminModel.insert(data); } } if (await dbUtil.isExistCollection(F('news'))) { let newsCnt = await NewsModel.count({}); if (newsCnt == 0) { let newsArr = NEWS_CATE.split(','); for (let j in newsArr) { let title = newsArr[j].split('=')[1]; let cateId = newsArr[j].split('=')[0]; let data = {}; data.NEWS_TITLE = title + '标题1'; data.NEWS_DESC = title + '简介1'; data.NEWS_CATE_ID = cateId; data.NEWS_CATE_NAME = title; data.NEWS_CONTENT = [{ type: 'text', val: title + '内容1' }]; data.NEWS_PIC = [CONST_PIC]; await NewsModel.insert(data); } } } if (await dbUtil.isExistCollection(F('meet'))) { let meetCnt = await MeetModel.count({}); if (meetCnt == 0) { let meetArr = MEET_TYPE.split(','); for (let j in meetArr) { let title = meetArr[j].split('=')[1]; let typeId = meetArr[j].split('=')[0]; let data = {}; data.MEET_TITLE = title + '标题1'; data.MEET_STYLE_SET = { desc: title + '简介1', pic: CONST_PIC }; data.MEET_ADMIN_ID = '1'; data.MEET_TYPE_ID = typeId; data.MEET_TYPE_NAME = title; data.MEET_CONTENT = [{ type: 'text', val: title + '内容1' }]; data.MEET_DAYS = []; data.MEET_FORM_SET = [ { type: 'text', title: '姓名', must: true }, { type: 'mobile', title: '手机', must: true } ]; await MeetModel.insert(data); } } } if (await dbUtil.isExistCollection(F('album'))) { let albumCnt = await AlbumModel.count({}); if (albumCnt == 0) { let albumArr = ALBUM_CATE.split(','); for (let j in albumArr) { let title = albumArr[j].split('=')[1]; let cateId = albumArr[j].split('=')[0]; let data = {}; data.ALBUM_TITLE = title + '标题1'; data.ALBUM_CATE_ID = cateId; data.ALBUM_CATE_NAME = title; data.ALBUM_OBJ = { cover: [CONST_PIC], detail: [{ type: 'text', val: title + '内容1' }] }; await AlbumModel.insert(data); } } } if (await dbUtil.isExistCollection(F('product'))) { let productCnt = await ProductModel.count({}); if (productCnt == 0) { let productArr = PRODUCT_CATE.split(','); for (let j in productArr) { let title = productArr[j].split('=')[1]; let cateId = productArr[j].split('=')[0]; let data = {}; data.PRODUCT_TITLE = title + '标题1'; data.PRODUCT_CATE_ID = cateId; data.PRODUCT_CATE_NAME = title; data.PRODUCT_OBJ = { cover: [CONST_PIC], price: 1999, origPrice: 999, adv: '产品亮点', album: [CONST_PIC] }; await ProductModel.insert(data); } } } if (!await dbUtil.isExistCollection(F(INSTALL_CL))) { await dbUtil.createCollection(F(INSTALL_CL)); } } } module.exports = BaseProjectService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/fav_service.js ================================================ /** * Notes: 收藏模块业务逻辑 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-05-24 07:48:00 */ const BaseProjectService = require('./base_project_service.js'); const util = require('../../../framework/utils/util.js'); const FavModel = require('../model/fav_model.js'); class FavService extends BaseProjectService { /** 是否收藏 */ async isFav(userId, oid) { let where = { FAV_OID: oid, FAV_USER_ID: userId } let isFav = await FavModel.count(where); return { isFav }; } /** * 更新某人收藏 * @param {*} userId * @param {*} oid * @param {*} cancelIfExist 已收藏的情况下是否取消 */ async updateFav(userId, oid, title, type, path, cancelIfExist = true) { let { isFav } = await this.isFav(userId, oid); if (isFav > 0) { if (cancelIfExist) { // 取消 await this.delFav(userId, oid); return { isFav: 0 }; } else return { isFav: 1 }; } // 保存 let data = {}; data.FAV_TITLE = title; data.FAV_OID = oid; data.FAV_TYPE = type; data.FAV_PATH = path; data.FAV_USER_ID = userId; await FavModel.insert(data); return { isFav: 1 }; } /** 删除收藏 */ async delFav(userId, oid) { let where = { FAV_OID: oid, FAV_USER_ID: userId } let effect = await FavModel.del(where); return { effect }; } /** 我的收藏列表 */ async getMyFavList(userId, { search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 page, size, isTotal = true, oldTotal = 0 }) { orderBy = orderBy || { 'FAV_ADD_TIME': 'desc' }; let fields = 'FAV_TITLE,FAV_ADD_TIME,FAV_OID,FAV_TYPE,FAV_PATH'; let where = {}; if (util.isDefined(search) && search) { where.FAV_TITLE = { $regex: '.*' + search, $options: 'i' }; } where.FAV_USER_ID = userId; return await FavModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } } module.exports = FavService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/home_service.js ================================================ /** * Notes: 全局/首页模块业务逻辑 * Date: 2021-03-15 04:00:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectService = require('./base_project_service.js'); const setupUtil = require('../../../framework/utils/setup/setup_util.js'); const constants = require('../public/constants.js'); const NewsModel = require('../model/news_model.js'); class HomeService extends BaseProjectService { async getSetup(key) { return await setupUtil.get(key); } /**首页列表 */ async getHomeList() { let list = await setupUtil.get(constants.SETUP_HOME_VOUCH_KEY); if (!list || !Array.isArray(list)) list = []; if (list.length == 0) { let orderBy = { 'NEWS_ORDER': 'asc', 'NEWS_ADD_TIME': 'desc' }; let fields = 'NEWS_PIC,NEWS_CATE_NAME,NEWS_TITLE,NEWS_DESC,NEWS_ADD_TIME'; let where = {}; where.NEWS_STATUS = 1; // 状态 let retList = await NewsModel.getAll(where, fields, orderBy, 10); for (let k = 0; k < retList.length; k++) { list.push({ type: 'news', ext: retList[k].NEWS_CATE_NAME, title: retList[k].NEWS_TITLE, id: retList[k]._id, desc: retList[k].NEWS_DESC, pic: retList[k].NEWS_PIC }) } } return list; } } module.exports = HomeService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/meet_service.js ================================================ /** * Notes: 预约模块业务逻辑 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2021-12-10 07:48:00 */ const BaseProjectService = require('./base_project_service.js'); const util = require('../../../framework/utils/util.js'); const MeetModel = require('../model/meet_model.js'); const JoinModel = require('../model/join_model.js'); const DayModel = require('../model/day_model.js'); const LogUtil = require('../../../framework/utils/log_util.js'); const timeUtil = require('../../../framework/utils/time_util.js'); const dataUtil = require('../../../framework/utils/data_util.js'); const projectConfig = require('../public/project_config.js'); const MEET_LOG_LEVEL = 'debug'; class MeetService extends BaseProjectService { constructor() { super(); this._log = new LogUtil(projectConfig.MEET_LOG_LEVEL); } /** * 抛出异常 * @param {*} msg * @param {*} code */ AppError(msg) { this._log.error(msg); super.AppError(msg); } _meetLog(meet, func = '', msg = '') { let str = ''; str = `[MEET=${meet.MEET_TITLE}][${func}] ${msg}`; this._log.debug(str); } /** 统一获取Meet(某天) */ async getMeetOneDay(meetId, day, where, fields = '*') { let meet = await MeetModel.getOne(where, fields); if (!meet) return meet; meet.MEET_DAYS_SET = await this.getDaysSet(meetId, day, day); return meet; } /** 获取日期设置 */ async getDaysSet(meetId, startDay, endDay = null) { let where = { DAY_MEET_ID: meetId } if (startDay && endDay && endDay == startDay) where.day = startDay; else if (startDay && endDay) where.day = ['between', startDay, endDay]; else if (!startDay && endDay) where.day = ['<=', endDay]; else if (startDay && !endDay) where.day = ['>=', startDay]; let orderBy = { 'day': 'asc' } let list = await DayModel.getAllBig(where, 'day,dayDesc,times', orderBy, 1000); for (let k = 0; k < list.length; k++) { delete list[k]._id; } return list; } // 按时段统计某时段报名情况 async statJoinCnt(meetId, timeMark) { let whereJoin = { JOIN_MEET_TIME_MARK: timeMark, JOIN_MEET_ID: meetId }; let ret = await JoinModel.groupCount(whereJoin, 'JOIN_STATUS'); let stat = { //统计数据 succCnt: ret['JOIN_STATUS_1'] || 0, //1=预约成功, cancelCnt: ret['JOIN_STATUS_10'] || 0, //10=已取消, adminCancelCnt: ret['JOIN_STATUS_99'] || 0, //99=后台取消 }; let whereDay = { DAY_MEET_ID: meetId, day: this.getDayByTimeMark(timeMark) }; let day = await DayModel.getOne(whereDay, 'times'); if (!day) return; let times = day.times; for (let j in times) { if (times[j].mark === timeMark) { let data = { ['times.' + j + '.stat']: stat } await DayModel.edit(whereDay, data); return; } } } // 预约前检测 async beforeJoin(userId, meetId, timeMark) { await this.checkMeetRules(userId, meetId, timeMark); } // 预约逻辑 async join(userId, meetId, timeMark, forms) { // 预约时段是否存在 let meetWhere = { _id: meetId }; let day = this.getDayByTimeMark(timeMark); let meet = await this.getMeetOneDay(meetId, day, meetWhere); if (!meet) { this.AppError('预约时段选择错误1,请重新选择'); } let daySet = this.getDaySetByTimeMark(meet, timeMark); if (!daySet) this.AppError('预约时段选择错误2,请重新选择'); let timeSet = this.getTimeSetByTimeMark(meet, timeMark); if (!timeSet) this.AppError('预约时段选择错误3,请重新选择'); // 规则校验 await this.checkMeetRules(userId, meetId, timeMark); let data = {}; data.JOIN_USER_ID = userId; data.JOIN_MEET_ID = meetId; data.JOIN_MEET_TITLE = meet.MEET_TITLE; data.JOIN_MEET_DAY = daySet.day; data.JOIN_MEET_TIME_START = timeSet.start; data.JOIN_MEET_TIME_END = timeSet.end; data.JOIN_MEET_TIME_MARK = timeMark; data.JOIN_START_TIME = timeUtil.time2Timestamp(daySet.day + ' ' + timeSet.start + ':00'); data.JOIN_FORMS = forms; data.JOIN_STATUS = JoinModel.STATUS.SUCC; data.JOIN_CODE = dataUtil.genRandomIntString(15); // 入库 let joinId = await JoinModel.insert(data); // 若有手机号码 用户入库 let mobile = ''; let userName = ''; for (let k = 0; k < forms.length; k++) { if (!mobile && forms[k].type == 'mobile') { mobile = forms[k].val; continue; } else if (!userName && forms[k].title == '姓名') { userName = forms[k].val; continue; } } // 统计 this.statJoinCnt(meetId, timeMark); return { result: 'ok', joinId } } // 根据日期获取其所在天设置 getDaySetByDay(meet, day) { for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) { if (meet.MEET_DAYS_SET[k].day == day) return dataUtil.deepClone(meet.MEET_DAYS_SET[k]); } return null; } // 根据时段标识获取其所在天 getDayByTimeMark(timeMark) { return timeMark.substr(1, 4) + '-' + timeMark.substr(5, 2) + '-' + timeMark.substr(7, 2); } // 根据时段标识获取其所在天设置 getDaySetByTimeMark(meet, timeMark) { let day = this.getDayByTimeMark(timeMark); for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) { if (meet.MEET_DAYS_SET[k].day == day) return dataUtil.deepClone(meet.MEET_DAYS_SET[k]); } return null; } // 根据时段标识获取其所在时段设置 getTimeSetByTimeMark(meet, timeMark) { let day = this.getDayByTimeMark(timeMark); for (let k = 0; k < meet.MEET_DAYS_SET.length; k++) { if (meet.MEET_DAYS_SET[k].day != day) continue; for (let j in meet.MEET_DAYS_SET[k].times) { if (meet.MEET_DAYS_SET[k].times[j].mark == timeMark) return dataUtil.deepClone(meet.MEET_DAYS_SET[k].times[j]); } } return null; } // 预约时段人数和状态控制校验 async checkMeetTimeControll(meet, timeMark) { if (!meet) this.AppError('预约时段设置错误, 预约项目不存在'); let daySet = this.getDaySetByTimeMark(meet, timeMark); // 当天设置 let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 预约时段设置 if (!daySet || !timeSet) this.AppError('预约时段设置错误day&time'); let statusDesc = timeSet.status == 1 ? '开启' : '关闭'; let limitDesc = ''; if (timeSet.isLimit) { limitDesc = '人数上限MAX=' + timeSet.limit; } else limitDesc = '人数不限制NO'; this._meetLog(meet, `------------------------------`); this._meetLog(meet, `#预约时段控制,预约日期=<${daySet.day}>`, `预约时段=[${timeSet.start}-${timeSet.end}],状态=${statusDesc}, ${limitDesc} 当前预约成功人数=${timeSet.stat.succCnt}`); if (timeSet.status == 0) this.AppError('该时段预约已经关闭,请选择其他'); // 时段总人数限制 if (timeSet.isLimit) { if (timeSet.stat.succCnt >= timeSet.limit) { this.AppError('该时段预约人员已满,请选择其他'); } } } /** 报名规则校验 */ async checkMeetRules(userId, meetId, timeMark) { // 预约时段是否存在 let meetWhere = { _id: meetId }; let day = this.getDayByTimeMark(timeMark); let meet = await this.getMeetOneDay(meetId, day, meetWhere); if (!meet) { this.AppError('预约时段选择错误,请重新选择'); } // 预约时段人数和状态控制校验 await this.checkMeetTimeControll(meet, timeMark); // 截止规则 await this.checkMeetEndSet(meet, timeMark); // 针对用户的次数限制 await this.checkMeetLimitSet(userId, meet, timeMark); } // 预约次数限制校验 async checkMeetLimitSet(userId, meet, timeMark) { if (!meet) this.AppError('预约次数规则错误, 预约项目不存在'); let meetId = meet._id; let daySet = this.getDaySetByTimeMark(meet, timeMark); // 当天设置 let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 预约时段设置 this._meetLog(meet, `------------------------------`); this._meetLog(meet, `#预约次数规则,预约日期=<${daySet.day}>`, `预约时段=[${timeSet.start}~${timeSet.end}]`); let where = { JOIN_MEET_ID: meetId, JOIN_MEET_TIME_MARK: timeMark, JOIN_USER_ID: userId, JOIN_STATUS: JoinModel.STATUS.SUCC } let cnt = await JoinModel.count(where); this._meetLog(meet, `预约次数规则,mode=本时段可预约1次`, `当前已预约=${cnt}次`); if (cnt >= 1) { this.AppError(`您本时段已经预约,无须重复预约`); } } // 预约截止设置校验 async checkMeetEndSet(meet, timeMark) { if (!meet) this.AppError('预约截止规则错误, 预约项目不存在'); this._meetLog(meet, `------------------------------`); let daySet = this.getDaySetByTimeMark(meet, timeMark); // 当天设置 let timeSet = this.getTimeSetByTimeMark(meet, timeMark); // 预约时段设置 this._meetLog(meet, `#预约截止规则,预约日期=<${daySet.day}>`, `预约时段=[${timeSet.start}-${timeSet.end}]`); let nowTime = timeUtil.time('Y-M-D h:m:s'); let startTime = daySet.day + ' ' + timeSet.start + ':00'; this._meetLog(meet, `预约开始规则,mode=<时段过期判定>`, `预约开始时段=${startTime},当前时段=${nowTime}`); if (nowTime > startTime) { this.AppError('该时段已开始,无法预约,请选择其他'); } } /** 预约详情 */ async viewMeet(meetId) { let fields = '*'; let where = { _id: meetId, MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]] } let meet = await MeetModel.getOne(where, fields); if (!meet) return null; let getDaysSet = []; meet.MEET_DAYS_SET = await this.getDaysSet(meetId, timeUtil.time('Y-M-D')); //今天及以后 let daysSet = meet.MEET_DAYS_SET; let now = timeUtil.time('Y-M-D'); for (let k = 0; k < daysSet.length; k++) { let dayNode = daysSet[k]; if (dayNode.day < now) continue; // 排除过期 let getTimes = []; for (let j in dayNode.times) { let timeNode = dayNode.times[j]; // 排除状态关闭的时段 if (timeNode.status != 1) continue; // 判断数量是否已满 if (timeNode.isLimit && timeNode.stat.succCnt >= timeNode.limit) timeNode.error = '预约已满'; // 截止规则 if (!timeNode.error) { try { await this.checkMeetEndSet(meet, timeNode.mark); } catch (ex) { if (ex.name == 'AppError') timeNode.error = '预约结束'; else throw ex; } } getTimes.push(timeNode); } dayNode.times = getTimes; getDaysSet.push(dayNode); } // 只返回需要的字段 let ret = {}; ret.MEET_DAYS_SET = getDaysSet; ret.MEET_IS_SHOW_LIMIT = meet.MEET_IS_SHOW_LIMIT; ret.MEET_TITLE = meet.MEET_TITLE; ret.MEET_TYPE_NAME = meet.MEET_TYPE_NAME; ret.MEET_CONTENT = meet.MEET_CONTENT; return ret; } /** 用户自助签到 */ async userSelfCheckin(userId, timeMark) { let day = this.getDayByTimeMark(timeMark); let today = timeUtil.time('Y-M-D'); if (day != today) this.AppError('仅在预约当天可以签到,当前签到码的日期是' + day); let whereSucc = { JOIN_MEET_DAY: day, JOIN_MEET_TIME_MARK: timeMark, JOIN_USER_ID: userId, JOIN_STATUS: JoinModel.STATUS.SUCC } let cntSucc = await JoinModel.count(whereSucc); let whereCheckin = { JOIN_MEET_DAY: day, JOIN_MEET_TIME_MARK: timeMark, JOIN_USER_ID: userId, JOIN_IS_CHECKIN: 1, JOIN_STATUS: JoinModel.STATUS.SUCC } let cntCheckin = await JoinModel.count(whereCheckin); let ret = ''; if (cntSucc == 0) { ret = '您没有本次报名的记录,请在「个人中心」查看详情~'; } else if (cntSucc == cntCheckin) { ret = '您已签到,无须重复签到,请在「个人中心」查看详情~'; } else { let where = { JOIN_MEET_DAY: day, JOIN_MEET_TIME_MARK: timeMark, JOIN_USER_ID: userId, JOIN_IS_CHECKIN: 0, JOIN_STATUS: JoinModel.STATUS.SUCC } let data = { JOIN_IS_CHECKIN: 1 } await JoinModel.edit(where, data); ret = '签到成功,请在「个人中心」查看详情~' } return { ret }; } /** 预约前获取关键信息 */ async detailForJoin(userId, meetId, timeMark) { let fields = 'MEET_DAYS_SET,MEET_FORM_SET, MEET_TITLE'; let where = { _id: meetId, MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]] } let day = this.getDayByTimeMark(timeMark); let meet = await this.getMeetOneDay(meetId, day, where, fields); if (!meet) return null; let dayDesc = timeUtil.fmtDateCHN(this.getDaySetByTimeMark(meet, timeMark).day); let timeSet = this.getTimeSetByTimeMark(meet, timeMark); let timeDesc = timeSet.start + '~' + timeSet.end; meet.dayDesc = dayDesc + ' ' + timeDesc; // 取出本人最近一次本时段填写表单 let whereMy = { JOIN_USER_ID: userId, JOIN_MEET_ID: meetId, JOIN_MEET_TIME_MARK: timeMark } let orderByMy = { JOIN_ADD_TIME: 'desc' } let joinMy = await JoinModel.getOne(whereMy, 'JOIN_FORMS', orderByMy); // 取出本人最近一次本项目填写表单 if (!joinMy) { whereMy = { JOIN_USER_ID: userId, JOIN_MEET_ID: meetId, } let orderByMy = { JOIN_ADD_TIME: 'desc' } joinMy = await JoinModel.getOne(whereMy, 'JOIN_FORMS', orderByMy); } // 取出本人最近一次的填写表单 if (!joinMy) { whereMy = { JOIN_USER_ID: userId, } let orderByMy = { JOIN_ADD_TIME: 'desc' } joinMy = await JoinModel.getOne(whereMy, 'JOIN_FORMS', orderByMy); } let myForms = joinMy ? joinMy.JOIN_FORMS : []; meet.myForms = myForms; return meet; } /** 获取某天可用时段 */ async getUsefulTimesByDaysSet(meetId, day) { let where = { DAY_MEET_ID: meetId, day } let daysSet = await DayModel.getAll(where, 'day,times'); let usefulTimes = []; for (let k = 0; k < daysSet.length; k++) { if (daysSet[k].day != day) continue; let times = daysSet[k].times; for (let j in times) { if (times[j].status != 1) continue; usefulTimes.push(times[j]); } break; } return usefulTimes; } /** 按天获取预约项目 */ async getMeetListByDay(day) { let where = { MEET_STATUS: MeetModel.STATUS.COMM, }; let orderBy = { 'MEET_ORDER': 'asc', 'MEET_ADD_TIME': 'desc' }; let fields = 'MEET_TITLE,MEET_DAYS_SET,MEET_STYLE_SET'; let list = await MeetModel.getAll(where, fields, orderBy); let retList = []; for (let k = 0; k < list.length; k++) { let usefulTimes = await this.getUsefulTimesByDaysSet(list[k]._id, day); if (usefulTimes.length == 0) continue; let node = {}; node.timeDesc = usefulTimes.length > 1 ? usefulTimes.length + '个时段' : usefulTimes[0].start; node.title = list[k].MEET_TITLE; node.pic = list[k].MEET_STYLE_SET.pic; node._id = list[k]._id; retList.push(node); } return retList; } /** 获取从某天开始可预约的日期 */ async getHasDaysFromDay(day) { let where = { day: ['>=', day], }; let fields = 'times,day'; let list = await DayModel.getAllBig(where, fields); let retList = []; for (let k = 0; k < list.length; k++) { for (let n in list[k].times) { if (list[k].times[n].status == 1) { retList.push(list[k].day); break; } } } return retList; } /** 取得预约分页列表 */ async getMeetList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 typeId, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'MEET_ORDER': 'asc', 'MEET_ADD_TIME': 'desc' }; let fields = 'MEET_TITLE,MEET_STYLE_SET,MEET_DAYS'; let where = {}; if (typeId && typeId !== '0') where.MEET_TYPE_ID = typeId; console.log(typeId) where.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 状态 if (util.isDefined(search) && search) { where.MEET_TITLE = { $regex: '.*' + search, $options: 'i' }; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'sort': // 排序 if (sortVal == 'view') { orderBy = { 'MEET_VIEW_CNT': 'desc', 'MEET_ADD_TIME': 'desc' }; } if (sortVal == 'new') { orderBy = { 'MEET_ADD_TIME': 'desc' }; } break; } } let result = await MeetModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); return result; } /** 取消我的预约 只有成功可以取消 */ async cancelMyJoin(userId, joinId) { let where = { JOIN_USER_ID: userId, _id: joinId, JOIN_IS_CHECKIN: 0, // 签到不能取消 JOIN_STATUS: JoinModel.STATUS.SUCC }; let join = await JoinModel.getOne(where); if (!join) { this.AppError('未找到可取消的预约记录'); } // 取消规则判定 let whereMeet = { _id: join.JOIN_MEET_ID, MEET_STATUS: ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]] } let meet = await this.getMeetOneDay(join.JOIN_MEET_ID, join.JOIN_MEET_DAY, whereMeet); if (!meet) this.AppError('预约项目不存在或者已关闭'); let daySet = this.getDaySetByTimeMark(meet, join.JOIN_MEET_TIME_MARK); let timeSet = this.getTimeSetByTimeMark(meet, join.JOIN_MEET_TIME_MARK); if (!timeSet) this.AppError('被取消的时段不存在'); let startT = daySet.day + ' ' + timeSet.start + ':00'; let startTime = timeUtil.time2Timestamp(startT); let now = timeUtil.time(); if (now > startTime) this.AppError('该预约已经开始,无法取消'); let data = { JOIN_STATUS: JoinModel.STATUS.CANCEL, JOIN_REASON: '', JOIN_IS_CHECKIN: 0, } await JoinModel.edit(where, data); this.statJoinCnt(join.JOIN_MEET_ID, join.JOIN_MEET_TIME_MARK); } /** 取得我的预约详情 */ async getMyJoinDetail(userId, joinId) { let fields = 'JOIN_IS_CHECKIN,JOIN_REASON,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME,JOIN_CODE,JOIN_FORMS'; let where = { _id: joinId, JOIN_USER_ID: userId }; return await JoinModel.getOne(where, fields); } /** 取得我的预约分页列表 */ async getMyJoinList(userId, { search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { // 'JOIN_MEET_DAY': 'desc', // 'JOIN_MEET_TIME_START': 'desc', 'JOIN_ADD_TIME': 'desc' }; let fields = 'JOIN_IS_CHECKIN,JOIN_REASON,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME'; let where = { JOIN_USER_ID: userId }; //where.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 状态 if (util.isDefined(search) && search) { where.JOIN_MEET_TITLE = { $regex: '.*' + search, $options: 'i' }; } else if (sortType) { // 搜索菜单 switch (sortType) { case 'timedesc': { //按时间倒序 orderBy = { 'JOIN_MEET_DAY': 'desc', 'JOIN_MEET_TIME_START': 'desc', 'JOIN_ADD_TIME': 'desc' }; break; } case 'timeasc': { //按时间正序 orderBy = { 'JOIN_MEET_DAY': 'asc', 'JOIN_MEET_TIME_START': 'asc', 'JOIN_ADD_TIME': 'asc' }; break; } case 'today': { //今天 where.JOIN_MEET_DAY = timeUtil.time('Y-M-D'); break; } case 'tomorrow': { //明日 where.JOIN_MEET_DAY = timeUtil.time('Y-M-D', 86400); break; } case 'succ': { //预约成功 where.JOIN_STATUS = JoinModel.STATUS.SUCC; //where.JOIN_MEET_DAY = ['>=', timeUtil.time('Y-M-D')]; //where.JOIN_MEET_TIME_START = ['>=', timeUtil.time('h:m')]; break; } case 'cancel': { //已取消 where.JOIN_STATUS = ['in', [JoinModel.STATUS.CANCEL, JoinModel.STATUS.ADMIN_CANCEL]]; break; } } } let result = await JoinModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); return result; } /** 取得我的某日预约列表 */ async getMyJoinSomeday(userId, day) { let fields = 'JOIN_IS_CHECKIN,JOIN_MEET_ID,JOIN_MEET_TITLE,JOIN_MEET_DAY,JOIN_MEET_TIME_START,JOIN_MEET_TIME_END,JOIN_STATUS,JOIN_ADD_TIME'; let where = { JOIN_USER_ID: userId, JOIN_MEET_DAY: day }; //where.MEET_STATUS = ['in', [MeetModel.STATUS.COMM, MeetModel.STATUS.OVER]]; // 状态 let orderBy = { 'JOIN_MEET_TIME_START': 'asc', 'JOIN_ADD_TIME': 'desc' } return await JoinModel.getAll(where, fields, orderBy); } } module.exports = MeetService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/news_service.js ================================================ /** * Notes: 资讯模块业务逻辑 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2020-10-29 07:48:00 */ const BaseProjectService = require('./base_project_service.js'); const util = require('../../../framework/utils/util.js'); const NewsModel = require('../model/news_model.js'); class NewsService extends BaseProjectService { /** 浏览资讯信息 */ async viewNews(id) { let fields = '*'; let where = { _id: id, NEWS_STATUS: 1 } let news = await NewsModel.getOne(where, fields); if (!news) return null; return news; } /** 取得分页列表 */ async getNewsList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 cateId, //附加查询条件 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'NEWS_ORDER': 'asc', 'NEWS_ADD_TIME': 'desc' }; let fields = 'NEWS_PIC,NEWS_VIEW_CNT,NEWS_TITLE,NEWS_DESC,NEWS_CATE_ID,NEWS_ADD_TIME,NEWS_ORDER,NEWS_STATUS,NEWS_CATE_NAME,NEWS_OBJ'; let where = {}; where.NEWS_STATUS = 1; // 状态 if (cateId && cateId !== '0') where.NEWS_CATE_ID = cateId; if (util.isDefined(search) && search) { where.NEWS_TITLE = { $regex: '.*' + search, $options: 'i' }; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'NEWS_ADD_TIME'); break; } } } return await NewsModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } } module.exports = NewsService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/passport_service.js ================================================ /** * Notes: passport模块业务逻辑 * Date: 2020-10-14 07:48:00 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) */ const BaseProjectService = require('./base_project_service.js'); const cloudBase = require('../../../framework/cloud/cloud_base.js'); const UserModel = require('../model/user_model.js'); const dataUtil = require('../../../framework/utils/data_util.js'); class PassportService extends BaseProjectService { // 注册 async register(userId, { mobile, name, forms, status }) { // 判断是否存在 let where = { USER_MINI_OPENID: userId } let cnt = await UserModel.count(where); if (cnt > 0) return await this.login(userId); where = { USER_MOBILE: mobile } cnt = await UserModel.count(where); if (cnt > 0) this.AppError('该手机已注册'); // 入库 let data = { USER_MINI_OPENID: userId, USER_MOBILE: mobile, USER_NAME: name, USER_OBJ: dataUtil.dbForms2Obj(forms), USER_FORMS: forms, USER_STATUS: Number(status) } await UserModel.insert(data); return await this.login(userId); } /** 获取手机号码 */ async getPhone(cloudID) { let cloud = cloudBase.getCloud(); let res = await cloud.getOpenData({ list: [cloudID], // 假设 event.openData.list 是一个 CloudID 字符串列表 }); if (res && res.list && res.list[0] && res.list[0].data) { let phone = res.list[0].data.phoneNumber; return phone; } else return ''; } /** 取得我的用户信息 */ async getMyDetail(userId) { let where = { USER_MINI_OPENID: userId } let fields = 'USER_MOBILE,USER_NAME,USER_FORMS,USER_OBJ,USER_STATUS,USER_CHECK_REASON' return await UserModel.getOne(where, fields); } /** 修改用户资料 */ async editBase(userId, { mobile, name, forms }) { let whereMobile = { USER_MOBILE: mobile, USER_MINI_OPENID: ['<>', userId] } let cnt = await UserModel.count(whereMobile); if (cnt > 0) this.AppError('该手机已注册'); let where = { USER_MINI_OPENID: userId } let user = await UserModel.getOne(where); if (!user) return; let data = { USER_MOBILE: mobile, USER_NAME: name, USER_OBJ: dataUtil.dbForms2Obj(forms), USER_FORMS: forms, }; if (user.USER_STATUS == UserModel.STATUS.UNCHECK) data.USER_STATUS = UserModel.STATUS.UNUSE; await UserModel.edit(where, data); } /** 登录 */ async login(userId) { let where = { 'USER_MINI_OPENID': userId }; let fields = 'USER_ID,USER_MINI_OPENID,USER_NAME,USER_PIC,USER_STATUS'; let user = await UserModel.getOne(where, fields); let token = {}; if (user) { // 正常用户 token.id = user.USER_MINI_OPENID; token.key = user.USER_ID; token.name = user.USER_NAME; token.pic = user.USER_PIC; token.status = user.USER_STATUS; // 异步更新最近更新时间 let dataUpdate = { USER_LOGIN_TIME: this._timestamp }; UserModel.edit(where, dataUpdate); UserModel.inc(where, 'USER_LOGIN_CNT', 1); } else token = null; return { token }; } } module.exports = PassportService; ================================================ FILE: cloudfunctions/mcloud/project/TRIP1/service/product_service.js ================================================ /** * Notes: 产品模块业务逻辑 * Ver : CCMiniCloud Framework 2.0.1 ALL RIGHTS RESERVED BY cclinux0730 (wechat) * Date: 2022-06-08 07:48:00 */ const BaseProjectService = require('./base_project_service.js'); const util = require('../../../framework/utils/util.js'); const ProductModel = require('../model/product_model.js'); class ProductService extends BaseProjectService { /** 浏览资讯信息 */ async viewProduct(id) { let fields = '*'; let where = { _id: id, PRODUCT_STATUS: ProductModel.STATUS.COMM } let product = await ProductModel.getOne(where, fields); if (!product) return null; ProductModel.inc(id, 'PRODUCT_VIEW_CNT', 1); return product; } /** 取得分页列表 */ async getProductList({ search, // 搜索条件 sortType, // 搜索菜单 sortVal, // 搜索菜单 orderBy, // 排序 page, size, isTotal = true, oldTotal }) { orderBy = orderBy || { 'PRODUCT_ORDER': 'asc', 'PRODUCT_ADD_TIME': 'desc' }; let fields = 'PRODUCT_VIEW_CNT,PRODUCT_TITLE,PRODUCT_CATE_ID,PRODUCT_ADD_TIME,PRODUCT_ORDER,PRODUCT_STATUS,PRODUCT_CATE_NAME,PRODUCT_OBJ'; let where = {}; where.and = { _pid: this.getProjectId() //复杂的查询在此处标注PID }; where.and.PRODUCT_STATUS = ProductModel.STATUS.COMM; // 状态 if (util.isDefined(search) && search) { where.or = [ { PRODUCT_TITLE: ['like', search] }, ]; } else if (sortType && util.isDefined(sortVal)) { // 搜索菜单 switch (sortType) { case 'cateId': { if (sortVal) where.and.PRODUCT_CATE_ID = String(sortVal); break; } case 'sort': { orderBy = this.fmtOrderBySort(sortVal, 'PRODUCT_ADD_TIME'); break; } } } return await ProductModel.getList(where, fields, orderBy, page, size, isTotal, oldTotal); } } module.exports = ProductService; ================================================ FILE: miniprogram/app.js ================================================ const setting = require('./setting/setting.js'); App({ onLaunch: function (options) { if (!wx.cloud) { console.error('请使用 2.2.3 或以上的基础库以使用云能力') } else { wx.cloud.init({ // env 参数说明: // env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源 // 此处请填入环境 ID, 环境 ID 可打开云控制台查看 // 如不填则使用默认环境(第一个创建的环境) // env: 'my-env-id', env: setting.CLOUD_ID, traceUser: true, }) } this.globalData = {}; // 用于自定义导航栏 wx.getSystemInfo({ success: e => { this.globalData.statusBar = e.statusBarHeight; let capsule = wx.getMenuButtonBoundingClientRect(); if (capsule) { this.globalData.custom = capsule; this.globalData.customBar = capsule.bottom + capsule.top - e.statusBarHeight; } else { this.globalData.customBar = e.statusBarHeight + 50; } } }); }, }) ================================================ FILE: miniprogram/app.json ================================================ { "pages": [ "projects/TRIP1/pages/default/index/default_index", "projects/TRIP1/pages/about/index/about_index", "projects/TRIP1/pages/search/search", "projects/TRIP1/pages/my/index/my_index", "projects/TRIP1/pages/my/reg/my_reg", "projects/TRIP1/pages/my/edit/my_edit", "projects/TRIP1/pages/my/foot/my_foot", "projects/TRIP1/pages/my/fav/my_fav", "projects/TRIP1/pages/news/index/news_index", "projects/TRIP1/pages/news/detail/news_detail", "projects/TRIP1/pages/news/cate1/news_cate1", "projects/TRIP1/pages/news/cate2/news_cate2", "projects/TRIP1/pages/admin/news/list/admin_news_list", "projects/TRIP1/pages/admin/news/add/admin_news_add", "projects/TRIP1/pages/admin/news/edit/admin_news_edit", "projects/TRIP1/pages/admin/setup/about/admin_setup_about", "projects/TRIP1/pages/admin/setup/about_list/admin_setup_about_list", "projects/TRIP1/pages/admin/setup/qr/admin_setup_qr", "projects/TRIP1/pages/admin/index/home/admin_home", "projects/TRIP1/pages/admin/index/login/admin_login", "projects/TRIP1/pages/admin/content/admin_content", "projects/TRIP1/pages/admin/mgr/log/admin_log_list", "projects/TRIP1/pages/admin/mgr/edit/admin_mgr_edit", "projects/TRIP1/pages/admin/mgr/list/admin_mgr_list", "projects/TRIP1/pages/admin/mgr/add/admin_mgr_add", "projects/TRIP1/pages/admin/mgr/pwd/admin_mgr_pwd", "projects/TRIP1/pages/admin/user/list/admin_user_list", "projects/TRIP1/pages/admin/user/detail/admin_user_detail", "projects/TRIP1/pages/admin/user/export/admin_user_export", "projects/TRIP1/pages/meet/index/meet_index", "projects/TRIP1/pages/meet/calendar/meet_calendar", "projects/TRIP1/pages/meet/join/meet_join", "projects/TRIP1/pages/meet/detail/meet_detail", "projects/TRIP1/pages/meet/self/meet_self", "projects/TRIP1/pages/meet/my_join_list/meet_my_join_list", "projects/TRIP1/pages/meet/my_join_detail/meet_my_join_detail", "projects/TRIP1/pages/admin/meet/cover/admin_meet_cover", "projects/TRIP1/pages/admin/meet/edit/admin_meet_edit", "projects/TRIP1/pages/admin/meet/export/admin_join_export", "projects/TRIP1/pages/admin/meet/join/admin_meet_join", "projects/TRIP1/pages/admin/meet/list/admin_meet_list", "projects/TRIP1/pages/admin/meet/record/admin_record_list", "projects/TRIP1/pages/admin/meet/scan/admin_meet_scan", "projects/TRIP1/pages/admin/meet/self/admin_meet_self", "projects/TRIP1/pages/admin/meet/temp/admin_temp_select", "projects/TRIP1/pages/admin/meet/time/admin_meet_time", "projects/TRIP1/pages/album/detail/album_detail", "projects/TRIP1/pages/album/index/album_index", "projects/TRIP1/pages/admin/album/list/admin_album_list", "projects/TRIP1/pages/admin/album/add/admin_album_add", "projects/TRIP1/pages/admin/album/edit/admin_album_edit", "projects/TRIP1/pages/product/detail/product_detail", "projects/TRIP1/pages/product/index/product_index", "projects/TRIP1/pages/admin/product/list/admin_product_list", "projects/TRIP1/pages/admin/product/add/admin_product_add", "projects/TRIP1/pages/admin/product/edit/admin_product_edit", "projects/TRIP1/pages/about/service/about_service", "cmpts/public/form/form_set/field/form_set_field", "cmpts/public/form/form_show/content/form_show_content", "pages/test1/test1" ], "window": { "backgroundColor": "#f1f1f1", "backgroundTextStyle": "dark", "navigationBarBackgroundColor": "#00C176", "navigationBarTitleText": "旅游景区门户小程序", "navigationBarTextStyle": "white" }, "tabBar": { "custom": false, "backgroundColor": "#FFFFFF", "color": "#999999", "selectedColor": "#00C176", "list": [ { "pagePath": "projects/TRIP1/pages/default/index/default_index", "text": "首页", "iconPath": "/projects/TRIP1/images/tabbar/home.png", "selectedIconPath": "/projects/TRIP1/images/tabbar/home_cur.png" }, { "pagePath": "projects/TRIP1/pages/product/index/product_index", "text": "景点", "iconPath": "/projects/TRIP1/images/tabbar/jing.png", "selectedIconPath": "/projects/TRIP1/images/tabbar/jing_cur.png" }, { "pagePath": "projects/TRIP1/pages/album/index/album_index", "text": "攻略", "iconPath": "/projects/TRIP1/images/tabbar/gong.png", "selectedIconPath": "/projects/TRIP1/images/tabbar/gong_cur.png" }, { "pagePath": "projects/TRIP1/pages/about/service/about_service", "text": "服务", "iconPath": "/projects/TRIP1/images/tabbar/service.png", "selectedIconPath": "/projects/TRIP1/images/tabbar/service_cur.png" }, { "pagePath": "projects/TRIP1/pages/my/index/my_index", "text": "我的", "iconPath": "/projects/TRIP1/images/tabbar/my.png", "selectedIconPath": "/projects/TRIP1/images/tabbar/my_cur.png" } ] }, "permission": { "scope.userLocation": { "desc": "获取你当前位置信息用于小程序位置接口的效果展示" } }, "usingComponents": { "cmpt-comm-list": "/cmpts/public/list/comm_list_cmpt", "cmpt-picker": "/cmpts/public/picker/picker_cmpt", "cmpt-modal": "/cmpts/public/modal/modal_cmpt" }, "sitemapLocation": "sitemap.json" } ================================================ FILE: miniprogram/app.wxss ================================================ @import "style/base/comm.wxss"; @import "style/public/project.wxss"; ================================================ FILE: miniprogram/cmpts/biz/detail/detail_cmpt.js ================================================ const pageHelper = require('../../../helper/page_helper'); const posterCmptHelper = require('../../public/poster/poster_cmpt_helper.js'); const FavBiz = require('../../../comm/biz/fav_biz.js'); const FootBiz = require('../../../comm/biz/foot_biz.js'); Component({ options: { addGlobalClass: true }, /** * 组件的属性列表 */ properties: { mode: { type: String, value: 'mode1' }, oid: { type: String, value: '' }, cate: { type: String, value: '' }, title: { type: String, value: '' }, cover: { type: String, value: '' }, desc: { type: String, value: '查看详情' }, qr: { type: String, value: '' }, bg: { type: String, value: '' }, tag: { type: String, //小角标 value: '' }, doFav: { type: Boolean, value: true }, doFoot: { type: Boolean, value: true }, doShare: { type: Boolean, value: true }, doHome: { type: Boolean, value: true }, doPoster: { type: Boolean, value: true }, doFoot: { type: Boolean, value: true }, doTop: { type: Boolean, value: true }, doSlot: { type: Boolean, value: false }, topBtnBottom: { type: Number, value: 190 }, topBtnShow: { type: Boolean, value: false }, }, /** * 组件的初始数据 */ data: { isFav: -1, showPoster: false, posterConfig: null, }, lifetimes: { created: function () { }, attached: function () { }, ready: async function () { if (!this.data.oid || !this.data.title) return; if (this.data.doFav) { FavBiz.isFav(this, this.data.oid); } if (this.data.doFoot) { FootBiz.addFoot(this.data.cate, this.data.title); } if (this.data.doShare) { let posterConfig = await posterCmptHelper.config1({ cover: this.data.cover, title: this.data.title, desc: this.data.desc, qr: this.data.qr, bg: this.data.bg }) this.setData({ posterConfig }); } }, move: function () { }, detached: function () { }, }, /** * 组件的方法列表 */ methods: { bindShareTap: function () { this.setData({ showPoster: true }); }, bindFavTap: async function () { if (this.data.isFav == -1) return; await FavBiz.updateFav(this, this.data.oid, this.data.isFav, this.data.cate, this.data.title); }, url: function (e) { pageHelper.url(e, this); }, bindHomeTap: function (e) { let url = pageHelper.fmtURLByPID('/pages/default/index/default_index'); wx.reLaunch({ url }); }, top: function (e) { // 回页首事件 pageHelper.top(); } } }) ================================================ FILE: miniprogram/cmpts/biz/detail/detail_cmpt.json ================================================ { "component": true, "usingComponents": { "cmpt-poster": "/cmpts/public/poster/poster_cmpt" } } ================================================ FILE: miniprogram/cmpts/biz/detail/detail_cmpt.wxml ================================================ 首页