Commit 844b9efe authored by fengyu's avatar fengyu

V1.0.0

parents
# 环境标识
VITE_APP_ENV = 'development'
# URL路径
VITE_APP_BASE_URL = '/practice-jiaxiu-mobile/'
# API地址
VITE_APP_BASE_API = 'https://info.gyntv.com.cn/back/ty-visit/ty-visit'
#组织标识
VITE_APP_VISITOR_CODE = 'practice-mediaCatalog'
#文件路径
VITE_APP_FILE_URL = '/download'
#kkfile地址
VITE_APP_PREVIEW_URL = 'http://jiaxiu.gyntv.com.cn:8012/onlinePreview?url='
#打包文件名称
VITE_APP_OUTDIR_FILENAME = 'practice-jiaxiu-mobile-html'
#systemCode
VITE_APP_SYSTEM_CODE = 'ty-centre'
#爽贵阳appid
VITE_APP_SGY_APPID = '685669b8b471aef47e2968a581ca03cd'
\ No newline at end of file
# 环境标识
VITE_APP_ENV = 'production'
# URL路径
VITE_APP_BASE_URL = '/practice-jiaxiu-mobile/'
# API地址
VITE_APP_BASE_API = 'https://info.gyntv.com.cn/back/ty-visit/ty-visit'
#组织标识
VITE_APP_VISITOR_CODE = 'practice-mediaCatalog'
#文件路径
VITE_APP_FILE_URL = 'https://info.gyntv.com.cn//download'
#kkfile地址
VITE_APP_PREVIEW_URL = 'http://jiaxiu.gyntv.com.cn:8012/onlinePreview?url='
#打包文件名称
VITE_APP_OUTDIR_FILENAME = 'practice-jiaxiu-mobile-html'
#systemCode
VITE_APP_SYSTEM_CODE = 'ty-centre'
#爽贵阳appid
VITE_APP_SGY_APPID = '685669b8b471aef47e2968a581ca03cd'
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
build
*.local
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
.rexma
stages:
- install
- deploy
cache:
key: jiaxiuvisit
paths:
- node_modules/
job_install:
stage: install
image: fyout.docker.harbor/library/arm-node:v17.3.0
script:
- npm cache clean --force
- npm config set registry http://registry.npm.taobao.org/
- npm install # 安装项目依赖
- npm install sass --save-dev
- npm install vite-plugin-sass --save-dev
- npm run build # 执行构建命令,生成静态文件1
artifacts:
paths:
- practice-tcsbm-html/ # 假设你的构建输出在 "dist/" 目录下2
tags:
- docker-node
only:
- master
when: manual
deploy:
stage: deploy
script:
- echo "test with tag build,gitlab-runner免密3"
- echo $USER
- su - gitlab-runner
- ssh root@172.16.7.4 mkdir -p /data/fengyu/prod/nginx/html/jiaxiu-visit-h5
- scp -r ./practice-tcsbm-html/** root@172.16.7.4:/data/fengyu/prod/nginx/html/jiaxiu-visit-h5
tags:
- shell
only:
- master
when: manual
\ No newline at end of file
stages:
- install
- deploy
cache:
key: jiaxiuvisit
paths:
- node_modules/
job_install:
stage: install
image: fyout.docker.harbor/library/arm-node:v17.3.0
script:
- npm cache clean --force
- npm config set registry http://registry.npm.taobao.org/
- npm install # 安装项目依赖
- npm install sass --save-dev
- npm install vite-plugin-sass --save-dev
- npm run build # 执行构建命令,生成静态文件1111
artifacts:
paths:
- practice-tcsbm-html/ # 假设你的构建输出在 "dist/" 目录下2
tags:
- docker-node
only:
- master
when: manual
deploy:
stage: deploy
script:
- echo "test with tag build,gitlab-runner免密3"
- echo $USER
- su - gitlab-runner
- ssh root@172.16.7.31 mkdir -p /data/k8snacos/prod/nginx/html/jiaxiu-visit-h5
- scp -r ./practice-tcsbm-html/** root@172.16.7.31:/data/k8snacos/prod/nginx/html/jiaxiu-visit-h5
tags:
- shell
only:
- master
when: manual
\ No newline at end of file
stages:
- install
- deploy
cache:
key: jiaxiuvisit
paths:
- node_modules/
job_install:
stage: install
script:
# - npm cache clean --force
- npm config set registry http://registry.npm.taobao.org/
# - npm install # 安装项目依赖
# - npm install sass --save-dev
# - npm install vite-plugin-sass --save-dev
- npm run build # 执行构建命令,生成静态文件1
artifacts:
paths:
- practice-tcsbm-html/ # 假设你的构建输出在 "dist/" 目录下2
tags:
- docker-node
only:
- master
when: manual
deploy:
stage: deploy
script:
- echo "test with tag build,gitlab-runner免密3"
- echo $USER
- su - gitlab-runner
- ssh root@172.16.6.21 mkdir -p /data/fengyu/prod/nginx/html/jiaxiu-visit-h5
- scp -r ./practice-tcsbm-html/** root@172.16.6.21:/data/fengyu/prod/nginx/html/jiaxiu-visit-h5
tags:
- shell
only:
- master
when: manual
\ No newline at end of file
stages:
- install
- deploy
cache:
key: jiaxiuvisit
paths:
- node_modules/
job_install:
stage: install
script:
- npm cache clean --force
- npm config set registry http://registry.npm.taobao.org/
- npm install # 安装项目依赖
- npm install sass --save-dev
- npm install vite-plugin-sass --save-dev
- npm run build # 执行构建命令,生成静态文件1
artifacts:
paths:
- practice-tcsbm-html/ # 假设你的构建输出在 "dist/" 目录下2
tags:
- docker-node
only:
- master
when: manual
deploy:
stage: deploy
script:
- echo "test with tag build,gitlab-runner免密3"
- echo $USER
- su - gitlab-runner
- ssh root@192.168.0.60 mkdir -p /data/fengyu/prod/nginx/html/jiaxiu-visit-h5
- scp -r ./practice-tcsbm-html/** root@192.168.0.60:/data/fengyu/prod/nginx/html/jiaxiu-visit-h5
tags:
- shell
only:
- master
when: manual
\ No newline at end of file
stages:
- install
- deploy
cache:
key: jiaxiuvisit
paths:
- node_modules/
job_install:
stage: install
script:
- npm cache clean --force
- npm config set registry http://registry.npm.taobao.org/
- npm install # 安装项目依赖
- npm install sass --save-dev
- npm install vite-plugin-sass --save-dev
- npm run build # 执行构建命令,生成静态文件1
artifacts:
paths:
- practice-tcsbm-html/ # 假设你的构建输出在 "dist/" 目录下2
tags:
- docker-node
only:
- master
when: manual
deploy:
stage: deploy
script:
- echo "test with tag build,gitlab-runner免密3"
- echo $USER
- su - gitlab-runner
- ssh root@192.168.0.50 mkdir -p /data/fengyu/prod/nginx/html/jiaxiu-visit-h5
- scp -r ./practice-tcsbm-html/** root@192.168.0.50:/data/fengyu/prod/nginx/html/jiaxiu-visit-h5
tags:
- shell
only:
- master
when: manual
\ No newline at end of file
// .npmrc
public-hoist-pattern[]=@vue*
// or
// shamefully-hoist = true
# 小程序平台模板 vue3
## 安装依赖
```
yarn install
```
### 本地服务
```
yarn start
```
### 小程序平台打包
```
yarn build
```
## 默认安装的 UI 库
[wot-design-uni](https://wot-design-uni.netlify.app/component/button.html)
### 自定义爽贵阳条件编译平台 H5-SGY
#### 1.配置扩展平台
```
//package.json
"uni-app": {
"scripts": {
"h5-sgy": {
"title": "爽贵阳平台",
"env": {
"UNI_PLATFORM": "h5"
},
"define": {
"H5-SGY": true
}
}
}
}
```
#### 2.修改启动命令
```
//package.json
"scripts": {
"start": "rexma start-rexma",
"build": "rexma build-rexma",
"start:platform": "rexma start",
"build:platform": "rexma build"
},
//package.json
"scripts": {
"start": "uni -p h5-sgy",
"build": "uni build -p h5-sgy",
"start:platform": "rexma start",
"build:platform": "rexma build"
}
```
#### 3.使用方式参考 main.js
```
// #ifdef H5
console.log('当前基准平台:H5')
// #endif
// #ifdef H5-SGY
console.log('当前扩展平台:H5-SGY')
// #endif
```
##### 注意:H5-SGY 条件编译是基于 H5 条件编译进行扩展,H5-SGY 条件编译和 H5 条件编译会同时生效。若需要仅 H5 条件编译生效,请指定运行或打包平台为 H5。
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
VanButton: typeof import('vant/es')['Button']
VanCalendar: typeof import('vant/es')['Calendar']
VanCascader: typeof import('vant/es')['Cascader']
VanCol: typeof import('vant/es')['Col']
VanEmpty: typeof import('vant/es')['Empty']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanList: typeof import('vant/es')['List']
VanNavBar: typeof import('vant/es')['NavBar']
VanPopup: typeof import('vant/es')['Popup']
VanProgress: typeof import('vant/es')['Progress']
VanPullRefresh: typeof import('vant/es')['PullRefresh']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanStep: typeof import('vant/es')['Step']
VanSteps: typeof import('vant/es')['Steps']
VanSticky: typeof import('vant/es')['Sticky']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VanTextEllipsis: typeof import('vant/es')['TextEllipsis']
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
<title>甲秀图库</title>
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
\ No newline at end of file
{
"name": "rexma-temp-vue3",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"start": "rexma start-rexma --custom h5-sgy",
"build": "rexma build-rexma --custom h5-sgy",
"start:platform": "rexma start",
"build:platform": "rexma build"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4000720240327002",
"@dcloudio/uni-app-plus": "3.0.0-4000720240327002",
"@dcloudio/uni-components": "3.0.0-4000720240327002",
"@dcloudio/uni-h5": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-alipay": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-baidu": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-jd": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-lark": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-qq": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-toutiao": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-weixin": "3.0.0-4000720240327002",
"@dcloudio/uni-mp-xhs": "3.0.0-4000720240327002",
"@dcloudio/uni-quickapp-webview": "3.0.0-4000720240327002",
"@vant/area-data": "^1.5.1",
"axios": "^1.7.2",
"dayjs": "^1.11.11",
"pinia": "2.0.36",
"pinia-plugin-persist": "^1.0.0",
"vant": "^4.9.1",
"vconsole": "^3.15.1",
"vue": "^3.3.11",
"vue-i18n": "^9.1.9",
"vue-router": "4",
"wot-design-uni": "^1.2.26",
"xinhua-sdk": "^1.6.0"
},
"devDependencies": {
"@dcloudio/types": "^3.3.2",
"@dcloudio/uni-automator": "3.0.0-4000720240327002",
"@dcloudio/uni-cli-shared": "3.0.0-4000720240327002",
"@dcloudio/uni-stacktracey": "3.0.0-4000720240327002",
"@dcloudio/vite-plugin-uni": "3.0.0-4000720240327002",
"@types/node": "^20.14.5",
"@vant/auto-import-resolver": "^1.2.1",
"@vitejs/plugin-legacy": "4.1.1",
"@vue/runtime-core": "^3.3.11",
"@vue/tsconfig": "^0.1.3",
"add": "^2.0.6",
"rexma-cli": "^1.9.3",
"sass": "^1.77.6",
"typescript": "^4.9.4",
"uni-mini-router": "^0.1.6",
"uni-parse-pages": "^0.0.1",
"unplugin-auto-import": "^0.17.6",
"unplugin-vue-components": "^0.27.2",
"vite": "4.3.5",
"vue-tsc": "^1.0.24"
},
"uni-app": {
"scripts": {
"h5-sgy": {
"title": "爽贵阳平台",
"env": {
"UNI_PLATFORM": "h5",
"REXMA": true
},
"define": {
"H5-SGY": true
}
}
}
}
}
\ No newline at end of file
<script setup lang="ts">
onLaunch(() => {
console.log('App Launch');
});
onShow(() => {
console.log('App Show');
});
onHide(() => {
console.log('App Hide');
});
</script>
<style></style>
import request from '@/utils/request'
/**
* @description 账号密码登录
* @param {any} data 账号密码登录
* @returns
*/
export const loginByPassword = (data) => {
return request({
url: '/login',
method: 'post',
data: data
})
}
/**
* @description 爽贵阳快捷登录
* @param {any} data 爽贵阳快捷登录
* @returns
*/
export const loginBySgy = (data) => {
return request({
url: '/sgylogin',
method: 'post',
data: data
})
}
\ No newline at end of file
import request from '@/utils/request'
/**
* @description 组织列表查询
* @param {Any} data 标签对象
* @returns
*/
export const selectOrganizeList = (data) => {
return request({
url: '/app/appMediaSelect/selectAppOrganizeList',
method: 'post',
data: data
})
}
/**
* @description 专区列表查询
* @param {Any} page 分页对象
* @param {Any} data 图组对象
* @returns
*/
export const selectPrefecturetList = (page,data) => {
return request({
url: `/app/appMediaSelect/selectAppMediaByOrganIdPage/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
\ No newline at end of file
import request from '@/utils/request'
/**
* @description 上传图片
* @param {File} file File对象
* @param {Function} handleUploadProgress 上传进度回调
* @returns
*/
export const uploadFile = (file, handleUploadProgress) => {
const formData = new FormData()
formData.append("file", file)
formData.append("systemCode", import.meta.env.VITE_APP_SYSTEM_CODE)
return request({
url: '/html/htmlMediaInsert/htmlSingleUpload',
method: 'post',
data: formData,
onUploadProgress: handleUploadProgress,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
/**
* @description 查询类型数据
* @returns
*/
export const selectTypeList = () => {
const data = {
materialType: 3
}
return request({
url: '/html/htmlMediaSelect/selectHtmlClassifyList',
method: 'post',
data: data
})
}
/**
* @description 查询来源数据
* @param {Number} sourceType 1.来源类型 2.来源渠道
* @returns
*/
export const selectSourceList = (sourceType) => {
const data = { sourceType }
return request({
url: '/html/htmlMediaSelect/selectHtmlSourceList',
method: 'post',
data: data
})
}
/**
* @description 查询标签数据
* @returns
*/
export const selectTagsList = () => {
const data = {}
return request({
url: `/html/htmlMediaSelect/treeHtmlTagData/${import.meta.env.VITE_APP_SYSTEM_CODE}`,
method: 'post',
data: data
})
}
/**
* @description 精细查询图组列表
* @param {Any} page 分页对象
* @param {Any} data 图组对象
* @returns
*/
export const selectFinePictureList = (page, data) => {
return request({
url: `/app/appMediaSelect/selectAppFineCatalogList/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
/**
* @description 广泛查询图组列表
* @param {Any} page 分页对象
* @param {Any} data 图组对象
* @returns
*/
export const selectCoarsePictureList = (page, data) => {
return request({
url: `/app/appMediaSelect/selectAppCatalogList/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
/**
* @description 我的图组列表
* @param {Any} page 分页对象
* @param {Any} data 图组对象
* @returns
*/
export const selectMinePictureList = (page, data) => {
return request({
url: `/app/appMediaSelect/selectAppMaterialRetrievalList/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
/**
* @description 我的收藏列表
* @param {Any} page 分页对象
* @param {Any} data 图组对象
* @returns
*/
export const selectCollectPictureList = (page, data) => {
return request({
url: `/app/appMediaSelect/selectAppPersonMaterialList/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
/**
* @description 发布图组
* @param {Any} data 图组对象
* @returns
*/
export const publishPicture = ( data) => {
return request({
url: '/app/appMediaUpdate/updateAppCollect',
method: 'post',
data: data
})
}
/**
* @description 新增图组
* @param {Any} data 图组对象
* @returns
*/
export const insertPicture = (data) => {
return request({
url: '/html/htmlMediaInsert/htmlInsertImageCatalog',
method: 'post',
data: data
})
}
/**
* @description 新增图组地址
* @param {Any} data 图组地址列表
* @returns
*/
export const insertPictureUrl = (data) => {
return request({
url: '/html/htmlMediaInsert/htmlBatchInsertEnclosure',
method: 'post',
data: data
})
}
/**
* @description 删除图组
* @param {Any} data 删除信息对象
* @returns
*/
export const deleteAppCatalog = (data) => {
return request({
url: '/app/appMediaDelete/deleteAppCatalog',
method: 'post',
data: data
})
}
/**
* @description 查询图组详情
* @param {Number} id 图组id
* @returns
*/
export const selectPictureById = (id) => {
return request({
url: `/app/appMediaSelect/selectAppByMaterialId/${id}`,
method: 'post',
data: {}
})
}
/**
* @description 查询组织
* @param {Any} data 组织对象
* @returns
*/
export const selectOrganizeList = (data) => {
data.moduleCode = import.meta.env.VITE_APP_VISITOR_CODE
return request({
url: '/html/htmlMediaSelect/selectHtmlOrganizeList',
method: 'post',
data: data
})
}
import request from '@/utils/request'
/**
* @description 专题标签列表查询
* @param {Any} data 标签对象
* @returns
*/
export const selectTagsList = (data) => {
return request({
url: '/app/appMediaSelect/selectAppTagList',
method: 'post',
data: data
})
}
/**
* @description 专题列表查询
* @param {Any} page 分页对象
* @param {Any} data 标签对象
* @returns
*/
export const selectSubjectList = (page,data) => {
return request({
url: `/app/appMediaSelect/selectAppMediaByTagNamePage/${page.pageNum}/${page.pageSize}`,
method: 'post',
data: data
})
}
\ No newline at end of file
This diff is collapsed.
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createRouter: typeof import('uni-mini-router')['createRouter']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onError: typeof import('@dcloudio/uni-app')['onError']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onHide: typeof import('@dcloudio/uni-app')['onHide']
const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
const onMounted: typeof import('vue')['onMounted']
const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
const onReady: typeof import('@dcloudio/uni-app')['onReady']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onResize: typeof import('@dcloudio/uni-app')['onResize']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
const onShow: typeof import('@dcloudio/uni-app')['onShow']
const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const showToast: typeof import('vant/es')['showToast']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useLink: typeof import('vue-router')['useLink']
const useRoute: typeof import('uni-mini-router')['useRoute']
const useRouter: typeof import('uni-mini-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
const xma: typeof import('rexma-cli')['xma']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {
}
}
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
export function useInitScroll() {
// 记录离开时导航条的位置
let scrollY = ref();
// 离开路由时的钩子函数
onBeforeRouteLeave((to, from, next) => {
// 记录当前的滚动条位置
scrollY.value =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
next()
})
onActivated(() => {
nextTick(() => { }).then(() => {
window.scroll(0, scrollY.value);
})
})
}
\ No newline at end of file
import { createSSRApp } from "vue";
import App from "./App.vue";
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import router from "./router";
import Vconsole from "vconsole";
import 'vant/es/toast/style'
import 'vant/es/dialog/style'
import 'vant/es/notify/style'
import 'vant/es/image-preview/style'
export function createApp() {
const app = createSSRApp(App);
const pinia = createPinia()
pinia.use(piniaPersist)
app.use(pinia)
app.use(router);
let vConsole = new Vconsole();
app.use(vConsole);
return {
app,
};
}
// #ifdef H5
console.log('当前基准平台:H5')
// #endif
// #ifdef H5-SGY
console.log('当前扩展平台:H5-SGY')
// #endif
{
"name" : "",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
"sdkConfigs" : {}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics": {
"enable": false
},
"vueVersion" : "3",
"h5" : {
"router" : {
"base" : "./",
"mode" : "hash"
},
"sdkConfigs" : {
"maps" : {
"qqmap" : {
"key" : "MN4BZ-7JXKW-2RYRD-32QGF-AHONV-PAFUN"
}
}
},
"optimization" : {
"treeShaking" : {
"enable" : true
}
}
}
}
{
"easycom": {
"autoscan": true,
"custom": {
"^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue"
}
},
"pages": [ // pages 数组中第一项表示应用启动页
{
"path": "pages/home/index",
"name": "home",
"style": {
"navigationBarTitleText": "甲秀图库"
}
},
{
"path": "pages/classify/index",
"name": "classify",
"style": {
"navigationBarTitleText": "分类",
"navigationStyle": "custom"
}
},
{
"path": "pages/mine/index",
"name": "mine",
"style": {
"navigationBarTitleText": "个人中心"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/home/content",
"name": "home-content",
"style": {
"navigationBarTitleText": "图组详情"
}
},
{
"path": "pages/publish/index",
"name": "publish",
"style": {
"navigationBarTitleText": "图组发布"
}
},
{
"path": "pages/publish/result",
"name": "publish-result",
"style": {
"navigationBarTitleText": "发布结果"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/prefecture/index",
"name": "prefecture",
"style": {
"navigationBarTitleText": "专区"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/subject/index",
"name": "subject",
"style": {
"navigationBarTitleText": "专题"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/subject/list",
"name": "subject-list",
"style": {
"navigationBarTitleText": "专题列表"
},
"meta": {
"requireAuth": true
}
},
{
"path": "pages/account/login",
"name": "account-login",
"style": {
"navigationBarTitleText": "登录"
}
},
{
"path": "pages/account/userinfo",
"name": "account-userinfo",
"style": {
"navigationBarTitleText": "用户信息"
},
"meta": {
"requireAuth": true
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#fff",
"backgroundColor": "#F8F8F8",
"app-plus": {
"background": "#efeff4"
}
},
"tabBar": {
"color": "#707070",
"selectedColor": "#0E7CE3",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/home/index",
"iconPath": "static/image/home.png",
"selectedIconPath": "static/image/home-select.png",
"text": "首页"
}, {
"pagePath": "pages/classify/index",
"iconPath": "static/image/classify.png",
"selectedIconPath": "static/image/classify-select.png",
"text": "分类"
}, {
"pagePath": "pages/mine/index",
"iconPath": "static/image/mine.png",
"selectedIconPath": "static/image/mine-select.png",
"text": "我的"
}]
}
}
<template>
<!-- <van-nav-bar title="登录" :left-arrow="true" fixed placeholder safe-area-inset-top @click-left="router.go(-1)" /> -->
<div class="warp clearfloat">
<div class="login-top clearfloat box-s">
<div class="ge-back"><img src="@/static/image/login.png"></div>
<div class="logo-imgs">
<img src="@/static/image/login-circle.png">
</div>
</div>
</div>
<div class="tab-account">
<!-- <ul class="nav nav-tabs login-tabs">
<li :class="{ active: activeIndex == 0 }" @click="activeIndex = 0">
<a data-toggle="tab">登录</a>
</li>
<li :class="{ active: activeIndex == 1 }" @click="activeIndex = 1">
<a data-toggle="tab">注册</a>
</li>
</ul> -->
<div class="tab-content">
<div class="tab-pane fade" v-if="activeIndex == 0">
<form>
<div class="form-group login-group_re">
<i class="iconfont icon-shoujihaoma"></i>
<input type="text" v-model="formData.account" class="form-control inpt-form"
placeholder="请输入手机号" :rules="[{ required: true, message: '请输入手机号' }]">
</div>
<div class="form-group login-group_re">
<i class="iconfont icon-mima"></i>
<input v-model="formData.password" class="form-control inpt-form" type="password"
placeholder="请输入密码" v-if="!passwordVisible">
<input v-model="formData.password" class="form-control inpt-form" type="text"
placeholder="请输入密码" v-else>
<i class="icon-icon-test iconfont xian-mi icon-icon-test" @click="passwordVisible = true"
v-if="!passwordVisible"></i>
<i class="iconfont xian-mi icon-close-eye" @click="passwordVisible = false" v-else></i>
</div>
<div class="login-btns">
<van-button class="btn" type="primary" round @click="login">登录</van-button>
<!-- #ifdef H5-SGY -->
<van-button class="btn" plain type="primary" round
@click="fastLoginBySgy">爽贵阳用户快捷登录</van-button>
<!-- #endif -->
</div>
</form>
</div>
<div class="tab-pane fade in active" v-if="activeIndex == 1">
<form role="form">
<div class="form-group login-group_re">
<i class="iconfont icon-shoujihaoma"></i>
<input type="text" class="form-control inpt-form" placeholder="请输入手机号">
</div>
<div class="form-group login-group_re">
<i class="iconfont icon-yanzhengma2"></i>
<input type="tel" class="form-control inpt-form" placeholder="请输入手机号验证码">
<a href="javascript:;" data-appid="2034800824" data-cbfn="callback"
class="linkABlue yanzheng">获取验证码</a>
</div>
<div class="form-group login-group_re">
<i class="iconfont icon-mima"></i>
<input data-toggle="password" class="form-control inpt-form" type="password"
placeholder="请输入密码">
</div>
<button type="button" class="conf-btn login-btns">注册</button>
</form>
</div>
</div>
</div>
</template>
<script setup>
import { showToast, showLoadingToast, closeToast } from 'vant'
import { loginByPassword, loginBySgy } from '@/api/account'
import useUserStore from '@/store/user'
const router = useRouter()
const userStore = useUserStore()
const activeIndex = ref(0)
const passwordVisible = ref(false)
const formData = ref({
account: '',
password: ''
})
const login = async () => {
if (!formData.value.account) {
showToast('请输入用户名')
return
}
if (!formData.value.password) {
showToast('请输入密码')
return
}
showLoadingToast({
message: '登录中',
forbidClick: true,
duration: 0
})
const res = await loginByPassword(formData.value)
userStore.login(res)
closeToast()
showToast('登录成功')
router.pushTab({ name: 'home' })
}
const sgyLoginParams = ref({
appid: import.meta.env.VITE_APP_SGY_APPID,
type: "sgy",
encryptDataMap: {}
})
const fastLoginBySgy = () => {
xma.xh.getUserProfile({
range: ['ACCOUNT', 'MOBILE', 'CITIZEN'],
async success(info) {
console.log(info)
showLoadingToast({
message: '登录中',
forbidClick: true,
duration: 0
})
sgyLoginParams.value.encryptDataMap = info.data
const res = await loginBySgy(sgyLoginParams.value)
console.log(res)
userStore.login(res)
closeToast()
xma.showToast({
title: '登录成功',
icon: 'success'
})
router.pushTab({ name: 'home' })
}
});
}
</script>
<style scoped>
@import url('@/assets/iconfont/iconfont.css');
.clearfloat:after {
display: block;
clear: both;
content: "";
visibility: hidden;
height: 0
}
.clearfloat {
zoom: 1
}
.box-s {
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.tab-account .login-tabs {
display: flex;
justify-content: center;
}
.tab-account .login-tabs li {
width: 50%;
text-align: center;
}
.tab-account {
background-color: #fff;
padding: 0;
margin-top: 11%;
}
.tab-account .nav-tabs {
padding: 0 0.4rem;
border-bottom: none !important;
}
.tab-account .nav-tabs li {
width: 35%;
text-align: center;
}
.nav-tabs>li>a {
color: #000;
font-size: 0.45rem;
}
.nav>li>a {
position: relative;
display: block;
padding: 10px 15px;
}
.tab-account .nav-tabs>li.active>a,
.nav-tabs>li.active>a:focus,
.nav-tabs>li.active>a:hover {
color: #4C82FF;
border-color: transparent;
border-bottom: 2px solid #4C82FF !important;
background-color: transparent;
}
.tab-account .tab-content {
margin-top: 10px;
background: #fff;
padding: 0.4rem;
}
.form-control:focus,
.form-control:active,
.form-control:hover {
border-color: #1890ff !important;
box-shadow: none;
}
.conf-btn {
width: 100%;
padding: 10px 20px !important;
border-radius: 50px !important;
border: none;
background: #4c82ff !important;
color: #fff;
font-size: 0.48rem;
}
.login-top {
width: 100%;
height: 6.8rem;
}
.login-top .ge-back img {
width: 100%;
height: 6.4rem;
display: block;
margin: 0 auto;
}
.logo-imgs {
position: relative;
left: 44%;
top: -27%;
width: 3rem;
height: 3rem;
text-align: center;
background: #fff;
border-radius: 16px;
-moz-box-shadow: 2px 2px 5px rgba(76, 130, 255, .4);
-webkit-box-shadow: 2px 2px 5px rgba(76, 130, 255, .4);
box-shadow: 2px 2px 5px rgba(76, 130, 255, .4);
}
.logo-imgs img {
width: 2.2rem;
height: 2.2rem;
margin: 0.4rem 0;
}
.login-group_re {
display: flex;
gap: 10px;
margin-bottom: 3%;
}
.login-group_re i {
line-height: 37px;
color: #4C82FF;
font-size: 1rem;
background: #fff;
}
.login-group_re .input-group-addon {
padding: 0;
background-color: transparent;
border: none;
border-radius: none;
}
.login-group_re .input-group {
width: 100%;
}
.login-group_re .xian-mi {
color: #8a8a8a;
}
.login-group_re .inpt-form {
flex: 1;
border: none !important;
border-bottom: solid 1px #EEE !important;
height: 40px;
outline: none;
line-height: 40px;
background-color: #FFF;
}
.login-group_re .inpt-form:focus {
border-bottom: 1px solid #4C82FF !important;
}
.yanzheng {
line-height: 40px;
color: #4C82FF;
font-size: 0.4rem;
width: 2.5rem;
text-align: center;
font-size: 0.4rem;
}
.yanzheng:focus,
.yanzheng:hover,
.yanzheng:active {
color: #4c82ff;
}
.login-wang {
display: flex;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
justify-content: space-between;
margin-top: 3%;
}
.login-wang a {
font-size: 0.4rem;
}
.login-btns {
margin-top: 4%;
width: 100%;
gap: 15px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.btn {
width: 100%;
}
</style>
\ No newline at end of file
<template>
<van-nav-bar title="用户中心" :left-arrow="true" border fixed placeholder safe-area-inset-top
@click-left="router.go(-1)" />
<div class="container">
<div class="content">
<div class="item">
<van-icon name="friends-o" size="26" />
<div class="title">用户名</div>
<div class="text">
<div>{{ userStore.userinfo?.user.name }}</div>
<van-icon name="arrow" size="18" color="#d1d1d1" />
</div>
</div>
<div class="item">
<van-icon name="phone-o" size="26" />
<div class="title">手机号码</div>
<div class="text">
<div>{{ userStore.userinfo?.user.phone }}</div>
<van-icon name="arrow" size="18" color="#d1d1d1" />
</div>
</div>
<div class="item">
<van-icon name="envelop-o" size="26" />
<div class="title">邮箱</div>
<div class="text">
<div>{{ userStore.userinfo?.user.email }}</div>
<van-icon name="arrow" size="18" color="#d1d1d1" />
</div>
</div>
</div>
<div class="logout">
<van-button type="warning" block @click="logout">退出登录</van-button>
</div>
</div>
</template>
<script setup>
import { showConfirmDialog, showToast } from 'vant'
import useUserStore from "@/store/user"
const router = useRouter()
const userStore = useUserStore()
const logout = () => {
showConfirmDialog({
title: '提示',
message:
'确定退出登录吗',
}).then(() => {
userStore.logout()
showToast('退出登录成功')
router.go(-1)
}).catch(() => {
})
}
</script>
<style lang="scss" scoped>
.container {
padding: 15px 10px;
.content {
background-color: #ffffff;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
border-radius: 5px;
.item {
display: flex;
align-items: center;
gap: 10px;
padding: 15px;
border-bottom: 1px solid #e8e8e8;
.title {
flex: 1;
font-size: 16px;
}
.text {
display: flex;
gap: 10px;
font-size: 16px;
color: #0E7CE3;
}
}
}
.logout {
margin-top: 20px;
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.1);
}
}
</style>
\ No newline at end of file
<template>
<div class="bg">
<van-sticky>
<div class="header">
<div class="title">分类</div>
<div class="search">
<div class="s-box">
<van-icon name="search" color="#303030" />
<input class="placeholder" placeholder="请输入关键词" v-model="value" />
</div>
<van-icon v-if="value" name="clear" color="#969696" />
</div>
</div>
</van-sticky>
<div class="content">
<div class="list">
<div class="item" v-for="(item, index) in 20" :key="index">
<img src="/static/image/cover-1.png">
<div class="blurbox">
<div class="bg"></div>
<div class="title">XXX专题</div>
</div>
</div>
<div class="item">
<img src="/static/image/cover-2.png">
<div class="blurbox">
<div class="bg"></div>
<div class="title">XXX专题</div>
</div>
</div>
<div class="item">
<img src="/static/image/cover-3.png">
<div class="blurbox">
<div class="bg"></div>
<div class="title">XXX专题</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
const value = ref('')
</script>
<style scoped lang="scss">
.bg {
height: 100vh;
background: linear-gradient(to bottom, #D2E4FF 5%, #fff 25%);
.header {
display: flex;
align-items: center;
padding: 0 20px;
height: 50px;
gap: 15px;
background-color: #D2E4FF;
.title {
font-size: 18px;
font-weight: bold;
}
.search {
width: 45%;
background-color: #F7F8FA;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
opacity: 0.7;
padding: 0 10px;
.s-box {
display: flex;
align-items: center;
gap: 5px;
.placeholder {
color: #303030;
font-size: 14px;
}
}
}
}
.content {
padding: 10px 10px 0 10px;
min-height: 100vh;
.list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.item {
break-inside: avoid;
background-color: #ffffff;
border-radius: 5px;
margin-bottom: 10px;
width: 32%;
position: relative;
img {
width: 100%;
height: 170px;
object-fit: cover;
border-radius: 5px;
}
.blurbox {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
bottom: 0;
height: 32px;
width: 100%;
border-radius: 0 0 5px 5px;
.bg {
position: absolute;
border-radius: 0 0 5px 5px;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(10px);
}
.title {
font-size: 28rpx;
color: #fff;
font-weight: bold;
z-index: 1;
}
}
}
}
}
}
</style>
<template>
<van-popup v-model:show="show" position="bottom" :close-on-click-overlay="false" safe-area-inset-bottom @close="handleClose">
<div class="container">
<div class="header-placeholder">
<div class="header">
<span class="reset" @click="handleReset">重置</span>
<span class="confirm" @click="handleConfirm">确认</span>
</div>
</div>
<div class="content">
<div class="item" v-for="(item, index) in dataList" :key="index"
:class="{ active: selectItemIndex == index }" @click="selectItemIndex = index">
<span>{{ item.sourceName }}</span>
</div>
</div>
</div>
</van-popup>
</template>
<script setup>
import { selectSourceList } from '@/api/publish';
const emits = defineEmits(["confirm", "close"])
const dataList = ref([])
const getList = async () => {
const res = await selectSourceList(2)
dataList.value = res.data
}
getList()
const selectItemIndex = ref(null)
const handleConfirm = () => {
emits('confirm', dataList.value[selectItemIndex.value])
show.value = false
}
const handleReset = () => {
selectItemIndex.value = null
}
const handleClose = () => {
emits('close')
}
const show = ref(false)
const open = () => {
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.container {
max-height: 50vh;
padding: 0 20px;
.header-placeholder {
height: 55px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
position: fixed;
width: calc(100vw - 40px);
height: 55px;
background-color: #ffffff;
color: #545454;
.confirm {
color: #0e7ce3;
}
}
}
.content {
display: flex;
flex-wrap: wrap;
gap: 15px;
padding-bottom: 15px;
.item {
background-color: #eef1f3;
flex: 0 0 calc((100vw - 70px) / 3);
padding: 15px 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
color: #676767;
font-size: 15px;
span {
max-width: 80%;
}
}
.active {
background-color: #0e7ce3;
color: #ffffff;
}
}
}
</style>
\ No newline at end of file
<template>
<van-popup v-model:show="show" position="bottom" :close-on-click-overlay="false" safe-area-inset-bottom @close="handleClose">
<div class="container">
<div class="header-placeholder">
<div class="header">
<span class="reset" @click="handleReset">重置</span>
<span class="confirm" @click="handleConfirm">确认</span>
</div>
</div>
<div class="content">
<div class="item" v-for="(item, index) in dataList" :key="index"
:class="{ active: selectItemIndex == index }" @click="selectItemIndex = index">
<span>{{ item.sourceName }}</span>
</div>
</div>
</div>
</van-popup>
</template>
<script setup>
import { selectSourceList } from '@/api/publish';
const emits = defineEmits(["confirm", "close"])
const dataList = ref([])
const getList = async () => {
const res = await selectSourceList(1)
dataList.value = res.data
}
getList()
const selectItemIndex = ref(null)
const handleConfirm = () => {
emits('confirm', dataList.value[selectItemIndex.value])
show.value = false
}
const handleReset = () => {
selectItemIndex.value = null
}
const handleClose = () => {
emits('close')
}
const show = ref(false)
const open = () => {
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.container {
max-height: 50vh;
padding: 0 20px;
.header-placeholder {
height: 55px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
position: fixed;
width: calc(100vw - 40px);
height: 55px;
background-color: #ffffff;
color: #545454;
.confirm {
color: #0e7ce3;
}
}
}
.content {
display: flex;
flex-wrap: wrap;
gap: 15px;
padding-bottom: 15px;
.item {
background-color: #eef1f3;
flex: 0 0 calc((100vw - 70px) / 3);
padding: 15px 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
color: #676767;
font-size: 15px;
span {
max-width: 80%;
}
}
.active {
background-color: #0e7ce3;
color: #ffffff;
}
}
}
</style>
\ No newline at end of file
<template>
<van-popup v-model:show="show" position="bottom" :close-on-click-overlay="false" safe-area-inset-bottom @close="handleClose">
<div class="container">
<div class="header-placeholder">
<div class="header">
<span class="reset" @click="handleReset">重置</span>
<span class="confirm" @click="handleConfirm">确认</span>
</div>
</div>
<van-cascader v-model="activeId" :show-header="false" :options="treeList" :field-names="fieldNames" />
</div>
</van-popup>
</template>
<script setup>
import { selectTagsList } from '@/api/publish'
const emits = defineEmits(["confirm", "close"])
const activeId = ref(null)
const fieldNames = {
text: 'title',
value: 'id',
children: 'children'
}
const treeList = ref([])
const dataList=ref([])
const getList = async () => {
const res = await selectTagsList()
treeList.value = res.data
dataList.value=dealTreeData(res.data)
}
getList()
const dealTreeData = (data) => {
let arrTree = []
data.forEach((ele) => {
let obj = { ...ele }
delete obj.children
arrTree.push(obj)
if (ele?.children?.length) {
arrTree.push(...dealTreeData(ele.children))
}
});
return arrTree;
}
const handleConfirm = () => {
const item = dataList.value.filter(item => item.id == activeId.value)[0]
emits('confirm', item)
show.value = false
}
const handleReset = () => {
activeId.value = null
}
const handleClose = () => {
emits('close')
}
const show = ref(false)
const open = () => {
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.container {
max-height: 50vh;
.header-placeholder {
height: 55px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
position: fixed;
width: calc(100vw - 40px);
height: 55px;
background-color: #ffffff;
color: #545454;
padding: 0 20px;
.confirm {
color: #0e7ce3;
}
}
}
::v-deep(.van-sidebar-item) {
text-align: center;
}
}
</style>
\ No newline at end of file
<template>
<van-popup v-model:show="show" position="bottom" :close-on-click-overlay="false" safe-area-inset-bottom @close="handleClose">
<div class="container">
<div class="header-placeholder">
<div class="header">
<span class="reset" @click="handleReset">重置</span>
<span class="confirm" @click="handleConfirm">确认</span>
</div>
</div>
<div class="content">
<div class="item" v-for="(item, index) in dataList" :key="index"
:class="{ active: selectItemIndex == index }" @click="selectItemIndex = index">
<span>{{ item.classifyType }}</span>
</div>
</div>
</div>
</van-popup>
</template>
<script setup>
import { selectTypeList } from '@/api/publish'
const emits = defineEmits(["confirm", "close"])
const dataList = ref([])
const getList = async () => {
const res = await selectTypeList()
dataList.value = res.data
}
getList()
const selectItemIndex = ref(null)
const handleConfirm = () => {
emits('confirm', dataList.value[selectItemIndex.value])
show.value = false
}
const handleReset = () => {
selectItemIndex.value = null
}
const handleClose = () => {
emits('close')
}
const show = ref(false)
const open = () => {
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.container {
max-height: 50vh;
padding: 0 20px;
.header-placeholder {
height: 55px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
position: fixed;
width: calc(100vw - 40px);
height: 55px;
background-color: #ffffff;
color: #545454;
.confirm {
color: #0e7ce3;
}
}
}
.content {
display: flex;
flex-wrap: wrap;
gap: 15px;
padding-bottom: 15px;
.item {
background-color: #eef1f3;
flex: 0 0 calc((100vw - 70px) / 3);
padding: 15px 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
color: #676767;
font-size: 15px;
span {
max-width: 80%;
}
}
.active {
background-color: #0e7ce3;
color: #ffffff;
}
}
}
</style>
\ No newline at end of file
<template>
<!-- <van-nav-bar title="图组详情" :left-arrow="true" fixed placeholder safe-area-inset-top @click-left="router.go(-1)" /> -->
<div class="container" v-if="catalog">
<div class="info">
<div class="header">
<div class="user">
<img class="avatar" src="../../static/image/avatar-content.png">
<div class="username">{{ catalog.author }}</div>
</div>
<div class="collect">
<van-button icon="plus" loading-size="14" type="primary">收藏</van-button>
</div>
</div>
<div class="tags">
<div class="item" v-for="(tagName, index) in catalog.tagName.split(',')" :key="index">
<span class="tag">{{ tagName }}</span>
</div>
</div>
<div class="content">
<van-row :gutter="[0, 10]">
<van-col span="12">
<div class="item">
<div class="label">渠道:</div>
<div class="value">
<span class="tag">{{ catalog.sourceName }}</span>
</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">类型:</div>
<div class="value">
<span class="tag">{{ catalog.sourceDitch }}</span>
</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">创建人:</div>
<div class="value">{{ catalog.createBy }}</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">组织:</div>
<div class="value">
<van-text-ellipsis :content="catalog.organizeName" />
</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">创建时间:</div>
<div class="value">{{ dayjs(catalog.createtime).format('YYYY-MM-DD') }}</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">数量:</div>
<div class="value">{{ catalog.fileNum }}</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">拍摄时间:</div>
<div class="value">{{ dayjs(catalog.shoottime).format('YYYY-MM-DD') }}</div>
</div>
</van-col>
<van-col span="12">
<div class="item">
<div class="label">大小:</div>
<div class="value">{{ catalog.fileSize }}KB</div>
</div>
</van-col>
<van-col span="24">
<div class="item">
<div class="label">拍摄地点:</div>
<div class="value">{{ catalog.shootLocation }}</div>
</div>
</van-col>
</van-row>
</div>
</div>
<div class="atlas">
<div class="title">{{ catalog.materialTitle }}</div>
<div class="atlas-desc">{{ catalog.materialIntro }}</div>
<div class="list">
<div class="item" v-for="(item, index) in catalog.enclosureList" :key="index">
<img :src="fileDomain + item.compressPath" @click="handlePreviewImage(index)">
<div class="item-desc">
{{ item.enclosureDesc }}
</div>
<div class="item-info">
<!-- <span>808x539</span> -->
<span>{{ item.fileSize }}KB</span>
</div>
</div>
</div>
</div>
</div>
<van-empty description="暂无数据" v-else />
</template>
<script setup>
import dayjs from 'dayjs'
import { showImagePreview } from 'vant';
import { selectPictureById } from '@/api/publish'
const fileDomain = import.meta.env.VITE_APP_FILE_URL
const previewImages = ref([])
const id = ref(0)
onLoad((options) => {
id.value = options.id
handleSelect()
})
const catalog = ref(null)
const handleSelect = async () => {
const res = await selectPictureById(id.value)
catalog.value = res.data
previewImages.value = res.data.enclosureList.map(item => {
return fileDomain + item.watermarkPath
})
}
const handlePreviewImage = (index) => {
showImagePreview({
images: previewImages.value,
startPosition: index,
});
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f6f6f6;
padding: 15px 10px;
display: flex;
flex-direction: column;
gap: 15px;
height: 100vh;
.info {
background-color: #ffffff;
border-radius: 5px;
padding: 20px 15px;
display: flex;
flex-direction: column;
gap: 20px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
.header {
display: flex;
align-items: center;
justify-content: space-between;
.user {
display: flex;
align-items: center;
gap: 10px;
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
}
.username {
font-size: 17px;
}
}
.collect {
:deep(.van-button--normal) {
padding: 0 5px;
width: 70px;
height: 35px;
font-size: 15px;
.van-button__icon {
font-size: 14px;
}
}
}
}
.tags {
display: flex;
gap: 10px;
flex-wrap: wrap;
font-size: 15px;
}
.content {
font-size: 14px;
.item {
display: flex;
color: #6e737e;
.label {
// width: 75px;
}
.value {
flex: 1;
}
}
}
}
.atlas {
background-color: #ffffff;
border-radius: 10px;
padding: 20px 15px;
display: flex;
flex-direction: column;
gap: 10px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
.title {
font-size: 20px;
overflow-wrap: break-word;
white-space: normal;
}
.atlas-desc {
line-height: 30px;
color: #707070;
font-size: 15px;
overflow-wrap: break-word;
white-space: normal;
}
.list {
column-count: 2;
column-gap: 10px;
.item {
break-inside: avoid;
margin-bottom: 10px;
img {
width: 100%;
object-fit: cover;
}
.item-desc {
font-size: 15px;
color: #707070;
line-height: 25px;
overflow-wrap: break-word;
white-space: normal;
}
.item-info {
font-size: 13px;
color: #707070;
margin-top: 5px;
display: flex;
justify-content: space-between;
}
}
}
}
.tag {
color: #4c70ac;
background-color: #f3f8fe;
padding: 5px 10px;
}
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<!-- #ifdef MP-WEIXIN -->
<view class="container">微信小程序环境</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="container">H5环境</view>
<!-- #endif -->
<!-- #ifdef APP -->
<view class="container">APP环境</view>
<!-- #endif -->
<!-- <van-tabbar v-model="active" :placeholder="true" active-color="#0E7CE3" route>
<van-tabbar-item icon="home-o" to="/home">首页</van-tabbar-item>
<van-tabbar-item icon="apps-o" to="/prefecture">专区</van-tabbar-item>
<van-tabbar-item icon="send-gift-o" to="/subject">专题</van-tabbar-item>
<van-tabbar-item icon="user-o" to="/mine">我的</van-tabbar-item>
</van-tabbar> -->
</template>
<script setup>
import {
ref
} from 'vue'
const active = ref('/home')
// #ifdef H5
console.log('当前环境为H5') // 这里可以编写H5环境的代码逻辑
// #endif
// #ifdef APP
console.log('当前环境为APP') // 这里可以编写APP环境的代码逻辑
// #endif
</script>
<style scoped></style>
\ No newline at end of file
<template>
<van-popup v-model:show="show" position="bottom" round @close="handleClose">
<div class="more">
<div class="item" @click="handleUpdate">编辑图组</div>
<div class="item delete" @click="handleDelete">删除图组</div>
<div class="item" @click="handleClose">取消</div>
</div>
</van-popup>
</template>
<script setup>
import { ref } from 'vue'
import { deleteAppCatalog } from '@/api/publish'
import { showConfirmDialog } from 'vant'
import useUserStore from '@/store/user'
const userStore = useUserStore()
const emits = defineEmits(["refresh"])
const catalog = reactive({
userId: null,
materialId: '',
delBy: ''
})
const handleClose = () => {
show.value = false
}
const handleDelete = () => {
showConfirmDialog({
title: '删除图组',
message: '确定删除该图组吗?',
})
.then(() => {
catalog.userId = userStore.userinfo.user.id
catalog.materialId = pictrueInfo.value.materialId
catalog.delBy = userStore.userinfo.user.name
deleteAppCatalog(catalog).then(res => {
showToast('删除成功')
emits('refresh')
handleClose()
})
})
}
const handleUpdate = () => {
console.log('编辑')
}
const pictrueInfo = ref(null)
const show = ref(false)
const open = (e) => {
console.log(e)
pictrueInfo.value = e
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.more {
padding: 10px;
.delete {
color: #E23535;
}
.item {
padding: 10px 0;
text-align: center;
border-bottom: 1px solid #eee;
&:last-child {
border-bottom: none;
}
}
}
</style>
\ No newline at end of file
<template>
<van-pull-refresh v-model="refreshing" @refresh="handleRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" :offset="50" @load="getList"
v-if="dataList.length">
<div class="list">
<div class="item" v-for="(item, index) in dataList" :key="index">
<img :src="fileDomain + item.coverpicture"
@click="router.push({ name: 'home-content', params: { id: item.materialId } })">
<div class="desc">
<span class="title">
<van-text-ellipsis :content="item.materialTitle" />
</span>
<div class="tag">
<span v-for="(tagName, index) in item.tagName.split(',')" :key="index">{{
tagName }}</span>
</div>
<div class="info">
<van-button type="primary" size="mini" block @click="handlePublishPicture(item)"
v-if="active == 0">立即发布</van-button>
<div class="user" v-else>
<div class="user-box">
<img src="@/static/image/avatar.png">
<span>{{ item.author }}</span>
</div>
<div v-if="active == 1">
<van-icon name="ellipsis" size="26" color="#545454" @click="handleMore(item)" />
</div>
<div v-if="active == 2">
<van-icon name="star" color="#F1C13E" />
</div>
</div>
</div>
</div>
</div>
</div>
</van-list>
<van-empty description="暂无数据" v-else />
</van-pull-refresh>
</template>
<script setup>
import useUserStore from '@/store/user'
import { selectMinePictureList, selectCollectPictureList } from '@/api/publish'
const props = defineProps({
active: {
type: Number,
default: 0
}
})
const emits = defineEmits(["total", "refresh", "opreation", "publish"])
const router = useRouter()
const userStore = useUserStore()
const refreshing = ref(false)
const loading = ref(false)
const finished = ref(true)
const fileDomain = import.meta.env.VITE_APP_FILE_URL
const page = reactive({
pageNum: 0,
pageSize: 10
})
const catalog = reactive({
userId: null,
materialTitle: '',
collect: 1,
materialType: 3,
typeClassify: '',
sourceName: '',
organizeInt: [],
tagId: '',
beginTime: '',
endTime: ''
})
const dataList = ref([])
const getList = async () => {
page.pageNum++
loading.value = true
catalog.userId = userStore.userinfo.user.id
catalog.collect = props.active == 0 ? 0 : 1
let res = null
if (props.active == 2) {
res = await selectCollectPictureList(page, catalog)
} else {
res = await selectMinePictureList(page, catalog)
}
setDataList(res)
emits('total', { activeIndex: props.active, value: res.data.total })
}
const setDataList = (res) => {
if (refreshing.value) {
dataList.value = res.data.list
} else {
dataList.value.push(...res.data.list)
}
loading.value = false
finished.value = dataList.value.length >= res.data.total
refreshing.value = false
}
getList()
const handleRefresh = () => {
refreshing.value = true
page.pageNum = 0
getList()
}
const handleMore = (e) => {
emits('opreation', e)
}
const handlePublishPicture = (e) => {
emits('publish', e)
}
defineExpose({
refresh: handleRefresh
})
</script>
<style lang="scss" scoped>
.list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-top: 20px;
.item {
break-inside: avoid;
background-color: #ffffff;
border-radius: 5px;
margin-bottom: 10px;
width: 49%;
img {
width: 100%;
height: 150px;
object-fit: cover;
}
.desc {
padding: 5px 10px;
display: flex;
flex-direction: column;
gap: 5px;
.title {
font-size: 16px;
}
.tag {
display: flex;
flex-wrap: wrap;
gap: 3px;
span {
font-size: 14px;
padding: 0 5px;
background-color: #F3F8FF;
color: #4C70AC;
font-size: 12PX;
border-radius: 3px;
}
}
.info {
display: flex;
justify-content: space-between;
padding: 5px 0;
.user {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.user-box {
display: flex;
gap: 7px;
align-items: center;
img {
width: 23px;
height: 23px;
border-radius: 50%;
}
span {
color: #9F9F9F;
font-size: 12px;
}
}
}
}
.collect {
display: flex;
align-items: center;
gap: 3px;
span {
color: #9F9F9F;
font-size: 12px;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<van-popup v-model:show="showPublish" round position="bottom" closeable>
<div class="popbox">
<div class="title">发布图组</div>
<van-form @submit="handleSubmit" required colon>
<van-field v-model="formData.organizeName" is-link readonly name="picker" label="选择组织"
placeholder="请选择组织" @click="showOrganize = true" :rules="[{ required: true, message: '请选择组织' }]" />
<div class="btn">
<van-button round type="primary" native-type="submit" size="small">立即发布</van-button>
</div>
</van-form>
</div>
</van-popup>
<van-popup v-model:show="showOrganize" round position="bottom">
<van-cascader v-model="formData.organizeName" title="请选择组织" :options="options" :field-names="fieldNames"
@close="showOrganize = false" @finish="onFinish" />
</van-popup>
</template>
<script setup>
import useUserStore from '@/store/user'
import { publishPicture } from '@/api/publish'
import { selectOrganizeList } from '@/api/prefecture'
import { showLoadingToast, closeToast, showToast } from 'vant'
const emits = defineEmits(["refresh"])
const userStore = useUserStore()
const dataList = ref([])
const options = ref([])
const getList = async () => {
const data = {
userId: userStore.userinfo.user.id,
sysCode: import.meta.env.VITE_APP_SYSTEM_CODE,
moduleCode: 'practice-mediaCatalog'
}
const res = await selectOrganizeList(data)
dataList.value = res.data
options.value = buildTree(res.data)
}
const formData = ref({
materialId: null,
organizeId: '',
organizeName: '',
collect: 1
})
const showOrganize = ref(false)
const fieldNames = {
text: 'organName',
value: 'id',
children: 'children',
};
const buildTree = (items) => {
const tree = [{
id: '0',
organName: '无组织',
children: []
}]
const lookup = {}
// 初始化lookup对象,方便后续快速查找
items.forEach(item => {
lookup[item.id] = { ...item, id: item.id.toString(), children: [] };
});
// 构建树
items.forEach(item => {
if (item.superiorId == 0) {
// superiorId=0的项是顶级项
tree.push(lookup[item.id]);
} else {
// 否则,添加到对应父节点的children数组中
if (!lookup[item.superiorId]) {
// 如果父节点不存在(理论上不应该发生,除非数据有误),可以创建一个空的占位符
lookup[item.superiorId] = { children: [] };
}
lookup[item.superiorId].children.push(lookup[item.id]);
}
});
return removeEmptyChildren(tree)
}
const removeEmptyChildren = (nodes) => {
nodes.forEach(node => {
if (node.children.length === 0) {
delete node.children;
} else {
removeEmptyChildren(node.children);
}
});
return nodes
}
// 全部选项选择完毕后,会触发 finish 事件
const onFinish = ({ selectedOptions }) => {
showOrganize.value = false;
console.log(selectedOptions)
formData.value.organizeId = selectedOptions[selectedOptions.length - 1].id
formData.value.organizeName = selectedOptions[selectedOptions.length - 1].organName
};
const handleSubmit = async () => {
showLoadingToast({
message: '发布中',
forbidClick: true,
duration: 0
})
await publishPicture(formData.value)
closeToast()
showToast('发布成功')
showPublish.value = false
emits('refresh')
}
const showPublish = ref(false)
const open = (e) => {
console.log(e)
formData.value.materialId = e.materialId
showPublish.value = true
getList()
}
const close = () => {
showPublish.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.popbox {
padding: 20px;
.title {
font-size: 18px;
font-weight: bold;
margin-bottom: 20px;
}
.btn {
width: 100%;
display: flex;
justify-content: center;
margin-top: 20px;
.van-button {
width: 100%;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="container" v-if="userStore.isLogin">
<div class="userinfo">
<img class="avatar" mode="aspectFill"
:src="fileDomain + userStore.userinfo.user.headSculpturePhoto ?? '../../static/image/avatar-content.png'"
@click="router.push({ name: 'account-userinfo' })">
<div class="user">
<div class="nickname">{{ userStore.userinfo.user.name }}</div>
<div class="section">
{{ userStore.userinfo.organizeList[0]?.organName ?? '未知部门' }}
</div>
</div>
<div class="exit">
<img src="../../static/image/exit.png" @click="logout">
</div>
</div>
<div class="menu">
<div class="status">
<div class="item">
<div class="num">{{ total[0] }}</div>
<div class="text">待发布</div>
</div>
<div class="item">
<div class="num">{{ total[1] }}</div>
<div class="text">已发布</div>
</div>
<div class="item">
<div class="num">{{ total[2] }}</div>
<div class="text">收藏</div>
</div>
</div>
<van-button type="primary" icon="guide-o" size="small"
@click="router.push({ name: 'publish' })">新建图组</van-button>
</div>
<div class="edit">
<van-button plain type="default" round block
@click="router.push({ name: 'account-userinfo' })">编辑资料</van-button>
</div>
<div class="area">
<div class="a-prefecture a-box" @click="router.push({ name: 'prefecture' })">
<div class="a-text">专区</div>
</div>
<div class="a-subject a-box" @click="router.push({ name: 'subject' })">
<div class="a-text">专题</div>
</div>
</div>
<div class="content">
<van-tabs v-model:active="active" background="#f8f8f8" animated swipeable sticky>
<van-tab title="待发布">
<picture-list ref="waitingPublishPicture" :active="0" @total="setTotal" @refresh="handleRefreshPublishPicture" @publish="handlePublishPicture"></picture-list>
</van-tab>
<van-tab title="已发布">
<picture-list ref="publishPicture" :active="1" @total="setTotal" @opreation="handleOperation"></picture-list>
</van-tab>
<van-tab title="收藏">
<picture-list :active="2" @total="setTotal"></picture-list>
</van-tab>
</van-tabs>
</div>
</div>
<MoreOperations ref="morePopupRef" @refresh="handleRefreshPublishPicture"></MoreOperations>
<Publish ref="publishPopupRef" @refresh="handleRefreshWaitingPublishPicture"></Publish>
</template>
<script setup>
import { showConfirmDialog, showToast } from 'vant'
import useUserStore from '@/store/user'
import PictureList from './components/PictureList'
import { useInitScroll } from '@/hooks/useScroll'
import MoreOperations from './components/MoreOperations/index.vue'
import Publish from './components/Publish/index.vue'
useInitScroll()
const router = useRouter()
const userStore = useUserStore()
const active = ref(0)
const fileDomain = import.meta.env.VITE_APP_FILE_URL
const total = reactive({
0: 0,
1: 0,
2: 0
})
onShow(() => {
toLogin()
})
const toLogin = () => {
if (userStore.isLogin())
return
router.push({ name: 'account-login' })
}
const setTotal = (e) => {
total[e.activeIndex] = e.value
}
const publishPicture = ref()
const handleRefreshPublishPicture = () => {
publishPicture.value.refresh()
}
const publishPopupRef = ref()
const handlePublishPicture = (e) => {
publishPopupRef.value.open(e)
}
const waitingPublishPicture = ref()
const handleRefreshWaitingPublishPicture = () => {
handleRefreshPublishPicture()
waitingPublishPicture.value.refresh()
}
const logout = () => {
showConfirmDialog({
title: '提示',
message:
'确定退出登录吗',
}).then(() => {
userStore.logout()
showToast('退出登录成功')
router.push({ name: 'account-login' })
}).catch(() => {
})
}
const morePopupRef = ref()
const handleOperation = (e) => {
morePopupRef.value.open(e)
}
</script>
<style lang="scss" scoped>
.container {
background-color: #f8f8f8;
padding: 38px 12px 0 12px;
min-height: 100vh;
.userinfo {
display: flex;
.avatar {
width: 58px;
height: 58px;
border-radius: 50%;
}
.user {
flex: 1;
margin-left: 16px;
display: flex;
flex-direction: column;
justify-content: space-around;
overflow: hidden;
.nickname {
font-size: 19px;
color: #232524;
}
.section {
width: max-content;
height: 20px;
padding: 0 10px;
line-height: 22px;
text-align: center;
color: #ffffff;
font-size: 13px;
background-color: #232524;
border-radius: 4px;
max-width: calc(100% - 20px);
}
}
.exit {
display: flex;
align-items: center;
img {
width: 28px;
height: 28px;
}
}
}
.menu {
display: flex;
margin-top: 30px;
.status {
display: flex;
flex: 1;
gap: 25px;
.item {
text-align: center;
.num {
font-size: 15px;
}
.text {
font-size: 10px;
color: #707070;
}
}
}
}
.edit {
margin-top: 20px;
.van-button {
background: #f8f8f8;
}
}
.area {
display: flex;
justify-content: space-between;
margin-top: 20px;
.a-box {
width: 344rpx;
height: 120rpx;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.a-prefecture {
background-image: url('../../static/image/prefecture.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.a-subject {
background-image: url('../../static/image/subject.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.a-text {
font-size: 32rpx;
color: #232524;
}
}
.content {
margin-top: 20px;
}
}
</style>@/hooks/useScroll
\ No newline at end of file
<template>
<van-popup v-model:show="show" position="left" :style="{ width: '65%', height: '100%' }">
<div class="list">
<div class="container" v-for="(item, index) in dataList" :key="index" @click="handleChoose(item,index)">
<div class="list-item">
<img class="left-logo" src="../../../static/image/organization-logo.png">
<span>{{ item.organName }}</span>
<!-- <van-icon name="arrow-down" size="20" /> -->
<van-icon name="success" size="25" color="#2879FE" v-if="active == index" />
</div>
<!-- <div class="children">
<div class="list-item">
<div class="left-logo"></div>
<span>贵阳日报</span>
<van-icon name="arrow-up" size="20" />
</div>
<div class="list-item">
<div class="left-logo"></div>
<span>摄影部</span>
<van-icon name="arrow-up" size="20" />
</div>
<div class="list-item">
<div class="left-logo"></div>
<span class="active">新媒体运营中心</span>
<van-icon name="success" size="25" color="#2879FE" />
</div>
<div class="list-item">
<div class="left-logo"></div>
<span>技术部</span>
<van-icon name="arrow-up" size="20" />
</div>
</div> -->
</div>
</div>
</van-popup>
</template>
<script setup>
import { selectOrganizeList } from '@/api/prefecture'
import useUserStore from '@/store/user'
import index from '../index.vue';
const show = ref(false)
const userStore = useUserStore()
const emits = defineEmits(["confirm"])
const active = ref(0)
const dataList = ref([])
const getList = async () => {
const data = {
userId: userStore.userinfo.user.id,
sysCode: import.meta.env.VITE_APP_SYSTEM_CODE,
moduleCode: 'practice-mediaCatalog'
}
const res = await selectOrganizeList(data)
dataList.value = res.data
emits('confirm', dataList.value[0])
}
getList()
const handleChoose = (item, index) => {
active.value = index
emits('confirm', item)
close()
}
const open = () => {
show.value = true
}
const close = () => {
show.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="scss" scoped>
.list {
padding: 50px 10px;
.list-item {
display: flex;
align-items: center;
gap: 5px;
padding: 10px 0;
border-bottom: 1px solid #f2F2F2;
.left-logo {
width: 25px;
height: 25px;
}
.active {
color: #2879FE;
}
span {
font-size: 15px;
color: #232524;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<div class="container">
<van-form @submit="handleSubmit" required colon>
<div class="content">
<div class="header">
<span class="title">基本信息</span>
<div class="title-line"></div>
</div>
<div class="form">
<!-- <van-field v-model="formData.area" is-link readonly label="拍摄地区" placeholder="请选择拍摄地区"
@click="showArea = true" :rules="[{ required: true, message: '请选择拍摄地区' }]" />
<van-field v-model="formData.address" label="详细地址" placeholder="请填写拍摄详细地址"
:rules="[{ required: true, message: '请填写拍摄详细地址' }]" /> -->
<van-field v-model="formData.shootLocation" is-link readonly label="拍摄地区" placeholder="请选择拍摄地区"
@click="handleRegionPicker" :rules="[{ required: true, message: '请选择拍摄地区' }]" />
<van-field v-model="formData.shoottime" is-link readonly label="拍摄时间" placeholder="请选择拍摄时间"
@click=" showShoottimeCalendar = true" :rules="[{ required: true, message: '请选择拍摄时间' }]" />
<van-field v-model="formData.materialtime" is-link readonly label="入库时间" placeholder="请选择入库时间"
@click="showMaterialtimeCalendar = true" :rules="[{ required: true, message: '请选择入库时间' }]" />
<van-field v-model="formData.materialTitle" label="图组标题" placeholder="请填写图组标题"
:rules="[{ required: true, message: '请填写图组标题' }]" />
<van-field v-model="formData.materialIntro" type="textarea" label="图组描述" placeholder="请填写图组描述"
:rules="[{ required: true, message: '请填写图组描述' }]" />
</div>
</div>
<div class="footer" ref="footerRef">
<div>
<van-button plain hairline round type="primary" @click="handlePre">上一步</van-button>
</div>
<div>
<van-button round type="primary" native-type="submit">提交</van-button>
</div>
</div>
</van-form>
</div>
<!-- <van-popup v-model:show="showArea" position="bottom">
<van-area :area-list="areaList" @confirm="areaConfirm" @cancel="showArea = false" />
</van-popup> -->
<van-calendar v-model:show="showShoottimeCalendar" :min-date="minDate" @confirm="shoottimeCalendarConfirm" />
<van-calendar v-model:show="showMaterialtimeCalendar" :min-date="minDate" @confirm="materialtimeCalendarConfirm" />
</template>
<script setup>
import { areaList } from '@vant/area-data'
import dayjs from 'dayjs'
const emits = defineEmits(["confirm"])
const footerRef = ref()
const formData = ref({})
const showArea = ref(false)
const showShoottimeCalendar = ref(false)
const showMaterialtimeCalendar = ref(false)
const minDate = ref(new Date('1970-01-01'))
const handlePre = () => {
emits('confirm', { code: 'pre' })
}
const handleSubmit = () => {
// formData.value.shootLocation = formData.value.area + formData.value.address
emits('confirm', { code: 'submit', catalog: formData.value })
}
const areaConfirm = (selectedOptions) => {
showArea.value = false;
formData.value.area = selectedOptions.selectedOptions.map((item) => item.text).join('');
}
const shoottimeCalendarConfirm = (data) => {
showShoottimeCalendar.value = false
formData.value.shoottime = dayjs(data).format('YYYY-MM-DD HH:mm:ss')
}
const materialtimeCalendarConfirm = (data) => {
showMaterialtimeCalendar.value = false
formData.value.materialtime = dayjs(data).format('YYYY-MM-DD HH:mm:ss')
}
const handleRegionPicker = () => {
xma.chooseLocation({
success: function (res) {
formData.value.shootLocation = res.address
},
fail: function (err) {
console.log(err)
}
});
}
</script>
<style lang="scss" scoped>
.container {
padding-top: 10px;
background-color: #f6f6f6;
.content {
padding: 10px;
background-color: #ffffff;
.header {
display: flex;
font-size: 16px;
flex-direction: column;
align-items: center;
gap: 6px;
.title {
color: #545454;
}
.title-line {
background-color: #2879fe;
height: 4px;
width: 15px;
border-radius: 5px;
}
}
.form {
margin-top: 10px;
.van-cell-group--inset {
margin: 0;
.van-cell {
margin-top: 10px;
font-size: 15px;
}
}
}
}
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #ffffff;
display: flex;
justify-content: space-between;
padding: 15px 10px;
box-shadow: -1px -1px 5px rgba(0, 0, 0, 0.1);
align-items: center;
height: 38px;
z-index: 999;
.info {
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
.info-content {
color: #2879fe;
}
}
:deep(.van-button--normal) {
padding: 0 20px;
width: 90px;
height: 35px;
font-size: 15px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="container">
<div class="content">
<div class="header">
<span class="title">图组上传</span>
<span class="btn" @click="handleUpload"><van-icon name="plus" size="14" />新增图片</span>
<!-- <input type="file" hidden ref="inputRef" accept="image/*" @change="changeFile" :multiple="true"> -->
</div>
<div class="list">
<div class="item" v-for="(item, index) in fileList" :key="index">
<div class="item-content">
<div class="logo">
<img :src="item.src">
<div class="close">
<img src="@/static/image/close.png" @click="handleDelete(index)">
</div>
</div>
<div class="info">
<div class="info-box">
<span class="title">图片{{ index + 1 }}描述:</span>
<div>
<radio-group @change="radioChange" class="radio-box">
<span class="title">封面</span>
<radio style="transform: scale(0.6);" :value="index"
:checked="index == current" />
</radio-group>
</div>
</div>
<textarea v-model="item.enclosureDesc" rows="2" placeholder="请输入图片描述"
:disabled="!item.uploadResult" />
</div>
</div>
<van-progress :percentage="item.progress" v-if="!item.uploadResult" />
</div>
</div>
</div>
<div class="footer-placeholder">
<div class="footer" ref="footerRef">
<div class="info">
<div>
<span>图片总大小:</span>
<span class="info-content">{{ fileSize }}KB</span>
</div>
<div>
<span>图片总容量:</span>
<span class="info-content">{{ fileList.length }}</span>
</div>
</div>
<div>
<van-button round type="primary" @click="handleNext">下一步</van-button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { uploadFile } from '@/api/publish'
import { showToast } from 'vant'
import useUserStore from "@/store/user"
const userStore = useUserStore()
const footerRef = ref()
const inputRef = ref()
const fileList = ref([])
const fileSize = ref(0)
const handleUpload = () => {
// inputRef.value.click()
xma.chooseImage({
count: 20, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album'], //从相册选择
success: function (res) {
console.log(res.tempFiles);
const files = res.tempFiles
for (let i = 0; i < files.length; i++) {
const item = files[i]
const index = fileList.value.push(item) - 1
let reader = new FileReader()
reader.readAsDataURL(item)
reader.onload = async (e) => {
item.src = e.target.result
fileList.value.splice(index, 1, { ...item })
item.uploadResult = await uploadFile(item, (e) => {
item.progress = Math.floor(
(e.loaded / e.total) * 100,
)
fileList.value.splice(index, 1, { ...item })
})
fileSize.value += parseInt(item.uploadResult.data.compressNameAndPath[0].size)
fileList.value.splice(index, 1, { ...item })
}
}
},
});
}
const current = ref(0)
const radioChange = (evt) => {
current.value = evt.detail.value
console.log(current.value)
}
const handleDelete = (index) => {
// 当删除的是最后一张图片且是封面图的时候,更换封面图为第一张
if (index + 1 == fileList.value.length && index == current.value) {
current.value = 0
}
fileList.value.splice(index, 1)
}
const emits = defineEmits(["confirm"])
const handleNext = () => {
if (!fileList.value.length) {
showToast('请上传图片')
return
}
const enclosureLists = []
for (let i = 0; i < fileList.value.length; i++) {
const item = fileList.value[i]
if (!item.enclosureDesc) {
showToast(`请输入图片${i + 1}的描述`)
return
}
enclosureLists.push({
mediacatalogId: null,
enclosureName: item.uploadResult.data.compressNameAndPath[0].name,
enclosureType: 3,
enclosureAddr: item.uploadResult.data.compressNameAndPath[0].path,
enclosureDesc: item.enclosureDesc,
createBy: userStore.userinfo.user.name,
fileSize: item.uploadResult.data.compressNameAndPath[0].size,
compressPath: item.uploadResult.data.compressPath[0],
watermarkPath: item.uploadResult.data.waterpath[0]
})
}
emits('confirm', { code: 'next', enclosureLists: enclosureLists, coverIndex: current.value })
}
</script>
<style lang="scss" scoped>
.container {
padding-top: 10px;
background-color: #f6f6f6;
min-height: 100vh;
.content {
padding: 10px;
background-color: #ffffff;
.header {
display: flex;
justify-content: space-between;
font-size: 16px;
.title {
color: #545454;
}
.btn {
color: #2879fe;
}
}
.list {
margin-top: 20px;
display: flex;
flex-direction: column;
gap: 10px;
.item {
.item-content {
display: flex;
gap: 10px;
.logo {
// flex: 0 0 35%;
width: 120px;
height: 90px;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 5px;
}
.close {
position: absolute;
top: 5px;
right: 5px;
img {
width: 18px;
height: 18px;
}
}
}
.info {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
box-sizing: border-box;
.info-box {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.radio-box {
display: flex;
align-items: center;
font-size: 28rpx;
color: #545454;
margin-bottom: 20rpx;
}
}
.title {
color: #545454;
font-size: 15px;
}
textarea {
border: 1px solid #cccccc;
flex: 1;
border-radius: 5px;
font-size: 14px;
padding: 10px;
width: 100%;
box-sizing: border-box;
resize: none;
}
}
}
}
.van-progress {
width: 35%;
margin-top: 5px;
}
}
}
.footer-placeholder {
height: 68px;
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #ffffff;
display: flex;
justify-content: space-between;
padding: 15px 10px;
box-shadow: -1px -1px 5px rgba(0, 0, 0, 0.1);
align-items: center;
height: 38px;
z-index: 999;
.info {
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
.info-content {
color: #2879fe;
}
}
:deep(.van-button--normal) {
padding: 0 20px;
height: 35px;
font-size: 15px;
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="container">
<van-form @submit="handleNext" required colon>
<div class="content">
<div class="header">
<span class="title">基本信息</span>
<div class="title-line"></div>
</div>
<div class="form">
<van-field v-model="formData.author" name="作者" label="作者" placeholder="请填写作者"
:rules="[{ required: true, message: '请填写作者' }]" />
<van-field v-model="formData.typeClassify" is-link readonly name="picker" label="类型" placeholder="请选择类型"
@click="openTypePopup" :rules="[{ required: true, message: '请选择类型' }]" />
<van-field v-model="formData.sourceDitch" is-link readonly name="picker" label="来源类型"
placeholder="请选择来源类型" @click="openSourceTypePopup"
:rules="[{ required: true, message: '请选择来源类型' }]" />
<van-field v-model="formData.sourceName" is-link readonly name="picker" label="来源渠道"
placeholder="请选择来源渠道" @click="openSourceChannelPopup"
:rules="[{ required: true, message: '请选择来源渠道' }]" />
<van-field v-model="formData.tagName" is-link readonly name="picker" label="标签" placeholder="请选择标签"
@click="openTagsPopup" :rules="[{ required: true, message: '请选择标签' }]" />
</div>
</div>
<div class="footer" ref="footerRef">
<div>
<van-button plain hairline round type="primary" @click="handlePre">上一步</van-button>
</div>
<div>
<van-button round type="primary" native-type="submit">下一步</van-button>
</div>
</div>
</van-form>
</div>
<type-popup ref="typePopupRef" @confirm="confirmTypePopup"></type-popup>
<source-type-popup ref="sourceTypePopupRef" @confirm="confirmSourceTypePopup"></source-type-popup>
<source-channel-popup ref="sourceChannelPopupRef" @confirm="confirmSourceChannelPopup"></source-channel-popup>
<tags-popup ref="tagsPopupRef" @confirm="confirmTagsPopup"></tags-popup>
</template>
<script setup>
import TypePopup from '../../../components/TypePopup/index.vue'
import SourceTypePopup from '../../../components/SourceTypePopup/index.vue'
import SourceChannelPopup from '../../../components/SourceChannelPopup/index.vue'
import TagsPopup from '../../../components/TagsPopup/index.vue'
import useUserStore from "@/store/user.js"
const emits = defineEmits(["confirm"])
const footerRef = ref()
const userStore = useUserStore()
const formData = ref({
createBy: userStore.userinfo?.user?.name,
author: userStore.userinfo?.user?.name,
userId: userStore.userinfo?.user?.id
})
const handlePre = () => {
emits('confirm', { code: 'pre' })
}
const handleNext = () => {
emits('confirm', { code: 'next', catalog: formData.value })
}
const typePopupRef = ref()
const openTypePopup = () => {
typePopupRef.value.open()
}
const confirmTypePopup = (e) => {
formData.value.typeClassify = e.classifyType
}
const sourceTypePopupRef = ref()
const openSourceTypePopup = () => {
sourceTypePopupRef.value.open()
}
const confirmSourceTypePopup = (e) => {
formData.value.sourceDitch = e.sourceName
}
const sourceChannelPopupRef = ref()
const openSourceChannelPopup = () => {
sourceChannelPopupRef.value.open()
}
const confirmSourceChannelPopup = (e) => {
formData.value.sourceName = e.sourceName
}
const tagsPopupRef = ref()
const openTagsPopup = () => {
tagsPopupRef.value.open()
}
const confirmTagsPopup = (e) => {
formData.value.tagId = e.id
formData.value.tagName = e.title
}
</script>
<style lang="scss" scoped>
.container {
padding-top: 10px;
background-color: #f6f6f6;
.content {
padding: 10px;
background-color: #ffffff;
.header {
display: flex;
font-size: 16px;
flex-direction: column;
align-items: center;
gap: 6px;
.title {
color: #545454;
}
.title-line {
background-color: #2879fe;
height: 4px;
width: 15px;
border-radius: 5px;
}
}
.form {
margin-top: 10px;
.van-cell-group--inset {
margin: 0;
.van-cell {
margin-top: 10px;
font-size: 15px;
}
}
}
}
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background-color: #ffffff;
display: flex;
justify-content: space-between;
padding: 15px 10px;
box-shadow: -1px -1px 5px rgba(0, 0, 0, 0.1);
align-items: center;
height: 38px;
z-index: 999;
.info {
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
.info-content {
color: #2879fe;
}
}
:deep(.van-button--normal) {
padding: 0 20px;
height: 35px;
font-size: 15px;
}
}
}
</style>
\ No newline at end of file
<template>
<van-nav-bar title="图组" :left-arrow="true" fixed placeholder safe-area-inset-top @click-left="router.go(-1)" />
<div class="container">
<div class="steps-placeholder" :style="{ height: `${stepsRef?.offsetHeight}px` }">
<div ref="stepsRef" class="steps-container">
<van-steps :active="stepsActive" active-color="#2879fe" inactive-color="#b7bdc6">
<van-step>图组上传</van-step>
<van-step>基本信息</van-step>
<van-step>图组信息</van-step>
</van-steps>
</div>
</div>
<keep-alive>
<component :is="componentName" @confirm="handleConfirm"></component>
</keep-alive>
</div>
</template>
<script setup>
import AtlasUpload from './components/AtlasUpload/index.vue'
import BasicInfo from './components/BasicInfo/index.vue'
import AtlasInfo from './components/AtlasInfo/index.vue'
import { insertPicture, insertPictureUrl } from '@/api/publish'
import { showLoadingToast, closeToast } from 'vant'
const router = useRouter()
const stepsActive = ref(0)
const stepsRef = ref()
const componentList = [AtlasUpload, BasicInfo, AtlasInfo]
let componentName = AtlasUpload
const enclosureLists = ref([])
const catalog = ref({
materialSource: 1,
materialType: 3,
checkState: 0,
collect: 0
})
const coverIndex = ref(0)
const handleConfirm = async (data) => {
if (data.code == 'next') {
stepsActive.value++
componentName = componentList[stepsActive.value]
enclosureLists.value = data.enclosureLists ?? enclosureLists.value
catalog.value = data.catalog ? { ...catalog.value, ...data.catalog } : catalog.value
coverIndex.value = data.coverIndex ?? coverIndex.value
}
if (data.code == 'pre') {
stepsActive.value--
componentName = componentList[stepsActive.value]
}
if (data.code == 'submit') {
showLoadingToast({
message: '提交中',
forbidClick: true,
duration: 0
})
catalog.value = data.catalog ? { ...catalog.value, ...data.catalog } : catalog.value
setCatalog()
const res = await insertPicture(catalog.value)
enclosureLists.value.forEach(item => {
item.mediacatalogId = res.data
})
await insertPictureUrl({ enclosureLists: enclosureLists.value })
closeToast()
router.replace({ name: 'publish-result' })
}
}
const setCatalog = () => {
let materialFilePath = []
let compressPath = []
let watermarkPath = []
let fileSize = 0
catalog.value.materialFilePath = enclosureLists.value.forEach(item => {
materialFilePath.push(item.enclosureAddr)
compressPath.push(item.compressPath)
watermarkPath.push(item.watermarkPath)
fileSize += parseInt(item.fileSize)
})
catalog.value.materialFilePath = materialFilePath.join(',')
catalog.value.compressPath = compressPath.join(',')
catalog.value.watermarkPath = watermarkPath.join(',')
catalog.value.fileSize = fileSize.toString()
catalog.value.fileNum = enclosureLists.value.length
catalog.value.coverpicture = enclosureLists.value[coverIndex.value].enclosureAddr
}
</script>
<style lang="scss" scoped>
.steps-container {
position: fixed;
left: 0;
right: 0;
z-index: 999;
:deep(.van-steps--horizontal) {
.van-steps__items {
padding-bottom: 32px;
.van-step__title {
font-size: 16px;
}
.van-step__circle-container {
top: 40px;
}
.van-step__line {
top: 40px;
}
}
}
}
</style>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment