乡村相册迁移位置

This commit is contained in:
aixianling
2022-08-08 10:33:18 +08:00
parent e912b6d00c
commit 91abd76323
109 changed files with 5 additions and 5 deletions

View File

@@ -1,287 +0,0 @@
<template>
<div class="AddAlbum">
<div class="form-group">
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>相册名称</span>
</div>
<div class="right">
<input placeholder="请输入相册名称" :maxlength="15" v-model="albumName" placeholder-style="color: #999" />
</div>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>拍摄人</span>
</div>
<div class="right" @click="linkTo('./PersonnelSetting?id=' + id)">
<span>{{ albumUserList.length ? '已选择' : '不限' }}</span>
<image src="./images/right.png" />
</div>
</div>
<div class="form-group__item" @click="linkTo('./SourceSetting?value=' + photoSource)">
<div class="left">
<label>*</label>
<span>照片来源</span>
</div>
<div class="right">
<span>{{ photoSource == 1 ? '仅限工作相册拍摄' : '不限' }}</span>
<image src="./images/right.png" />
</div>
</div>
</div>
<button v-if="id && id !== '1'" @click="remove" class="form-btn form-btn__remove" hover-class="text-hover">删除相册</button>
<button :loading="isLoading" @click="save" class="form-btn" hover-class="text-hover">保存</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'AddAlbum',
appName: '新增相册',
data () {
return {
albumName: '',
createUserId: '',
photoSource: 0,
watermarkId: '',
isLoading: false,
id: '',
info: {},
albumUserList: []
}
},
computed: {
...mapState(['user']),
},
onLoad (query) {
this.id = query.id || ''
if (query.id) {
this.getInfo(query.id)
}
uni.$on('watermarkChange', e => {
if (e.type === 'photoSource') {
this.photoSource = e.value
}
if (e.type === 'personnel') {
this.albumUserList = e.value
}
})
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
remove () {
this.$confirm('确定删除该相册?相册删除后,相册内的照片会同步删除!').then(() => {
this.$http.post(`/api/appalbum/delete?ids=${this.id}`).then(res => {
if (res.code == 0) {
this.$u.toast('删除成功')
uni.$emit('update')
setTimeout(() => {
uni.reLaunch({
url: './AppCountryAlbum'
})
}, 500)
}
})
}).catch(() => {
})
},
getInfo (id) {
this.$http.post(`/api/appalbum/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
this.albumName = res.data.albumName
this.photoSource = res.data.photoSource || 0
this.albumUserList = res.data.albumUserList || []
}
})
},
save () {
if (!this.albumName) {
return this.$u.toast('请输入相册名称')
}
this.$loading()
this.$http.post('/api/appalbum/addOrUpdate', {
albumName: this.albumName,
photoSource: this.photoSource,
watermarkId: '',
albumUserList: this.albumUserList,
id: this.id || ''
}).then(res => {
if (res.code === 0) {
this.$u.toast(this.id ? '编辑成功' : '新建成功')
if (this.id) {
uni.$emit('change')
} else {
uni.$emit('update')
}
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 500)
} else {
this.$hideLoading()
}
})
}
}
}
</script>
<style lang="scss" scoped>
.AddAlbum {
padding-bottom: 130px;
* {
line-height: 1;
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
&.form-btn__remove {
bottom: 140rpx;
background: #FF4466;
color: #fff;
}
}
.form-group {
margin-bottom: 16px;
padding: 0 32px;
background: #fff;
.form-group__item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
font-size: 32px;
color: #333333;
border-bottom: 1px solid #DDDDDD;
&.form-group__checked {
height: auto;
padding: 32px 0;
.left {
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
&.left-add {
display: flex;
align-items: center;
h2 {
margin-bottom: 0;
}
}
.add-btn {
position: relative;
width: 48px;
height: 48px;
margin-right: 16px;
border-radius: 50%;
overflow: hidden;
background: #1088F9;
&::after {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 4px;
height: 24px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
&::before {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 24px;
height: 4px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
}
p {
color: #999999;
font-size: 28px;
}
}
}
label {
color: #FF4466;
}
&:last-child {
border: none;
}
.right {
display: flex;
align-items: center;
color: #999999;
image {
width: 32px;
height: 32px;
}
input {
text-align: right;
color: #999;
font-size: 32px;
}
}
}
}
}
</style>

View File

@@ -1,234 +0,0 @@
<template>
<div class="report">
<components class="report-item" ref="reportItem" :config="currConfig" v-if="currConfig.length" :is="component"></components>
<div class="report-list" data-html2canvas-ignore>
<div class="report-btns">
<span @click="back">返回</span>
<h2>拼图模板</h2>
<span @click="save">保存</span>
</div>
<div class="report-wrapper">
<div
class="report-item"
:key="index"
v-for="(item, index) in configList"
:class="[currIndex === index ? 'active' : '']"
@click="changeComponent(item, index)">
<image class="img" :src="item.thum" />
<image class="checked" v-if="currIndex === index" src="./images/xuanzhong.png" />
<span @click="toEdit">编辑</span>
</div>
</div>
</div>
</div>
</template>
<script>
import Daily from './components/report/Daily'
import WorkReport from './components/report/WorkReport'
import InspectLog from './components/report/InspectLog'
import MeetingMminutes from './components/report/MeetingMminutes'
export default {
name: 'Report',
appName: '拼图汇报',
data () {
return {
component: 'WorkReport',
configList: [],
currIndex: 0,
albumId: ''
}
},
components: {
Daily,
InspectLog,
WorkReport,
MeetingMminutes
},
computed: {
currConfig () {
if (this.currIndex < 0 || !this.configList.length) return []
return this.configList[this.currIndex].itemList
}
},
onLoad (query) {
this.albumId = query.id || ''
this.getConfig()
},
methods: {
getConfig () {
this.$http.post(`/api/appalbumtemplate/list?size=100&templateType=1&status=1`).then(res => {
if (res.code === 0) {
this.configList = res.data.records
}
})
},
back () {
uni.navigateBack({
delta: 1
})
},
toEdit () {
this.$refs.reportItem.linkTo()
},
save () {
this.$loading()
this.$refs.reportItem.screenshot() && this.$refs.reportItem.screenshot().then(canvas => {
let dataURL = canvas.toDataURL('image/png')
const file = this.dataURLtoFile(dataURL, 'photo.png')
let formData = new FormData()
formData.append('file', file)
this.$http.post('/admin/file/add2?type=image', formData).then(res => {
if (res.code === 0) {
const data = this.configList[this.currIndex]
uni.navigateTo({
url: `./ReportImg?albumId=${this.albumId}&img=${res.data.url}&fileId=${res.data.id}&type=${data.watermarkType}&templateId=${data.id}`
})
}
uni.hideLoading()
})
}).catch(e => {
console.log(e)
})
},
dataURLtoFile (dataurl, filename) {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
},
changeComponent (e, index) {
this.currIndex = index
this.component = this.mapComponent(e.watermarkType)
},
mapComponent (type) {
return {
'9': 'WorkReport',
'10': 'Daily',
'11': 'InspectLog',
'12': 'MeetingMminutes'
}[type]
}
}
}
</script>
<style lang="scss" scoped>
.report {
position: relative;
padding-bottom: 330px;
.report-btns {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
span {
color: #222222;
font-size: 32px;
font-weight: 600;
}
h2 {
color: #333333;
font-size: 28px;
font-weight: 600;
}
}
* {
box-sizing: border-box;
}
.report-item {
padding-bottom: 20px;
}
.report-list {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
padding-bottom: 16px;
background: #FFFFFF;
.report-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
}
.report-item {
position: relative;
width: 176px;
height: 208px;
border: 4px solid transparent;
.img {
width: 100%;
height: 208px;
}
span {
display: none;
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 128px;
height: 56px;
line-height: 56px;
text-align: center;
color: #fff;
font-size: 32px;
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
transform: translate(-50%, -50%);
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
&.active {
.img {
border: 4px solid #408EF6;
}
span {
display: block;
}
}
}
}
}
</style>

View File

@@ -1,471 +0,0 @@
<template>
<div class="photo" v-if="pageShow">
<div class="photo-header">
<h2>{{ info.albumName }}</h2>
<div
class="right"
@click="linkTo('./AddAlbum?id=' + id)"
hover-class="text-hover"
v-if="info.albumName !== '系统相册' && info.createUserId === user.openId">
<image src="./images/setting.png" />
<span>相册设置</span>
</div>
</div>
<div class="photo-info">
<div class="photo-info__item">
<h2>{{ totalInfo.all || 0 }}</h2>
<span>照片</span>
</div>
<div class="photo-info__item">
<h2>{{ totalInfo.today || 0 }}</h2>
<span>今日</span>
</div>
<div class="photo-info__item">
<h2>{{ totalInfo.benyue || 0 }}</h2>
<span>本月</span>
</div>
<div class="photo-info__item">
<h2>{{ totalInfo.bennian || 0 }}</h2>
<span>今年</span>
</div>
</div>
<div class="photo-list">
<div class="photo-title">
<div class="left">
<picker mode="date" @change="onChange">
<div class="left-item">
<span>{{ date || '所有日期' }}</span>
<image src="./images/down.png" />
</div>
</picker>
<div class="left-item" style="margin-right: 0;" @click="toChoose">
<span v-if="userId"><AiOpenData v-if="userId" type="userName" :openid="userId"></AiOpenData></span>
<span v-else>拍摄人</span>
<image src="./images/down.png" />
</div>
</div>
<div class="right" hover-class="text-hover" @click="toEdit">
<image src="./images/edit.png" />
<span>编辑照片</span>
</div>
</div>
<div class="photo-item__wrapper">
<div class="photo-item" @click="linkTo('./Photo?id=' + item.id)" v-for="(item, index) in list" :key="index">
<!-- <image :src="item.photoUrl" mode="aspectFill" /> -->
<u-lazy-load :image="item.photoUrl" :height="328" :loading-img="$cdn + 'watermark/loading.png'" img-mode="aspectFill"></u-lazy-load>
<div class="photo-item__text">
<h2><AiOpenData v-if="item.createUserId" type="userName" :openid="item.createUserId"></AiOpenData></h2>
<p>{{ item.createTime }}</p>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</div>
<div class="btn-wrapper">
<div class="btn" @click="linkTo('./AddReport?id=' + id)">上传拼图汇报</div>
<div class="btn" @click="toAddImg" hover-class="text-hover">上传照片</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
name: 'AlbumDetail',
appName: '工作相册',
data () {
return {
list: [],
type: '',
info: {},
name: '',
date: '',
imgList: [],
hideStatus: false,
pageShow: false,
id: '',
current: 1,
totalInfo: {},
isMore: false,
userId: ''
}
},
computed: {
...mapState(['user'])
},
onLoad (query) {
this.id = query.id
this.$nextTick(() => {
this.getTotalInfo(query.id)
this.getInfo(query.id)
this.getList()
})
uni.$on('change', () => {
this.isMore = false
this.current = 1
this.getInfo(query.id)
this.$nextTick(() => {
this.getList()
})
})
uni.$on('update', () => {
this.isMore = false
this.current = 1
this.getTotalInfo(query.id)
this.$nextTick(() => {
this.getList()
})
})
},
onUnload () {
uni.$off('change')
uni.$off('update')
},
methods: {
...mapActions(['selectPrivilegedContact']),
linkTo (url) {
uni.navigateTo({
url
})
},
toChoose () {
this.$loading()
this.selectPrivilegedContact({
fromDepartmentId: 0,
mode: 'single',
selectedOpenUserIds: this.userId ? [this.userId] : ''
}).then(res => {
console.log(res)
uni.hideLoading()
if (res.userList && res.userList) {
this.userId = res.userList[0].openUserId
} else {
this.$u.toast('该用户未授权')
}
this.isMore = false
this.current = 1
this.$nextTick(() => {
this.getList()
})
}).catch(() => {
uni.hideLoading()
})
},
toEdit () {
if (!this.list.length) {
return this.$u.toast('相册无照片,请上传照片')
}
this.linkTo(`./EditAlbum?id=${this.id}`)
},
onChange (e) {
this.date = e.detail.value
this.isMore = false
this.current = 1
this.$nextTick(() => {
this.getList()
})
},
getInfo (id) {
this.$loading()
this.$http.post(`/api/appalbum/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.info = res.data
}
this.pageShow = true
})
},
getTotalInfo (id) {
this.$http.post(`/api/appalbumphoto/photoDetail?id=${id}`).then(res => {
if (res.code === 0) {
this.totalInfo = res.data
}
})
},
toAddImg () {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: this.info.photoSource === '1' ? ['camera'] : ['album', 'camera'],
success: res => {
this.linkTo(`./Watermark?url=${encodeURIComponent(res.tempFilePaths[0])}&albumId=${this.id}`)
}
})
},
getList () {
if (this.isMore) return
this.$loading()
this.$http.post(`/api/appalbumphoto/DetailByAlbumID`, null, {
params: {
albumId: this.id,
pageSize: 10,
queryTime: this.date,
userId: this.userId,
pageNum: this.current
}
}).then(res => {
if (res.code === 0) {
if (this.current > 1) {
this.list = [...this.list, ...res.data.records]
} else {
this.list = []
this.$nextTick(() => {
this.list = res.data.records
})
}
if (res.data.records.length < 10) {
this.isMore = true
uni.hideLoading()
return false
}
this.current = this.current + 1
}
uni.hideLoading()
})
}
},
onReachBottom () {
this.getList()
}
}
</script>
<style lang="scss" socped>
.photo {
min-height: 100vh;
padding-bottom: 130px;
box-sizing: border-box;
* {
box-sizing: border-box;
}
.photo-list {
padding: 32px;
.photo-item__wrapper {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
.photo-item {
position: relative;
width: 328px;
height: 328px;
margin-bottom: 32px;
border-radius: 12px;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
.photo-item__text {
position: absolute;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
padding: 20px 16px 16px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
h2 {
margin-bottom: 12px;
color: #fff;
font-size: 32px;
font-weight: 600;
}
p {
color: #fff;
font-size: 28px;
}
}
&:nth-of-type(2n) {
margin-left: 30px;
}
}
}
.photo-title {
display: flex;
align-items: center;
justify-content: space-between;
margin: 44px 0;
& > h2 {
color: #333333;
font-size: 38px;
font-weight: 600;
}
.left {
display: flex;
align-items: center;
.left-item {
display: flex;
align-items: center;
margin-right: 32px;
span {
color: #666666;
font-size: 26px;
}
image {
width: 32px;
height: 32px;
margin-left: 8px;
}
}
}
.right {
display: flex;
align-items: center;
font-size: 26px;
color: #333;
image {
width: 32px;
height: 32px;
margin-right: 8px;
}
}
}
}
.photo-header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 148px;
padding: 0 32rpx;
color: #Fff;
background: #3975C6;
div {
display: flex;
align-items: center;
width: 216px;
height: 56px;
line-height: 56px;
text-align: center;
justify-content: center;
border-radius: 28px;
font-size: 28px;
background: #285DA4;
}
image {
width: 32px;
height: 32px;
margin-right: 8px;
}
h2 {
flex: 1;
margin-right: 20px;
color: #fff;
font-size: 38px;
}
}
.photo-info {
display: flex;
align-items: center;
height: 168px;
background: #3975C6;
& > div {
flex: 1;
text-align: center;
h2 {
margin-bottom: 10px;
font-weight: 600;
font-size: 44px;
color: #fff;
}
span {
color: #C3D5EE;
font-size: 26px;
}
}
}
.btn-wrapper {
display: flex;
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
.btn {
&:active, &.hover {
opacity: 0.7;
}
}
.btn:first-child {
flex: 1;
height: 112px;
line-height: 112px;
text-align: center;
background: #FFFFFF;
box-shadow: inset 0px 1px 0px 0px #DDDDDD;
color: #333333;
font-size: 36px;
}
.btn:last-child {
flex: 1;
height: 112px;
line-height: 112px;
text-align: center;
background: #1365DD;
box-shadow: inset 0px 1px 0px 0px #DDDDDD;
color: #fff;
font-size: 36px;
}
}
}
</style>

View File

@@ -1,103 +0,0 @@
<template>
<div class="form">
<component ref="TabPage" :is="component" @change="onChange" :params="params"/>
</div>
</template>
<script>
import Tabbar from './components/Tabbar.vue'
import { mapActions, mapState } from "vuex"
export default {
name: 'AppCountryAlbum',
appName: '工作相册',
data() {
return {
component: 'Tabbar',
params: {}
}
},
components: {
Tabbar
},
onLoad () {
uni.setStorageSync('address', {
lat: '',
lng: '',
address: '',
weather: '',
cityCode: ``
})
setTimeout(() => {
this.getLocation()
}, 600)
},
onShow() {
this.$refs?.TabPage?.show()
},
computed: {
...mapState(['wxwork'])
},
methods: {
...mapActions(['injectJWeixin', 'agentSign']),
onChange(e) {
this.params = e.params
this.component = e.type
},
getLocation () {
this.injectJWeixin(['getLocation']).then(() => {
wx.getLocation({
type: 'wgs84',
success: res => {
var lat = res.latitude
var lng = res.longitude
this.$http.post('/api/appdvcpconfig/apiForward', `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=3RZBZ-LZUCF-CT6J5-NWKZH-FCWOQ-UUFKY&get_poi=1`).then(res => {
if (res.code === 0) {
const data = res.data.result
uni.setStorageSync('address', {
lat,
lng,
address: data.address,
cityCode: `${data.ad_info.adcode}`
})
this.getWeather(`${data.ad_info.adcode}`)
}
})
},
error: res => {
console.log(res)
}
})
}).catch(e => {
})
},
getWeather (code) {
this.$http.post(`/api/bdweather/wdata?districtId=${code}`).then(res => {
if (res.code === 0) {
const data = res.data.result.now
uni.setStorageSync('address', {
...uni.getStorageSync('address'),
weather: `${data.text} ${data.temp}°` || ''
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,331 +0,0 @@
<template>
<div class="Attendance">
<div class="Attendance-top">
<div>
<div class="left">
<h2>{{ DD }}</h2>
<div class="left-wrapper__right">
<h3>{{ yyyyMM }}</h3>
<p>·数据统计</p>
</div>
</div>
<div class="right" @click="isShow = true">
<image src="./images/qiehuan.png" />
<span>切换日期</span>
</div>
</div>
</div>
<div class="info">
<div class="info-tab">
<div class="left">
<span @click="changeTab(0)" :class="[currIndex === 0 ? 'active' : '']">全部 {{ attendanceCount.all || 0 }}</span>
<span @click="changeTab(1)" :class="[currIndex === 1 ? 'active' : '']">已出勤 {{ attendanceCount.hasIn || 0 }}</span>
<span @click="changeTab(2)" :class="[currIndex === 2 ? 'active' : '']">未出勤 {{ attendanceCount.hasOut || 0 }}</span>
</div>
<div class="right" @click="linkTo('./AttendanceSetting')" v-if="isAdmin">考勤设置</div>
</div>
<div class="info-table">
<div class="table-header">
<span>人员</span>
<span>上下班时间</span>
<span>工作时长</span>
</div>
<div class="table-body">
<div class="table-row" v-for="(item, index) in list" :key="index">
<div class="table-row__left">
<h2><AiOpenData v-if="item.userId" type="userName" :openid="item.userId"></AiOpenData></h2>
<p>已上传{{ item.photoCount || 0 }}</p>
</div>
<span>{{ item.workInTime }}-{{ item.workOutTime || '' }}</span>
<span>{{ item.workHours || 0 }}小时</span>
</div>
</div>
</div>
</div>
<u-calendar v-model="isShow" mode="date" @change="onDateChange"></u-calendar>
</div>
</template>
<script>
export default {
name: 'Attendance',
appName: '考勤统计',
data () {
return {
date: '',
currIndex: 0,
list: [],
attendanceCount: {},
all: '1',
hasIn: '',
hasOut: '',
yyyyMM: '',
DD: '',
isShow: false,
isAdmin: false
}
},
onLoad (query) {
this.isAdmin = !!this.$store.state.user.adminAuthType
if (query.date) {
this.date = this.$dayjs(query.date).format('YYYY年MM月DD')
this.yyyyMM = this.$dayjs(query.date).format('YYYY年MM月')
this.DD = this.$dayjs(query.date).format('DD')
} else {
this.date = this.$dayjs(new Date).format('YYYY年MM月DD')
this.yyyyMM = this.$dayjs(new Date).format('YYYY年MM月')
this.DD = this.$dayjs(new Date).format('DD')
}
this.getList()
this.getTotal()
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
changeTab (index) {
if (index === 0) {
this.all = '1'
this.hasIn = ''
this.hasOut = ''
} else if (index === 1) {
this.all = ''
this.hasIn = '1'
this.hasOut = ''
} else {
this.all = ''
this.hasIn = ''
this.hasOut = '1'
}
this.currIndex = index
this.getList()
},
onDateChange (e) {
this.date = `${e.year}${e.month > 9 ? e.month : '0' + e.month}${e.day > 9 ? e.day : '0' + e.day}`
this.yyyyMM = `${e.year}${e.month > 9 ? e.month : '0' + e.month}`
this.DD = e.day > 9 ? e.day : '0' + e.day
this.$nextTick(() => {
this.getList()
this.getTotal()
})
},
getTotal () {
this.$http.post(`/api/appattendancerecord/attendanceCount?queryTime=${this.date.replace(/年|月/g, '-')}`).then(res => {
if (res.code === 0) {
this.attendanceCount = res.data
}
})
},
getList () {
this.$loading()
this.$http.post(`/api/appattendancerecord/alldetail?all=${this.all}&hasIn=${this.hasIn}&hasOut=${this.hasOut}&queryTime=${this.date.replace(/年|月/g, '-')}`).then(res => {
if (res.code === 0) {
this.list = res.data.map(v => {
return {
...v,
workInTime: v.workInTime ? this.$dayjs(v.workInTime).format('HH:mm') : '',
workOutTime: v.workOutTime ? this.$dayjs(v.workOutTime).format('HH:mm') : ''
}
})
this.$hideLoading()
}
})
}
}
}
</script>
<style lang="scss" scoped>
.Attendance {
padding: 0 0 0;
* {
box-sizing: border-box;
line-height: 1;
}
i, em {
font-style: normal;
}
.info-table {
margin-top: 32px;
padding: 0 32px;
.table-header {
display: flex;
align-items: center;
height: 96px;
background: #F4F9FD;
border-radius: 8px;
span {
flex: 1;
text-align: center;
color: #333333;
font-size: 28px;
}
}
.table-body {
.table-row {
display: flex;
align-items: center;
height: 160px;
border-radius: 8px;
text-align: center;
&:nth-of-type(2n) {
background: #F4F9FD;
}
div {
h2 {
margin-bottom: 16px;
color: #333333;
font-size: 34px;
}
p {
color: #999999;
font-size: 28px;
}
}
div, span {
flex: 1;
}
span {
color: #333;
font-size: 28px;
}
}
}
}
.info {
position: relative;
top: -116px;
margin: 0 32px;
padding: 0 0 86px 0;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.02);
border-radius: 16px;
.info-tab {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
padding: 0 32px 0 16px;
.left {
display: flex;
align-items: center;
height: 100%;
span {
width: 124px;
height: 108px;
line-height: 108px;
margin-right: 32px;
text-align: center;
color: #999999;
font-size: 28px;
transition: all ease 0.3s;
&:last-child {
margin-right: 0;
}
&.active {
color: #1365DD;
border-bottom: 2px solid #1365DD;
}
}
}
.right {
font-size: 28px;
font-weight: 400;
color: #3975C6;
}
}
}
.Attendance-top {
height: 320px;
width: 100%;
padding: 58px 32px 0;
background: #3975C6;
& > div {
display: flex;
justify-content: space-between;
align-items: center;
}
.right {
display: flex;
align-items: center;
height: 56px;
padding: 0 36px;
background: #285DA4;
border-radius: 28px;
image {
width: 36px;
height: 26px;
margin-right: 12px;
}
span {
color: #FFFFFF;
font-size: 28px;
}
}
.left {
display: flex;
align-items: center;
line-height: 1;
h2 {
margin-right: 16px;
font-size: 100px;
font-weight: 600;
color: #FFFFFF;
}
h3 {
margin-bottom: 8px;
color: #a9c3e6;
font-size: 28px;
}
p {
font-size: 32px;
color: #FFFFFF;
}
}
}
}
</style>

View File

@@ -1,413 +0,0 @@
<template>
<div class="AttendanceFiexdTime">
<div class="form-group">
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>上班打卡时间</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workInTime')">
<div class="right">
<span>{{ form.workInTime || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>下班打卡时间</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workOutTime')">
<div class="right">
<span>{{ form.workOutTime || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>是否开启休息时间</h2>
<p>若开启休息时间则休息时间不计入工作时长</p>
</div>
<div class="right">
<switch color="#1088F9" :checked="form.openRestTime === '1'" @change="onOpenRestChange" />
</div>
</div>
<div class="form-group__item" v-if="form.openRestTime === '1'">
<div class="left">
<label>*</label>
<span>休息开始</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'restTimeBegin')">
<div class="right">
<span>{{ form.restTimeBegin || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
<div class="form-group__item" v-if="form.openRestTime === '1'">
<div class="left">
<label>*</label>
<span>休息结束</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'restTimeEnd')">
<div class="right">
<span>{{ form.restTimeEnd || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>允许打卡时间范围</h2>
<p>超过打卡时间则记为迟到提前打卡则记为早退</p>
</div>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>上班打卡</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workInFrom')">
<div class="right">
<span>{{ form.workInFrom || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>下班打卡</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workOutEnd')">
<div class="right">
<span>{{ form.workOutEnd || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>是否开启固定打卡点</h2>
<p>若开启不在固定范围内打卡将不计入考勤</p>
</div>
<div class="right">
<switch color="#1088F9" :checked="form.openWorkPoint === '1'" @change="onWorkPointChange" />
</div>
</div>
<div class="form-group__item form-item__address form-group__checked" v-if="form.openWorkPoint === '1' && address.address">
<div class="left">
<h2>{{ address.title }}</h2>
<p>{{ address.address }}</p>
<p style="margin-top: 8px;">允许打卡范围{{ address.distance }}</p>
</div>
<div class="right" @click="address = {}">
<image src="./images/remove.png" />
<span>删除</span>
</div>
</div>
<div class="form-group__item form-group__checked" v-if="form.openWorkPoint === '1' && !address.address">
<div class="left left-add" @click="linkTo('./ChooseAddess')">
<div class="add-btn"></div>
<h2 style="color: #1088F9;">添加打卡点</h2>
</div>
</div>
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
export default {
name: 'AttendanceFiexdTime',
appName: '固定时间打卡设置',
data () {
return {
form: {
openRestTime: '1',
openWorkPoint: '0',
workInTime: '',
restTimeBegin: '',
restTimeEnd: '',
workOutTime: '',
workInFrom: '',
workOutEnd: ''
},
address: {}
}
},
onLoad (query) {
uni.$on('address', e => {
this.address = e
})
if (query.id) {
this.id = query.id
this.getInfo(query.id)
}
},
onUnload () {
uni.$off('address')
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
getInfo (id) {
this.$http.post(`/api/appattendanceconfig/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.address = JSON.parse(res.data.workPointDesc)
this.form = {
...this.form,
...res.data
}
}
})
},
onTimeChange (e, type) {
this.form[type] = e.detail.value + ':00'
},
onOpenRestChange (e) {
this.form.restTimeBegin = ''
this.form.restTimeEnd = ''
this.form.openRestTime = e.detail.value ? '1' : '0'
},
onWorkPointChange (e) {
this.form.openWorkPoint = e.detail.value ? '1' : '0'
this.form.workPointDesc = {}
this.address = {}
},
save () {
if (!this.form.workInTime) {
return this.$u.toast('请选择上班打卡时间')
}
if (!this.form.workOutTime) {
return this.$u.toast('请选择下班打卡时间')
}
if (this.$dayjs('2020-06-01 ' + this.form.workOutTime).valueOf() <= this.$dayjs('2020-06-01 ' + this.form.workInTime).valueOf()) {
return this.$u.toast('下班时间不能早于上班时间')
}
if (this.form.openRestTime === '1') {
if (!this.form.restTimeBegin) {
return this.$u.toast('请选择休息开始时间')
}
if (!this.form.restTimeEnd) {
return this.$u.toast('请选择休息结束时间')
}
if (this.$dayjs('2020-06-01 ' + this.form.restTimeEnd).valueOf() <= this.$dayjs('2020-06-01 ' + this.form.restTimeBegin).valueOf()) {
return this.$u.toast('休息结束时间不能早于休息开始时间')
}
}
if (!this.form.workInFrom) {
return this.$u.toast('请选择上班打卡最早时间')
}
if (!this.form.workOutEnd) {
return this.$u.toast('请选择下班打卡最晚时间')
}
if (this.$dayjs('2020-06-01 ' + this.form.workOutEnd).valueOf() <= this.$dayjs('2020-06-01 ' + this.form.workInFrom).valueOf()) {
return this.$u.toast('下班打卡最晚时间不能早于上班打卡最早时间')
}
if (this.form.openWorkPoint === '1' && !this.address.address) {
return this.$u.toast('请选择固定打卡点')
}
this.$loading()
this.$http.post('/api/appattendanceconfig/addOrUpdate', {
openRestTime: this.form.openRestTime,
openWorkPoint: this.form.openWorkPoint,
workInFrom: `${this.form.workInFrom}`,
workOutEnd: `${this.form.workOutEnd}`,
workInTime: `${this.form.workInTime}`,
workOutTime: `${this.form.workOutTime}`,
restTimeBegin: `${this.form.restTimeBegin}`,
restTimeEnd: `${this.form.restTimeEnd}`,
type: 0,
workPointDesc: JSON.stringify(this.address),
id: this.id || ''
}).then(res => {
if (res.code === 0) {
this.$u.toast('提交成功')
setTimeout(() => {
uni.$emit('update')
uni.navigateBack({
delta: 1
})
}, 500)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.AttendanceFiexdTime {
padding-bottom: 130px;
* {
line-height: 1;
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.form-group {
margin-bottom: 16px;
padding: 0 32px;
background: #fff;
.form-group__item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
font-size: 32px;
color: #333333;
border-bottom: 1px solid #DDDDDD;
&.form-group__checked {
height: auto;
padding: 32px 0;
.left {
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
&.left-add {
display: flex;
align-items: center;
h2 {
margin-bottom: 0;
}
}
.add-btn {
position: relative;
width: 48px;
height: 48px;
margin-right: 16px;
border-radius: 50%;
overflow: hidden;
background: #1088F9;
&::after {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 4px;
height: 24px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
&::before {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 24px;
height: 4px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
}
p {
color: #999999;
font-size: 28px;
}
}
}
label {
color: #FF4466;
}
&:last-child {
border: none;
}
.right {
display: flex;
align-items: center;
color: #999999;
image {
width: 32px;
height: 32px;
}
}
}
}
.form-item__address {
.left {
flex: 1;
margin-right: 10px;
p {
line-height: 1.3;
}
}
.right {
span {
margin-left: 10px;
color: #1088F9;
font-size: 28px;
}
}
}
}
</style>

View File

@@ -1,398 +0,0 @@
<template>
<div class="AttendanceFiexdTime">
<div class="form-group">
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>最早允许打卡时间</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workInFrom')">
<div class="right">
<span>{{ form.workInFrom || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>最晚允许打卡时间</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'workOutEnd')">
<div class="right">
<span>{{ form.workOutEnd || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>是否开启休息时间</h2>
<p>若开启休息时间则休息时间不计入工作时长</p>
</div>
<div class="right">
<switch color="#1088F9" :checked="form.openRestTime === '1'" @change="onOpenRestChange" />
</div>
</div>
<div class="form-group__item" v-if="form.openRestTime === '1'">
<div class="left">
<label>*</label>
<span>休息开始</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'restTimeBegin')">
<div class="right">
<span>{{ form.restTimeBegin || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
<div class="form-group__item" v-if="form.openRestTime === '1'">
<div class="left">
<label>*</label>
<span>休息结束</span>
</div>
<picker mode="time" @change="e => onTimeChange(e, 'restTimeEnd')">
<div class="right">
<span>{{ form.restTimeEnd || '请设置时间' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>工作时长要求</h2>
</div>
</div>
<div class="form-group__item">
<div class="left">
<label>*</label>
<span>时长要求</span>
</div>
<picker :range="hours" mode="selector" @change="e => form.workHoursLimit = hours[e.detail.value]">
<div class="right">
<span>{{ form.workHoursLimit ? form.workHoursLimit + '小时' : '请选择工作时长' }}</span>
<image src="./images/right.png" />
</div>
</picker>
</div>
</div>
<div class="form-group">
<div class="form-group__item form-group__checked">
<div class="left">
<h2>是否开启固定打卡点</h2>
<p>若开启不在固定范围内打卡将不计入考勤</p>
</div>
<div class="right">
<switch color="#1088F9" :checked="form.openWorkPoint === '1'" @change="onWorkPointChange" />
</div>
</div>
<div class="form-group__item form-group__checked form-item__address" v-if="form.openWorkPoint === '1' && address.address">
<div class="left">
<h2>{{ address.title }}</h2>
<p>{{ address.address }}</p>
<p style="margin-top: 8px;">允许打卡范围{{ address.distance }}</p>
</div>
<div class="right" @click="address = {}">
<image src="./images/remove.png" />
<span>删除</span>
</div>
</div>
<div class="form-group__item form-group__checked" v-if="form.openWorkPoint === '1' && !address.address">
<div class="left left-add" @click="linkTo('./ChooseAddess')">
<div class="add-btn"></div>
<h2 style="color: #1088F9;">添加打卡点</h2>
</div>
</div>
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
export default {
name: 'AttendanceFlexibleTime',
appName: '灵活时间打卡设置',
data () {
return {
hours: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17'],
form: {
openRestTime: '1',
openWorkPoint: '0',
workHoursLimit: '',
restTimeBegin: '',
restTimeEnd: '',
workInFrom: '',
workOutEnd: ''
},
address: {},
id: ''
}
},
onLoad (query) {
uni.$on('address', e => {
this.address = e
})
if (query.id) {
this.id = query.id
this.getInfo(query.id)
}
},
onUnload () {
uni.$off('address')
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
getInfo (id) {
this.$http.post(`/api/appattendanceconfig/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.address = JSON.parse(res.data.workPointDesc)
this.form = {
...this.form,
...res.data
}
}
})
},
onTimeChange (e, type) {
this.form[type] = e.detail.value + ':00'
},
onOpenRestChange (e) {
this.form.restTimeBegin = ''
this.form.restTimeEnd = ''
this.form.openRestTime = e.detail.value ? '1' : '0'
},
onWorkPointChange (e) {
this.form.openWorkPoint = e.detail.value ? '1' : '0'
this.form.workPointDesc = {}
this.address = {}
},
save () {
if (!this.form.workInFrom) {
return this.$u.toast('请选择最早打卡时间')
}
if (!this.form.workOutEnd) {
return this.$u.toast('请选择最晚打卡时间')
}
if (this.$dayjs('2020-06-01 ' + this.form.workOutEnd).valueOf() <= this.$dayjs('2020-06-01 ' + this.form.workInFrom).valueOf()) {
return this.$u.toast('最晚打卡时间不能最早打卡时间')
}
if (this.form.openRestTime === '1') {
if (!this.form.restTimeBegin) {
return this.$u.toast('请选择休息时间')
}
if (!this.form.restTimeEnd) {
return this.$u.toast('请选择休息结束时间')
}
if (this.$dayjs('2020-06-01 ' + this.form.restTimeEnd).valueOf() <= this.$dayjs('2020-06-01 ' + this.form.restTimeBegin).valueOf()) {
return this.$u.toast('休息结束时间不能早于休息开始时间')
}
}
if (!this.form.workHoursLimit) {
return this.$u.toast('请选择工作时长')
}
if (this.form.openWorkPoint === '1' && !this.address.address) {
return this.$u.toast('请选择固定打卡点')
}
this.$loading()
this.$http.post('/api/appattendanceconfig/addOrUpdate', {
openRestTime: this.form.openRestTime,
workHoursLimit: this.form.workHoursLimit,
openWorkPoint: this.form.openWorkPoint,
workInFrom: `${this.form.workInFrom}`,
workOutEnd: `${this.form.workOutEnd}`,
restTimeBegin: `${this.form.restTimeBegin}`,
restTimeEnd: `${this.form.restTimeEnd}`,
type: 1,
workPointDesc: JSON.stringify(this.address),
id: this.id || ''
}).then(res => {
if (res.code === 0) {
this.$u.toast('提交成功')
setTimeout(() => {
uni.$emit('update')
uni.navigateBack({
delta: 1
})
}, 500)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.AttendanceFiexdTime {
padding-bottom: 130px;
* {
line-height: 1;
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.form-group {
margin-bottom: 16px;
padding: 0 32px;
background: #fff;
.form-group__item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
font-size: 32px;
color: #333333;
border-bottom: 1px solid #DDDDDD;
&.form-group__checked {
height: auto;
padding: 32px 0;
.left {
flex: 1;
margin-right: 10px;
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
p {
line-height: 1.2;
}
&.left-add {
display: flex;
align-items: center;
h2 {
margin-bottom: 0;
}
}
.add-btn {
position: relative;
width: 48px;
height: 48px;
margin-right: 16px;
border-radius: 50%;
overflow: hidden;
background: #1088F9;
&::after {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 4px;
height: 24px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
&::before {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 24px;
height: 4px;
background: #fff;
content: ' ';
transform: translate(-50%, -50%);
}
}
p {
color: #999999;
font-size: 28px;
}
}
}
label {
color: #FF4466;
}
&:last-child {
border: none;
}
.right {
display: flex;
align-items: center;
color: #999999;
image {
width: 32px;
height: 32px;
}
}
}
}
.form-item__address {
.left {
flex: 1;
margin-right: 10px;
p {
line-height: 1.3;
}
}
.right {
span {
margin-left: 10px;
color: #1088F9;
font-size: 28px;
}
}
}
}
</style>

View File

@@ -1,244 +0,0 @@
<template>
<div class="AttendanceSetting" v-if="pageShow">
<div class="cell-group" v-if="!list.length">
<div class="cell-item" hover-class="bg-hover" @click="linkTo('./AttendanceFiexdTime')">
<div class="cell-item__left">
<h2>固定时间上下班</h2>
<p>有固定的上下班时间考核迟到早退</p>
</div>
<image src="./images/right.png" />
</div>
<div class="cell-item" hover-class="bg-hover" @click="linkTo('./AttendanceFlexibleTime')">
<div class="cell-item__left">
<h2>灵活时间上下班</h2>
<p>上下班时间不固定考核工时时长</p>
</div>
<image src="./images/right.png" />
</div>
</div>
<div v-if="list.length">
<div class="config" v-for="(item, index) in list" :key="index">
<h2>当前配置{{ item.title }}</h2>
<div class="config-wrapper">
<div class="config-item" v-if="item.type === '0'">
<label>上班时间</label>
<span>{{ item.type === '0' ? item.workInTime : item.workInFrom }} - {{ item.type === '0' ? item.workOutTime : item.workOutEnd }}</span>
</div>
<div class="config-item" v-if="item.type === '1'">
<label>工作时长</label>
<span>{{ item.workHoursLimit }}小时</span>
</div>
<div class="config-item">
<label>休息时间</label>
<span v-if="item.openRestTime === '0'">未开启</span>
<span v-else>{{ item.restTimeBegin }} - {{ item.restTimeEnd }}</span>
</div>
<div class="config-item">
<label>打卡时间范围</label>
<!-- <span>上班前2小时下班后2小时打卡生效</span> -->
<span>{{ item.workInFrom }} - {{ item.workOutEnd }}</span>
</div>
<div class="config-item config-item__line" v-if="item.openWorkPoint === '1'">
<label>固定打卡点</label>
<span>{{ item.workPointDesc.address }}</span>
</div>
<div class="config-item" v-else>
<label>固定打卡点</label>
<span>未固定打卡点</span>
</div>
</div>
<div class="config-footer">
<div @click="toEdit(item)">修改规则</div>
<div @click="remove(item.id)">删除规则</div>
</div>
</div>
</div>
<div class="tips">
<span v-if="!list.length">当前考勤时间为00:00~24:00若新增考勤规则则以
新增规则为准</span>
工作时长=最晚拍照时间-最早拍照时间
若员工最早或者最晚拍照时间缺失对应工作时长为空
上班时间=最早拍照时间
下班时间=最晚拍照时间
</div>
</div>
</template>
<script>
export default {
name: 'AttendanceSetting',
appName: '考勤设置',
data () {
return {
list: [],
pageShow: false
}
},
onLoad () {
this.$loading()
this.getConfigList()
uni.$on('update', () => {
this.getConfigList()
})
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
toEdit (item) {
if (item.type === '0') {
this.linkTo(`./AttendanceFiexdTime?id=${item.id}`)
} else {
this.linkTo(`./AttendanceFlexibleTime?id=${item.id}`)
}
},
remove (id) {
this.$confirm('确定删除该数据?').then(() => {
this.$http.post(`/app/appattendanceconfig/delete?ids=${id}`).then(res => {
if (res.code == 0) {
this.$u.toast('删除成功')
this.getConfigList()
}
})
})
},
getConfigList () {
this.$http.post(`/api/appattendanceconfig/list?size=1`).then(res => {
if (res.code === 0) {
this.list = res.data.records.map(v => {
return {
...v,
title: v.type === '0' ? '固定时间上下班' : '灵活时间上下班',
workPointDesc: JSON.parse(v.workPointDesc)
}
})
}
this.pageShow = true
uni.hideLoading()
})
}
}
}
</script>
<style lang="scss" scoped>
.text-hover {
opacity: 0.7;
}
.bg-hover {
background: #eee;
}
.AttendanceSetting {
.tips {
line-height: 44px;
margin: 32px;
font-size: 28px;
color: #999999;
white-space: pre-line;
}
.config {
padding: 32rpx 32rpx 0;
background: #fff;
h2 {
margin-bottom: 24px;
color: #333333;
font-size: 32px;
font-weight: 600;
}
.config-wrapper {
padding-bottom: 32px;
.config-item {
display: flex;
align-items: center;
line-height: 40px;
margin-bottom: 8px;
font-size: 28px;
color: #333333;
label {
color: #999999;
}
&.config-item__line {
display: block;
span {
display: block;
}
}
}
}
.config-footer {
display: flex;
align-items: center;
height: 108px;
border-top: 1px solid #DDDDDD;
div {
flex: 1;
font-size: 32px;
color: #1365DD;
text-align: center;
&:last-child {
color: #FF4466;
}
}
}
}
.cell-group {
.cell-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 156px;
margin-bottom: 16px;
padding: 0 32px;
background: #FFFFFF;
&:active {
background: #eee;
}
image {
width: 32px;
height: 32px;
}
&:last-child {
margin-bottom: 0;
}
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
p {
color: #999999;
font-size: 28px;
}
}
}
}
</style>

View File

@@ -1,427 +0,0 @@
<template>
<div class="Attendance-address">
<AiTMap
:map.sync="map"
:lib.sync="lib"
:ops="ops"
:libraries="['service', 'tools']">
</AiTMap>
<u-popup v-model="isShow" :closeable="false" border-radius="32" height="70%" mode="bottom">
<div class="wrapper">
<div class="top">
<span @click="isShow = false">取消</span>
<span @click="confirm">确定</span>
</div>
<div class="address-search">
<div class="address-search__wrapper">
<image src="./images/search.png" />
<input placeholder-style="color: #98A6B6" placeholder="搜索地点" v-model="address" @input="onChange">
</div>
</div>
<scroll-view scroll-y scroll-into-view="address-item1">
<div class="address-item" :id="'address-item' + index" v-for="(item, index) in addressList" :key="index" @click="chooseAddress(index)">
<div class="left">
<h2>{{ item.title }}</h2>
<p>{{ item._distance >= 0 ? item._distance + 'm内' : '未知' }} | {{ item.address }}</p>
</div>
<div class="right" :class="[currIndex === index ? 'active' : '']"></div>
</div>
</scroll-view>
<div class="address-btn" v-if="!isChooseAddress">
<span>打卡有效范围</span>
<div class="right" @click="isShowScope = true">
<i>{{ distance[chooseIndex] }}</i>
<image src="./images/w-right.png" />
</div>
</div>
</div>
</u-popup>
<u-popup v-model="isShowScope" :closeable="false" :z-index="11111" border-radius="16" mode="bottom">
<div class="ActionSheet">
<div class="ActionSheet-list">
<div
@click="chooseDistance(index)"
v-for="(item, index) in distance"
:key="index"
:class="[chooseIndex === index ? 'active' : '']">
{{ item }}
</div>
</div>
<div class="cancel-btn" @click="isShowScope = false">取消</div>
</div>
</u-popup>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
name: 'ChooseAddess',
appName: '选择打卡点',
data () {
return {
latitude: '',
longitude: '',
isShow: false,
address: '',
currIndex: 0,
chooseIndex: 0,
isShowScope: false,
map: null,
ops: {},
lib: null,
map: null,
latLng: null,
distance: ['100', '200', '300', '400', '500'],
addressList: [],
page: 1,
marker: null,
timeout: null,
isChooseAddress: false
}
},
watch: {
map (v) {
if (v) {
this.init()
}
}
},
computed: {
...mapState(['user',])
},
onLoad (query) {
if (query.type === 'address') {
this.isChooseAddress = true
uni.setNavigationBarTitle({
title: '选择地点'
})
}
this.getLocation()
},
methods: {
...mapActions(['injectJWeixin']),
chooseDistance (index) {
this.chooseIndex = index
this.isShowScope = false
},
getLocation () {
this.injectJWeixin(['getLocation']).then(res => {
wx.getLocation({
type: 'wgs84',
success: res => {
this.longitude = res.longitude
this.latitude = res.latitude
},
error: res => {
console.log(res)
}
})
})
},
init () {
this.map.setZoom(19)
this.addMarker(this.map.getCenter())
this.map.on('click', e => {
this.addressList = []
this.latLng = e.latLng
this.isShow = true
this.addMarker(e.latLng)
this.getAddress()
})
},
confirm () {
const address = this.addressList[this.currIndex]
if (this.isChooseAddress) {
uni.$emit('filedChange', {
...uni.getStorageSync('formConfig'),
defaultValue: address.title
})
} else {
uni.$emit('address', {
address: address.address,
title: address.title,
lat: address.location.lat,
lng: address.location.lng,
distance: this.distance[this.chooseIndex]
})
}
uni.navigateBack({
delta: 1
})
},
chooseAddress (index) {
this.addMarker(this.addressList[index].location)
this.currIndex = index
},
addMarker (position) {
if (this.marker) {
this.marker.setMap(null)
this.marker = null
}
this.marker = new this.lib.MultiMarker({
id: 'marker-layer',
map: this.map,
styles: {
marker: new this.lib.MarkerStyle({
width: 30,
height: 45,
anchor: { x: 10, y: 30 }
}),
},
geometries: [{
id: 'marker',
styleId: 'marker',
position: position,
properties: {
title: 'marker'
}
}]
})
this.easeTo(position)
},
easeTo (position) {
this.map.easeTo({
center: position,
zoom: 17
},
{ duration: 500 })
},
onChange () {
if (this.timeout) {
clearTimeout(this.timeout)
}
this.timeout = setTimeout(() => {
this.currIndex = -1
new this.lib.service.Suggestion({
pageSize: 20
}).getSuggestions({
keyword: this.address
}).then(res => {
this.addressList = []
if (res.data.length) {
this.addressList = res.data
}
})
}, 500)
},
getAddress () {
this.currIndex = 0
new this.lib.service.Search({
pageSize: 20
}).explore({
center: this.latLng,
radius: 2000,
orderBy: '_distance'
}).then(res => {
this.addressList = []
if (res.data.length) {
this.addressList = res.data
}
})
}
}
}
</script>
<style lang="scss" scoped>
.Attendance-address {
width: 100%;
height: 100vh;
.ActionSheet {
background: #F5F6F6;
.ActionSheet-list {
margin-bottom: 8px;
background: #fff;
div {
height: 112px;
line-height: 112px;
text-align: center;
color: #333333;
font-size: 32px;
border-bottom: 1px solid #D8DDE6;
&.active {
color: #1365DD;
font-weight: 600;
}
&:active {
background: #eee;
}
&:last-child {
border: none;
}
}
}
.cancel-btn {
height: 112px;
line-height: 112px;
color: #333;
font-size: 32px;
text-align: center;
font-weight: 600;
background: #fff;
&:active {
background: #eee;
}
}
}
* {
box-sizing: border-box;
line-height: 1;
font-style: normal;
}
.wrapper {
height: 100%;
overflow: hidden;
scroll-view {
height: calc(100% - 308px);
padding: 0 32px;
.address-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32px 0;
border-bottom: 1px solid #EEEEEE;
&:last-child {
border: none;
}
.left {
flex: 1;
margin-right: 20px;
}
.right {
flex-shrink: 1;
width: 32px;
height: 32px;
border-radius: 50%;
border: 4px solid #CCCCCC;
transition: all ease 0.3s;
&.active {
border: 10px solid #1365DD;
}
}
h2 {
margin-bottom: 20px;
color: #222222;
font-weight: 600;
font-size: 34px;
}
p {
line-height: 1.2;
color: #999999;
font-size: 28px;
}
}
}
.address-search {
display: flex;
align-items: center;
height: 100px;
padding: 0 32px;
.address-search__wrapper {
display: flex;
align-items: center;
width: 100%;
height: 72px;
padding: 0 32px;
background: #F6F7F9;
border-radius: 36px;
image {
width: 48px;
height: 48px;
}
input {
flex: 1;
font-size: 26px;
color: #333;
}
}
}
.address-btn {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
line-height: 112px;
padding: 0 32px;
text-align: center;
color: #FFFFFF;
font-size: 32px;
background: #1365DD;
image {
width: 32px;
height: 32px;
margin-left: 4px;
}
.right {
display: flex;
align-items: center;
}
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
font-size: 32px;
color: #999;
font-weight: 600;
span:last-child {
color: #222;
}
}
}
map {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -1,189 +0,0 @@
<template>
<div class="Clipping">
<div class="photo-wrapper">
<!-- <image mode="widthFix" :src="img" /> -->
<kspCropper mode="free" ref="Cropper" :url="img" @ok="onOk"></kspCropper>
</div>
<div class="photo-footer">
<div class="title">
<span @click="back">返回</span>
<h2>剪裁</h2>
<span class="save-btn" @click="save">保存</span>
</div>
<scroll-view class="photo-bottom" scroll-x >
<!-- <div class="clipping-item" @click="currIndex = 0" :class="[currIndex === 0 ? 'active' : '']">
<image src="./images/clipping/yuantu.png" />
<span>原图</span>
</div> -->
<div class="clipping-item" @click="currIndex = 1" :class="[currIndex === 1 ? 'active' : '']">
<image src="./images/clipping/clipping5.png" />
<span>自由缩放</span>
</div>
<!-- <div class="clipping-item" @click="currIndex = 2" :class="[currIndex === 2 ? 'active' : '']">
<image src="./images/clipping/clipping4.png" />
<span>正方形</span>
</div>
<div class="clipping-item" @click="currIndex = 3" :class="[currIndex === 3 ? 'active' : '']">
<image src="./images/clipping/clipping3.png" />
<span>2:3</span>
</div>
<div class="clipping-item" @click="currIndex = 4" :class="[currIndex === 4 ? 'active' : '']">
<image src="./images/clipping/clipping2.png" />
<span>3:2</span>
</div>
<div class="clipping-item" @click="currIndex = 5" :class="[currIndex === 5 ? 'active' : '']">
<image src="./images/clipping/clipping1.png" />
<span>3:4</span>
</div> -->
</scroll-view>
</div>
</div>
</template>
<script>
import kspCropper from './components/ksp-cropper.vue'
export default {
name: 'Clipping',
appName: '图片剪裁',
components: {
kspCropper
},
data () {
return {
img: '',
currIndex: 1
}
},
onLoad (query) {
this.img = decodeURIComponent(query.url)
this.type = query.type
},
methods: {
back () {
uni.navigateBack({
delta: 1
})
},
save () {
this.$refs.Cropper.cropAppH5().then(res => {
console.log(res)
})
},
onOk (e) {
uni.$emit('cropper', e.path)
this.back()
},
rotateAngle () {
this.$refs.Cropper.rotateAngle()
}
}
}
</script>
<style lang="scss" scoped>
.Clipping {
position: relative;
width: 100%;
height: 100vh;
overflow-y: auto;
background: #000;
* {
box-sizing: border-box;
}
.photo-footer {
position: fixed;
left: 0;
bottom: 0;
z-index: 1;
width: 100%;
background: #FFFFFF;
border-radius: 32px 32px 0px 0px;
border: 1px solid #DDDDDD;
.title {
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 96px;
span {
position: absolute;
top: 50%;
left: 32px;
z-index: 1;
color: #222;
font-size: 32px;
font-weight: 600;
transform: translateY(-50%);
}
.save-btn {
left: initial;
right: 32px;
}
h2 {
color: #333;
font-size: 28px;
font-weight: 600;
}
}
.photo-bottom {
padding: 48px 48px;
font-size: 0;
white-space: nowrap;
.clipping-item {
display: inline-block;
margin-right: 48px;
text-align: center;
&:last-child {
margin-right: 0;
}
span {
display: block;
color: #333;
font-size: 28px;
}
image {
width: 80px;
height: 80px;
}
&.active {
span {
color: #3975C6;
}
}
}
}
}
.photo-wrapper {
display: flex;
align-items: center;
width: 100%;
height: calc(100vh - 312px);
& > image {
width: 100%;
}
}
}
</style>

View File

@@ -1,401 +0,0 @@
<template>
<div class="EditAlbum" v-if="pageShow">
<div class="img-item" v-for="(item, index) in list" :key="index" @click="choose(index)">
<u-lazy-load class="img" :height="182" :loading-img="$cdn + 'watermark/loading.png'" :image="item.photoUrl" img-mode="scaleToFill"></u-lazy-load>
<span class="icon" v-if="!item.checked"></span>
<image class="icon" v-else src="./images/img-choose.png" />
</div>
<span class="empty" v-if="!list.length">该相册暂无可编辑内容</span>
<div class="EditAlbum-footer">
<div @click="move">移动至</div>
<div @click="remove">删除</div>
</div>
<u-popup v-model="isShow" :closeable="false" border-radius="32" height="70%" mode="bottom">
<div class="album">
<div class="top">
<span @click="isShow = false">取消</span>
<span @click="confirm">确定</span>
</div>
<scroll-view scroll-y class="album-list__wrapper">
<div
class="item"
@click="currIndex = index"
v-for="(item, index) in albumList"
:key="index"
:class="[currIndex === index ? 'active' : '']">
<image class="checked" v-if="currIndex === index" src="./images/xuanzhong.png" />
<image class="icon" v-if="!item.lastPhotoUrl" src="./images/icon.png" />
<image class="img" v-if="item.lastPhotoUrl" :src="item.lastPhotoUrl" mode="aspectFill" />
<div class="item-bottom">
<h2>{{ item.albumName }}</h2>
<div class="item-bottom__info">
<div class="left">
<span>今日新增</span>
<i>{{ item.dayPhtoto }}</i>
<span></span>
</div>
<div class="right">
<image src="./images/zhaopianshuliang.png" />
<span>{{ item.photoTotal || 0 }}</span>
</div>
</div>
</div>
</div>
</scroll-view>
</div>
</u-popup>
</div>
</template>
<script>
export default {
appName: '相片编辑',
data () {
return {
id: '',
isShow: false,
list: [],
currIndex: 0,
albumList: [],
pageShow: false
}
},
computed: {
chooseImg () {
if (!this.list.length) {
return ''
}
return this.list.filter(v => v.checked).map(v => v.id).join(',')
}
},
onLoad (query) {
this.$loading()
this.id = query.id
this.getAlbumList()
this.$nextTick(() => {
this.getList()
})
},
methods: {
getList () {
this.$http.post(`/api/appalbumphoto/DetailByAlbumID`, null, {
params: {
albumId: this.id,
pageSize: 100000,
userId: this.$store.state.user.openId
}
}).then(res => {
if (res.code === 0) {
this.list = res.data.records.map(v => {
return {
...v,
checked: false
}
})
this.pageShow = true
}
})
},
confirm () {
this.$http.post(`/api/appalbumphoto/move?ids=${this.chooseImg}&targetId=${this.albumList[this.currIndex].id}`).then(res => {
if (res.code == 0) {
this.$u.toast('移入成功')
this.getAlbumList()
this.getList()
this.isShow = false
}
})
},
remove () {
if (!this.chooseImg) {
return this.$u.toast('请选择相片')
}
this.$confirm('确定删除这些图片?').then(() => {
this.$http.post(`/api/appalbumphoto/delete?ids=${this.chooseImg}`).then(res => {
if (res.code == 0) {
this.$u.toast('删除成功')
this.getAlbumList()
this.getList()
uni.$emit('update')
}
})
}).catch(() => {
})
},
move () {
if (!this.chooseImg) {
return this.$u.toast('请选择相片')
}
this.isShow = true
},
getAlbumList () {
this.$http.post('/api/appalbum/list', null, {
parmas: {
size: 1000
}
}).then(res => {
if (res.code === 0) {
this.albumList = res.data.records
}
})
},
choose (index) {
this.$set(this.list[index], 'checked', !this.list[index].checked)
}
}
}
</script>
<style lang="scss" scoped>
.EditAlbum {
min-height: 100vh;
padding: 16px 4px 130px;
font-size: 0;
box-sizing: border-box;
background: #1E1E21;
* {
box-sizing: border-box;
}
.empty {
position: absolute;
top: 160px;
left: 50%;
color: #8e8e90;
font-size: 28px;
transform: translateX(-50%);
}
.album {
height: 100%;
overflow: hidden;
.album-list__wrapper {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
.item {
display: inline-block;
position: relative;
width: 328px;
height: 328px;
margin-bottom: 32px;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 16px;
overflow: hidden;
background: #EFF5FA;
&:nth-of-type(2n) {
margin-left: 30px;
}
&.active {
border: 4px solid #2477F1;
}
.img {
width: 100%;
height: 100%;
}
.item-bottom {
position: absolute;
left: 0;
bottom: 0;
z-index: 1;
width: 100%;
padding: 20px 16px 16px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
& > h2 {
margin-bottom: 14px;
font-size: 32px;
color: #fff;
}
.item-bottom__info {
display: flex;
align-items: center;
justify-content: space-between;
.right {
display: flex;
align-items: center;
justify-content: space-between;
width: 86px;
height: 48px;
padding: 0 8px;
color: #fff;
background: rgba(0, 0, 0, 0.5);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
image {
width: 28px;
height: 28px;
}
span {
font-size: 28px;
}
}
.left {
span {
color: #c6c5c4;
font-size: 28px;
}
i {
padding: 0 3px;
color: #fff;
font-size: 28px;
font-style: normal;
}
}
}
}
& > span {
position: absolute;
left: 16px;
top: 16px;
z-index: 1;
width: 94px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 28px;
background: #FF524F;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
.icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 80px;
height: 80px;
transform: translate(-50%, -50%);
}
}
}
scroll-view {
height: calc(100% - 96px);
padding: 0 32px;
font-size: 0;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
font-size: 32px;
color: #999;
font-weight: 600;
span:last-child {
color: #222;
}
}
}
.EditAlbum-footer {
display: flex;
position: fixed;
align-items: center;
left: 0;
bottom: 0;
z-index: 11;
width: 100%;
height: 112px;
text-align: center;
background: #343437;
box-shadow: inset 0px 1px 0px 0px #666666, inset -1px 0px 0px 0px #666666;
div {
flex: 1;
line-height: 112px;
color: #fff;
font-size: 36px;
&:last-child {
border-left: 1px solid #666666;
}
}
}
.img-item {
display: inline-block;
position: relative;
width: 182px;
height: 182px;
margin-right: 4px;
margin-bottom: 4px;
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.02);
border-radius: 4px;
overflow: hidden;
.icon {
position: absolute;
top: 8px;
right: 8px;
z-index: 1;
width: 32px;
height: 32px;
content: ' ';
}
.img {
width: 182px;
height: 182px;
}
span {
width: 32px;
height: 32px;
background: rgba(0, 0, 0, 0.4);
border-radius: 16px;
border: 3px solid #FFFFFF;
}
&:nth-of-type(4n) {
margin-right: 0;
}
}
}
</style>

View File

@@ -1,153 +0,0 @@
<template>
<div class="form">
<div class="form-group">
<div class="form-item" :class="[config.fieldType === '1' ? 'textarea' : '']">
<span>{{ mapFieldLable(config.type) }}</span>
<div class="form-item__right" v-if="config.fieldType === '0'">
<input :placeholder="'请输入' + mapFieldLable(config.type)" :maxlength="10" v-model="config.defaultValue">
<span></span>
</div>
<div class="form-item__right" v-if="config.fieldType === 'date'" @click="isShowDate = true">
<span :style="{color: config.defaultValue ? '#333' : '#999'}">{{ config.defaultValue || '请选择' + mapFieldLable(config.type) }}</span>
<u-icon name="arrow-right" color="#E1E2E3" size="#E1E2E3"></u-icon>
</div>
<div class="form-item__right" v-if="config.fieldType === '1'">
<textarea :placeholder="'请输入' + mapFieldLable(config.type)" v-model="config.defaultValue" :maxlength="-1"></textarea>
</div>
</div>
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
<u-picker mode="time" v-model="isShowDate" :params="params" @confirm="onChange"></u-picker>
</div>
</template>
<script>
import { mapFieldLable } from './config'
export default {
appName: '相册相册',
data () {
return {
list: [],
mapFieldLable,
isShowDate: false,
params: {
year: true,
month: true,
day: true
},
currIndex: 0,
config: {
type: '',
fieldType: '',
defaultValue: ''
}
}
},
onLoad () {
this.config = {
...this.config,
...uni.getStorageSync('formConfig')
}
},
methods: {
onChange (e) {
this.$set(config, 'value', `${e.year}-${e.month}-${e.day}`)
},
save () {
uni.$emit('filedChange', this.config)
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.form {
padding-bottom: 130px;
* {
line-height: 1;
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.form-group {
margin-bottom: 16px;
padding: 0 32px;
background: #fff;
.form-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 120px;
font-size: 32px;
color: #333333;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border: none;
}
& > span {
margin-right: 20px;
}
&.textarea {
display: block;
height: auto;
padding: 32px 0;
textarea {
width: 100%;
margin-top: 20px;
text-align: left;
}
}
.form-item__right {
display: flex;
align-items: center;
justify-content: flex-end;
text-align: right;
height: 100%;
flex: 1;
span {
font-size: 30px;
color: #333;
}
input {
width: 100%;
height: 100%;
text-align: right;
font-size: 30px;
color: #333;
}
}
}
}
}
</style>

View File

@@ -1,157 +0,0 @@
<template>
<div class="message">
<div class="message-item" v-for="(item, index) in list" :key="index">
<h2>{{ item.createTime }}</h2>
<div v-if="item.channel !== '0'">{{ item.msg }}</div>
<div v-else>
<i v-for="(item, index) in item.msg" :key="index">
<i v-if="item.type === 0">{{ item.value }}</i>
<AiOpenData style="display: inline" v-else type="userName" :openid="item.value"></AiOpenData>
</i>
</div>
</div>
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
</div>
</template>
<script>
export default {
name: 'Message',
appName: '工作相册',
data () {
return {
size: 15,
current: 1,
isMore: false,
list: []
}
},
onLoad () {
this.getList()
},
methods: {
mapType (type) {
return {
'0': '照片查看',
'1': '照片上传',
'2': '打卡统计'
}[type]
},
getList () {
if (this.isMore) return
this.$loading()
this.$http.post(`/api/sysmessage/list`, null, {
params: {
size: 10,
current: this.current
}
}).then(res => {
if (res.code === 0) {
if (this.current > 1) {
this.list = [...this.list, ...res.data.records].map(v => {
let msg = v.content
if (v.channel === '0') {
if (v.content.split('$').length === 3) {
msg = v.content.split('$').map((v, index) => {
if (index === 1) {
return {
type: 1,
value: v.split('=')[1]
}
}
return {
type: 0,
value: v
}
})
}
}
return {
...v,
msg,
typeName: this.mapType(v.channel)
}
})
} else {
this.list = res.data.records.map(v => {
let msg = v.content
if (v.channel === '0') {
if (v.content.split('$').length === 3) {
msg = v.content.split('$').map((v, index) => {
if (index === 1) {
return {
type: 1,
value: v.split('=')[1]
}
}
return {
type: 0,
value: v
}
})
}
}
return {
...v,
msg,
typeName: this.mapType(v.channel)
}
})
}
if (res.data.records.length < 10) {
this.isMore = true
return false
}
this.current = this.current + 1
}
})
}
},
onReachBottom () {
this.getList()
}
}
</script>
<style lang="scss" scoped>
.message {
padding-bottom: 60px;
.message-item {
h2 {
padding: 48px 0 32px;
color: #666666;
font-size: 32px;
font-weight: normal;
text-align: center;
}
i {
font-style: normal;
}
& > div {
margin: 0 32px;
padding: 32px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.02);
font-size: 32px;
color: #333333;
line-height: 44px;
text-align: justify;
border-radius: 16px;
background: #fff;
}
}
}
</style>

View File

@@ -1,31 +0,0 @@
<template>
<div class="MovePhoto">
<image src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/64f71761d2b04746ad640a43706a92e4~tplv-k3u1fbpfcp-zoom-crop-mark:1304:1304:1304:734.awebp?" />
</div>
</template>
<script>
export default {
name: 'MovePhoto',
appName: '移动相片',
data () {
return {
}
},
onLoad () {
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,238 +0,0 @@
<template>
<div class="PersonnelSetting">
<div class="title">
<h2>拍摄人</h2>
<span>*选择拍摄人后相册只能上传该拍摄人照片</span>
</div>
<div class="cell-group">
<div class="cell-item" hover-class="bg-hover" @click="userList = [], currIndex = 0">
<div class="cell-item__left">
<h2>不限</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 0 ? 'active' : '']"></div>
</div>
<div class="cell-item" hover-class="bg-hover" @click="toChoose">
<div class="cell-item__left">
<h2>根据条件选择</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 1 ? 'active' : '']"></div>
</div>
</div>
<div class="user-wrapper" v-if="userList.length">
<div class="user" v-for="(item, index) in userList" :key="index">
<h2 class="user-left">
<AiOpenData v-if="item" type="userName" :openid="item"></AiOpenData>
</h2>
<image src="./images/remove.png" @click="remove(index)" />
</div>
</div>
<div class="tips">如选中人员未展示可能是未授权该成员应用权限需要先对这些成员进行应用授权 </div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
name: 'PersonnelSetting',
appName: '拍摄人选择',
data () {
return {
currIndex: 0,
userList: [],
ticket: '',
count: 0
}
},
onLoad (query) {
this.getInfo(query.id)
},
methods: {
...mapActions(['selectPrivilegedContact']),
linkTo (url) {
uni.navigateTo({
url
})
},
remove (index) {
this.userList.splice(index, 1)
},
save () {
if (this.currIndex === 1 && !this.userList.length) {
return this.$u.toast('请选择人员')
}
uni.$emit('watermarkChange', {
type: 'personnel',
value: this.userList.length ? this.userList : []
})
uni.navigateBack({
delta: 1
})
},
getInfo (id) {
this.$http.post(`/api/appalbum/queryDetailById?id=${id}`).then(res => {
if (res.code === 0) {
this.userList = res.data.albumUserList || []
this.currIndex = (res.data.albumUserList && res.data.albumUserList.length) ? 1 : 0
}
})
},
toChoose () {
this.$loading()
this.currIndex = 1
this.selectPrivilegedContact({
fromDepartmentId: 0,
selectedTickets: this.ticket ? [this.ticket] : [],
selectedOpenUserIds: this.userList
}).then(res => {
uni.hideLoading()
this.userList = res.userList.map(e => e.openUserId) || []
this.ticket = res.selectedTicket || ''
console.log(res)
}).catch(() => {
uni.hideLoading()
})
}
}
}
</script>
<style lang="scss" scoped>
.PersonnelSetting {
padding-bottom: 130px;
* {
box-sizing: border-box;
}
.user-wrapper {
background: #fff;
.user {
display: flex;
align-items: center;
justify-content: space-between;
height: 88px;
padding: 0 32px;
border-bottom: 1px solid #DDDDDD;
.user-left {
color: #333333;
font-size: 28px;
font-weight: 600;
}
image {
width: 32px;
height: 32px;
}
}
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.tips {
line-height: 44px;
margin: 32px;
font-size: 28px;
color: #999999;
white-space: pre-line;
}
.title {
display: flex;
padding: 20px 32px;
line-height: 1.3;
h2 {
font-weight: normal;
color: #666666;
font-size: 32px;
}
span {
flex: 1;
margin-left: 16px;
color: #999999;
font-size: 30px;
text-align: justify;
}
}
.cell-group {
.cell-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
margin-bottom: 16px;
padding: 0 32px;
background: #FFFFFF;
&:active {
background: #eee;
}
image {
width: 32px;
height: 32px;
}
&:last-child {
margin-bottom: 0;
}
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
p {
color: #999999;
font-size: 28px;
}
.cell-item__check {
flex-shrink: 1;
width: 32px;
height: 32px;
border-radius: 50%;
border: 4px solid #CCCCCC;
transition: all ease 0.3s;
&.active {
border: 10px solid #1365DD;
}
}
}
}
}
</style>

View File

@@ -1,181 +0,0 @@
<template>
<div class="photo" v-if="pageShow" @click="isShow = !isShow">
<div class="photo-wrapper">
<image mode="widthFix" :src="img" />
</div>
<div class="photo-bottom" :class="[isShow ? 'active' : '']">
<div class="top">
<h2>查看图片</h2>
<p>长按图片进行分享给他人</p>
<image @click.stop="isShow = false" src="./images/down_boldw.png" />
</div>
<div class="btns">
<div class="btn-item" hover-class="bg-hover" @click="back">
<image src="./images/fanhui-black.png" />
<span>返回</span>
</div>
<div class="btn-item" hover-class="bg-hover" v-if="createUserId === user.openId" @click="remove">
<image src="./images/remove-black.png" />
<span>删除</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Photo',
appName: '相片',
data () {
return {
img: '',
id: '',
isShow: true,
pageShow: false,
createUserId: ''
}
},
computed: {
...mapState(['user'])
},
onLoad (query) {
this.id = query.id
this.$loading()
this.$http.post(`/api/appalbumphoto/queryDetailById?id=${query.id}`).then(res => {
if (res.code == 0) {
this.img = res.data.photoUrl
this.createUserId = res.data.createUserId
}
this.$nextTick(() => {
this.pageShow = true
this.isShow = true
})
})
},
methods: {
back () {
uni.navigateBack({
delta: 1
})
},
remove () {
this.$confirm('确定删除该图片?').then(() => {
this.$http.post(`/api/appalbumphoto/delete?ids=${this.id}`).then(res => {
if (res.code == 0) {
this.$u.toast('删除成功')
uni.$emit('update')
this.back()
}
})
}).catch(() => {
})
}
}
}
</script>
<style lang="scss" scoped>
.photo {
position: relative;
width: 100%;
height: 100vh;
background: #000;
overflow-y: auto;
* {
box-sizing: border-box;
}
.photo-bottom {
position: fixed;
bottom: 0;
left: 0;
z-index: 11;
width: 100%;
transform: translateY(100%);
background: #fff;
border-radius: 32px 32px 0 0;
transition: all ease 0.4s;
&.active {
transform: translateY(0);
}
.top {
display: flex;
position: relative;
align-items: center;
justify-content: center;
flex-direction: column;
height: 96px;
h2 {
font-size: 28px;
color: #333333;
line-height: 40px;
}
p {
color: #999999;
font-size: 24px;
}
image {
position: absolute;
top: 50%;
right: 32px;
z-index: 1;
width: 32px;
height: 32px;
transform: translateY(-50%);
}
}
.btns {
display: flex;
align-items: center;
height: 216px;
div {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex: 1;
image {
width: 80px;
height: 80px;
}
span {
color: #333333;
font-size: 28px;
}
}
}
}
.photo-wrapper {
display: flex;
align-items: center;
width: 100%;
min-height: 100vh;
& > image {
width: 100%;
}
}
}
</style>

View File

@@ -1,145 +0,0 @@
<template>
<div class="photo-rank">
<div class="info-rank">
<div class="info-item__title">
<h2>成员拍照排名</h2>
</div>
<div class="info-rank__wrapper">
<div class="rank-item" v-for="(item, index) in list" :key="index">
<div class="rank-item__left">
<image src="./images/rank1.png" v-if="index === 0" />
<image src="./images/rank2.png" v-else-if="index === 1" />
<image src="./images/rank3.png" v-else-if="index === 2" />
<span v-else>{{ index + 1 > 9 ? index + 1 : '0' + (index + 1) }}</span>
<h2><AiOpenData v-if="item.name" type="userName" :openid="item.name"/></h2>
</div>
<div class="rank-item__right">
<span>已上传</span>
<i>{{ item.num }}</i>
<span></span>
</div>
</div>
<AiEmpty v-if="!list.length"></AiEmpty>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PhotoRank',
appName: '拍照排名',
data () {
return {
list: []
}
},
onLoad (query) {
this.getList(query.date)
},
methods: {
getList (date) {
this.$http.post(`/api/appattendancerecord/alluserphotosort?queryTime=${date}`).then(res => {
if (res.code === 0) {
this.list = Object.keys(res.data).map(v => {
return {
name: v,
num: res.data[v]
}
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.photo-rank {
padding: 32px 0 40px;
* {
box-sizing: border-box;
font-style: normal;
}
.info-rank {
margin: 0 32px;
padding: 0 32px 32px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.02);
border-radius: 16px;
&:last-child {
margin-bottom: 0;
}
.info-item__title {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
h2 {
font-weight: 600;
font-size: 32px;
color: #333;
}
}
.info-rank__wrapper {
.rank-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border-bottom: none;
}
& > div {
display: flex;
align-items: center;
}
.rank-item__right {
font-size: 28px;
color: #999999;
i {
color: #2E88FF;
}
}
.rank-item__left {
image {
width: 50px;
height: 50px;
margin-right: 32px;
}
span {
width: 60px;
margin-right: 22px;
padding-left: 6px;
color: #CCCCCC;
font-size: 32px;
font-weight: 600;
}
h2 {
color: #333333;
font-size: 32px;
}
}
}
}
}
}
</style>

View File

@@ -1,430 +0,0 @@
<template>
<div class="photo">
<div class="photo-top">
<div class="photo-top__middle" @click="isShow = true">
<span>保存至{{ albumName || '默认相册' }}</span>
<image src="./images/to-right.png" />
</div>
</div>
<div class="photo-wrapper">
<image mode="widthFix" :src="img" />
</div>
<div class="photo-footer">
<div class="item" @click="back">
<image src="./images/fanhui.png" />
<span>返回</span>
</div>
<div class="item" @click="upload">
<image src="./images/shangchuan.png" />
<span>上传</span>
</div>
</div>
<u-popup v-model="isShow" :closeable="false" border-radius="32" height="70%" mode="bottom">
<div class="album">
<div class="top">
<span @click="isShow = false">取消</span>
<span @click="onConfirm">确定</span>
</div>
<scroll-view scroll-y class="album-list__wrapper">
<div
class="item"
@click="currIndex = index"
v-for="(item, index) in albumList"
:key="index"
:class="[currIndex === index ? 'active' : '']">
<image class="checked" v-if="currIndex === index" src="./images/xuanzhong.png" />
<image class="icon" v-if="!item.lastPhotoUrl" src="./images/icon.png" />
<image class="img" v-if="item.lastPhotoUrl" :src="item.lastPhotoUrl" mode="aspectFill" />
<div class="item-bottom">
<h2>{{ item.albumName }}</h2>
<div class="item-bottom__info">
<div class="left">
<span>今日新增</span>
<i>{{ item.dayPhtoto }}</i>
<span></span>
</div>
<div class="right">
<image src="./images/zhaopianshuliang.png" />
<span>{{ item.photoTotal || 0 }}</span>
</div>
</div>
</div>
</div>
</scroll-view>
</div>
</u-popup>
</div>
</template>
<script>
export default {
name: 'Photo',
appName: '拼图汇报',
data () {
return {
img: '',
type: '',
albumList: [],
albumName: '',
albumId: '',
templateId: '',
isShow: false,
currIndex: 0,
fileId: ''
}
},
computed: {
defaultValue () {
if (!this.albumList.length) {
return [0]
}
return [this.albumList.map(v => v.value).indexOf(this.albumId)]
}
},
onLoad (query) {
this.img = query.img
this.type = query.type
this.templateId = query.templateId
this.albumId = query.albumId
this.fileId = query.fileId
this.getWatermarkList()
},
methods: {
back () {
uni.navigateBack({
delta: 1
})
},
upload () {
this.$loading()
this.$http.post('/api/appalbumphoto/addOrUpdate', {
albumId: this.albumId,
photoUrl: this.img,
watermarkType: this.type,
fileId: this.fileId,
templateId: this.templateId
}).then(res => {
if (res.code === 0) {
this.$u.toast('新增成功')
setTimeout(() => {
uni.reLaunch({
url: './AppCountryAlbum'
})
}, 500)
}
uni.hideLoading()
})
},
onConfirm () {
this.albumId = this.albumList[this.currIndex].value
this.albumName = this.albumList[this.currIndex].label
this.isShow = false
},
getWatermarkList () {
this.$http.post('/api/appalbum/list', null, {
parmas: {
size: 1000
}
}).then(res => {
if (res.code === 0) {
this.albumList = res.data.records.map(v => {
return {
...v,
label: v.albumName,
value: v.id
}
})
if (this.albumId) {
this.albumName = this.albumList.filter((v, index) => {
if (v.value === this.albumId) {
this.currIndex = index
}
return v.value === this.albumId
})[0].label
} else {
this.albumName = this.albumList[0].label
this.albumId = this.albumList[0].value
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.photo {
position: relative;
width: 100%;
height: 100vh;
overflow-y: auto;
background: #000;
* {
box-sizing: border-box;
}
.album {
height: 100%;
overflow: hidden;
.album-list__wrapper {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
.item {
display: inline-block;
position: relative;
width: 328px;
height: 328px;
margin-bottom: 32px;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 16px;
overflow: hidden;
background: #EFF5FA;
&:nth-of-type(2n) {
margin-left: 30px;
}
&.active {
border: 4px solid #2477F1;
}
.img {
width: 100%;
height: 100%;
}
.item-bottom {
position: absolute;
left: 0;
bottom: 0;
z-index: 1;
width: 100%;
padding: 20px 16px 16px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
& > h2 {
margin-bottom: 14px;
font-size: 32px;
color: #fff;
}
.item-bottom__info {
display: flex;
align-items: center;
justify-content: space-between;
.right {
display: flex;
align-items: center;
justify-content: space-between;
width: 86px;
height: 48px;
padding: 0 8px;
color: #fff;
background: rgba(0, 0, 0, 0.5);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
image {
width: 28px;
height: 28px;
}
span {
font-size: 28px;
}
}
.left {
span {
color: #c6c5c4;
font-size: 28px;
}
i {
padding: 0 3px;
color: #fff;
font-size: 28px;
font-style: normal;
}
}
}
}
& > span {
position: absolute;
left: 16px;
top: 16px;
z-index: 1;
width: 94px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 28px;
background: #FF524F;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
.icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 80px;
height: 80px;
transform: translate(-50%, -50%);
}
}
}
scroll-view {
height: calc(100% - 96px);
padding: 0 32px;
font-size: 0;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
font-size: 32px;
color: #999;
font-weight: 600;
span:last-child {
color: #222;
}
}
}
.photo-wrapper {
display: flex;
align-items: center;
width: 100%;
min-height: 100vh;
padding-bottom: 216px;
& > image {
width: 100%;
}
}
.photo-top {
display: flex;
position: fixed;
align-items: center;
justify-content: center;
top: 0;
left: 0;
z-index: 11;
width: 100%;
height: 128px;
padding: 0 32px;
background: rgba(0, 0, 0, 0.5);
& > image {
width: 28px;
height: 28px;
}
& > span {
color: #cbcbcb;
font-size: 32px;
}
.photo-top__middle {
display: flex;
align-items: center;
justify-content: center;
width: 400px;
height: 72px;
line-height: 1;
background: #0B111F;
border-radius: 40px;
font-size: 28px;
color: #cbcbcb;
span {
max-width: 70%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
image {
width: 32px;
height: 32px;
margin-left: 16px;
}
}
}
.photo-footer {
display: flex;
position: fixed;
align-items: center;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 216px;
background: #1E1E21;
.item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
text-align: center;
image {
width: 80px;
height: 80px;
}
span {
font-size: 28px;
color: #fff;
}
}
}
& > image {
width: 100%;
min-height: calc(100% - 216px);
}
}
</style>

View File

@@ -1,147 +0,0 @@
<template>
<div class="SourceSetting">
<div class="title">照片来源</div>
<div class="cell-group">
<div class="cell-item" hover-class="bg-hover" @click="currIndex = 0">
<div class="cell-item__left">
<h2>不限</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 0 ? 'active' : '']"></div>
</div>
<div class="cell-item" hover-class="bg-hover" @click="currIndex = 1">
<div class="cell-item__left">
<h2>仅限工作相册拍摄</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 1 ? 'active' : '']"></div>
</div>
</div>
<div class="tips">
选择不限后
1. 成员可以同步手机原相机数码相机等拍摄的照片和视频
2. 仅工作相册拍摄的照片或者视频会计入考勤保证考勤统计真实性
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
export default {
name: 'SourceSetting',
appName: '来源设置',
data () {
return {
currIndex: 0
}
},
onLoad (query) {
this.currIndex = Number(query.value)
},
methods: {
save () {
uni.$emit('watermarkChange', {
type: 'photoSource',
value: this.currIndex
})
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.SourceSetting {
* {
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.tips {
line-height: 44px;
margin: 32px;
font-size: 28px;
color: #999999;
white-space: pre-line;
}
.title {
height: 96px;
line-height: 96px;
padding: 0 32px;
color: #666666;
font-size: 32px;
}
.cell-group {
.cell-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
margin-bottom: 16px;
padding: 0 32px;
background: #FFFFFF;
&:active {
background: #eee;
}
image {
width: 32px;
height: 32px;
}
&:last-child {
margin-bottom: 0;
}
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
p {
color: #999999;
font-size: 28px;
}
.cell-item__check {
flex-shrink: 1;
width: 32px;
height: 32px;
border-radius: 50%;
border: 4px solid #CCCCCC;
transition: all ease 0.3s;
&.active {
border: 10px solid #1365DD;
}
}
}
}
}
</style>

View File

@@ -1,904 +0,0 @@
<template>
<div class="photo" :class="[isHide ? 'home-active' : '']" @click="isHide = true" :style="{height: height + 'px'}">
<div class="photo-top" data-html2canvas-ignore>
<div class="photo-top__middle" @click="isShowAlbum = true">
<span>保存至{{ albumName || '系统相册' }}</span>
<image src="./images/to-right.png" />
</div>
</div>
<div class="photo-wrapper">
<div ref="waterMarker" class="waterMarker-wrapper" :style="{height: canvasHeight + 'px'}">
<img class="waterMarker-img" :src="img" mode="widthFix" @load="onImgLoad" />
<div
class="watermark"
v-if="currIndex > -1 && currWatermarkConfig.length"
:style="{left: x + 'px', top: y + 'px', transform: 'scale(' + watermarkScale + ')', transformOrigin: 'left' }"
@touchstart="onTouchstart"
@touchmove="onTouchmove">
<component ref="WatermarkItem" :addressInfo="address" :is="'Watermark' + (currIndex + 1)" :config="currWatermarkConfig"></component>
<div v-if="!isHide" @click.stop="currIndex = -1" class="watermark-close" data-html2canvas-ignore>
<image src="./images/close-b.png" />
</div>
<span v-if="!isHide" class="watermark-edit" @click.stop="toEdit" data-html2canvas-ignore>编辑</span>
</div>
</div>
</div>
<div class="photo-bottom" data-html2canvas-ignore>
<div class="photo-bottom__top">
<span @click.stop="isHide = true">取消</span>
<h2>水印</h2>
<span @click.stop="isHide = true">确定</span>
</div>
<div class="waterlist">
<div
class="water-item"
:class="[currIndex === -1 ? 'active' : '']"
key="-1"
@click.stop="currIndex = -1">
<image src="./images/clear.png" />
<image class="checked" v-if="currIndex === -1" src="./images/xuanzhong.png" />
<div class="water-item__bottom">不使用水印</div>
</div>
<div
class="water-item"
:class="[currIndex === index ? 'active' : '']"
v-for="(item, index) in watermarkList"
:key="item.id"
@click.stop="currIndex = index">
<image :src="item.thum" />
<span v-show="currIndex === index" @click.stop="toEdit">编辑</span>
<image class="checked" v-if="currIndex === index" src="./images/xuanzhong.png" />
<div class="water-item__bottom">{{ item.name }}</div>
</div>
</div>
</div>
<div class="photo-tabbar" data-html2canvas-ignore>
<h2>编辑图片</h2>
<div class="tabbar-wrapper">
<div class="item" @click.stop="back">
<image src="./images/fanhui-black.png" />
<div>返回</div>
</div>
<div class="item" @click.stop="isHide = false">
<image src="./images/shuiyin-white.png" />
<div>水印</div>
</div>
<div class="item" @click.stop="toClipping">
<image src="./images/jiancai.png" />
<div>剪裁</div>
</div>
<div class="item" @click.stop="save">
<image src="./images/shangchuan-black.png" />
<div>上传</div>
</div>
</div>
</div>
<u-popup v-model="isShowAlbum" :closeable="false" border-radius="32" height="70%" mode="bottom">
<div class="album">
<div class="top">
<span @click="isShowAlbum = false">取消</span>
<span @click="onConfirm">确定</span>
</div>
<scroll-view scroll-y class="album-list__wrapper">
<div
class="item"
@click="albumIndex = index"
v-for="(item, index) in albumList"
:key="index"
:class="[albumIndex === index ? 'active' : '']">
<image class="checked" v-if="albumIndex === index" src="./images/xuanzhong.png" />
<image class="icon" v-if="!item.lastPhotoUrl" src="./images/icon.png" />
<image class="img" v-if="item.lastPhotoUrl" :src="item.lastPhotoUrl" mode="aspectFill" />
<div class="item-bottom">
<h2>{{ item.albumName }}</h2>
<div class="item-bottom__info">
<div class="left">
<span>今日新增</span>
<i>{{ item.dayPhtoto }}</i>
<span></span>
</div>
<div class="right">
<image src="./images/zhaopianshuliang.png" />
<span>{{ item.photoTotal || 0 }}</span>
</div>
</div>
</div>
</div>
</scroll-view>
</div>
</u-popup>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
import Watermark1 from './components/watermark/Watermark1'
import Watermark2 from './components/watermark/Watermark2'
import Watermark3 from './components/watermark/Watermark3'
import Watermark4 from './components/watermark/Watermark4'
import Watermark5 from './components/watermark/Watermark5'
import Watermark6 from './components/watermark/Watermark6'
import Watermark7 from './components/watermark/Watermark7'
import Watermark8 from './components/watermark/Watermark8'
import { mapActions, mapState } from 'vuex'
export default {
name: 'Watermark',
appName: '水印相机',
components: {
Watermark1,
Watermark2,
Watermark3,
Watermark4,
Watermark5,
Watermark6,
Watermark7,
Watermark8
},
data () {
return {
img: '',
currIndex: 0,
isHide: true,
height: '100%',
waterSrc: '',
albumId: '',
albumName: '',
albumIndex: 0,
watermarkList: [],
isShowAlbum: false,
albumList: [],
address: {},
x: 32,
y: 24,
startX: 0,
watermarkScale: 1,
startY: 0,
canvasHeight: 0
}
},
computed: {
defaultValue () {
if (!this.albumList.length) {
return [0]
}
return [this.albumList.map(v => v.value).indexOf(this.albumId)]
},
currWatermarkConfig () {
if (this.currIndex < 0 || !this.watermarkList.length) return []
return this.watermarkList[this.currIndex].itemList
},
...mapState(['wxwork'])
},
onLoad (query) {
if (query.albumId) {
this.albumId = query.albumId
}
this.img = decodeURIComponent(query.url)
this.height = uni.getSystemInfoSync().windowHeight
this.getLocation()
this.$nextTick(() => {
this.getWatermarkList()
})
uni.$on('cropper', e => {
this.img = e
this.x = 32
this.y = 200
})
},
mounted () {
// this.$nextTick(() => {
// document.body.addEventListener('touchmove', this.bindEvent, { passive: false })
// })
},
onUnload () {
uni.$off('cropper')
},
methods: {
...mapActions(['injectJWeixin', 'agentSign']),
toClipping () {
uni.navigateTo({
url: `./Clipping?url=${encodeURIComponent(this.img)}`
})
},
bindEvent (e) {
e.preventDefault()
},
onImgLoad () {
const img = document.querySelector('.waterMarker-img')
this.canvasHeight = img.clientHeight
this.watermarkScale = img.clientWidth / uni.getSystemInfoSync().windowWidth
},
onTouchstart (e) {
const isMobile = e.type !== 'mousemove'
const watermark = document.querySelector('.watermark')
if (isMobile) {
this.startX = e.touches[0].clientX - Number((watermark.style.left).replace('px', ''))
this.startY = e.touches[0].clientY - Number((watermark.style.top).replace('px', ''))
} else {
this.startX = e.clientX - Number((watermark.style.left).replace('px', ''))
this.startY = e.clientY -Number((watermark.style.top).replace('px', ''))
}
},
onTouchmove (e) {
const isMobile = e.type !== 'mousemove'
if (isMobile) {
this.x = e.touches[0].clientX - this.startX
this.y = e.touches[0].clientY - this.startY
} else {
this.x = e.clientX - this.startX
this.y = e.clientY - this.startY
}
},
toEdit () {
this.$refs.WatermarkItem.linkTo('./WatermarkConfig')
},
save () {
this.$loading()
this.isHide = true
this.$nextTick(() => {
html2canvas(this.$refs.waterMarker, {
allowTaint: true,
useCORS: true
}).then((canvas) => {
let dataURL = canvas.toDataURL('image/png')
const file = this.dataURLtoFile(dataURL, 'photo.png')
let formData = new FormData()
formData.append('file', file)
this.$http.post('/admin/file/add2?type=image', formData).then(res => {
if (res.code === 0) {
let info = {}
if (this.currIndex > -1) {
info = this.watermarkList[this.currIndex]
}
this.$http.post('/api/appalbumphoto/addOrUpdate', {
albumId: this.albumId,
photoUrl: res.data.url,
fileId: res.data.id,
watermarkType: this.currIndex > -1 ? info.watermarkType : '',
templateId: this.currIndex > -1 ? info.id : ''
}).then(res => {
if (res.code === 0) {
uni.$emit('update')
this.$u.toast('新增成功')
setTimeout(() => {
this.back()
}, 500)
} else {
this.$u.toast(res.msg)
}
})
}
})
}).catch(e => {
console.log(e)
})
})
},
getWeather (code) {
this.$http.post(`/api/bdweather/wdata?districtId=${code}`).then(res => {
if (res.code === 0) {
const data = res.data.result.now
uni.setStorageSync('address', {
...uni.getStorageSync('address'),
weather: `${data.text} ${data.temp}°` || ''
})
this.address = {
...uni.getStorageSync('address'),
weather: `${data.text} ${data.temp}°` || ''
}
}
})
},
getLocation () {
this.agentSign({
corpId: this.wxwork.config.corpId,
suiteId: this.wxwork.config.suiteId
}).then(() => {
this.injectJWeixin(['getLocation']).then(() => {
wx.getLocation({
type: 'wgs84',
success: res => {
var lat = res.latitude
var lng = res.longitude
this.$http.post('/api/appdvcpconfig/apiForward', `https://apis.map.qq.com/ws/geocoder/v1/?location=${lat},${lng}&key=3RZBZ-LZUCF-CT6J5-NWKZH-FCWOQ-UUFKY&get_poi=1`).then(res => {
if (res.code === 0) {
const data = res.data.result
uni.setStorageSync('address', {
lat,
lng,
address: data.address,
cityCode: `${data.ad_info.adcode}`
})
this.address = {
...uni.getStorageSync('address')
}
this.getWeather(`${data.ad_info.adcode}`)
}
})
},
error: res => {
console.log(res)
}
})
}).catch(e => {
})
})
},
dataURLtoFile (dataurl, filename) {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, { type: mime })
},
onConfirm () {
this.albumId = this.albumList[this.albumIndex].value
this.albumName = this.albumList[this.albumIndex].label
this.isShowAlbum = false
},
getWatermarkList () {
this.$http.post(`/api/appalbumtemplate/list?size=100&templateType=0`).then(res => {
if (res.code === 0) {
this.watermarkList = res.data.records
}
})
this.$http.post('/api/appalbum/list', null, {
params: {
size: 1000
}
}).then(res => {
if (res.code === 0) {
this.albumList = res.data.records.map(v => {
return {
...v,
label: v.albumName,
value: v.id
}
})
this.albumList.some((v, index) => {
if (this.albumId) {
if (v.value === this.albumId) {
this.albumIndex = index
this.albumName = v.label
return true
}
} else {
if (v.label === '系统相册') {
this.albumIndex = index
this.albumId = v.value
this.albumName = '系统相册'
return true
}
}
})
}
})
},
back () {
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.photo {
width: 100%;
background: #333;
overflow: hidden;
.photo-wrapper {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 128px;
left: 0;
width: 100%;
height: calc(100vh - 321px - 128px);
}
.newImg {
position: fixed;
left: 0;
top: 0;
z-index: 11111;
width: 100%;
height: 100%;
}
.album {
height: 100%;
overflow: hidden;
.album-list__wrapper {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
.item {
display: inline-block;
position: relative;
width: 328px;
height: 328px;
margin-bottom: 32px;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 16px;
overflow: hidden;
background: #EFF5FA;
&:nth-of-type(2n) {
margin-left: 30px;
}
&.active {
border: 4px solid #2477F1;
}
.img {
width: 100%;
height: 100%;
}
.item-bottom {
position: absolute;
left: 0;
bottom: 0;
z-index: 1;
width: 100%;
padding: 20px 16px 16px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
& > h2 {
margin-bottom: 14px;
font-size: 32px;
color: #fff;
}
.item-bottom__info {
display: flex;
align-items: center;
justify-content: space-between;
.right {
display: flex;
align-items: center;
justify-content: space-between;
width: 86px;
height: 48px;
padding: 0 8px;
color: #fff;
background: rgba(0, 0, 0, 0.5);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
image {
width: 28px;
height: 28px;
}
span {
font-size: 28px;
}
}
.left {
span {
color: #c6c5c4;
font-size: 28px;
}
i {
padding: 0 3px;
color: #fff;
font-size: 28px;
font-style: normal;
}
}
}
}
& > span {
position: absolute;
left: 16px;
top: 16px;
z-index: 1;
width: 94px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 28px;
background: #FF524F;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
.icon {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
width: 80px;
height: 80px;
transform: translate(-50%, -50%);
}
}
}
scroll-view {
height: calc(100% - 96px);
padding: 0 32px;
font-size: 0;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
font-size: 32px;
color: #999;
font-weight: 600;
span:last-child {
color: #222;
}
}
}
.waterMarker-wrapper {
position: relative;
max-height: calc(100vh - 321px - 128px);
overflow: hidden;
.waterMarker-img {
max-width: 100%;
object-fit: cover;
max-height: calc(100vh - 321px - 128px);
}
.watermark {
position: absolute;
left: 32px;
z-index: 11;
padding: 8px;
color: #FFFFFF;
font-size: 28px;
border: 2px solid #FFFFFF;
.watermark-edit {
position: absolute;
right: 0;
top: 0;
z-index: 1;
width: 80px;
height: 48px;
line-height: 48px;
text-align: center;
background: #FFFFFF;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
border-radius: 24px;
color: #222222;
font-size: 24px;
transform: translate(50%, -50%);
image {
width: 32px;
height: 32px;
}
}
.watermark-close {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
top: 0;
z-index: 1;
width: 48px;
height: 48px;
background: #FFFFFF;
border-radius: 50%;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.5);
transform: translate(-50%, -50%);
image {
width: 32px;
height: 32px;
}
}
}
}
* {
box-sizing: border-box;
}
.photo-tabbar {
position: fixed;
bottom: 0;
left: 0;
z-index: 10;
width: 100%;
height: 321px;
background: #FFFFFF;
border-radius: 32px 32px 0px 0px;
border: 1px solid #DDDDDD;
overflow: hidden;
h2 {
width: 750px;
height: 96px;
line-height: 96px;
margin-bottom: 20px;
text-align: center;
color: #333333;
font-size: 28px;
}
& > div {
align-items: center;
display: flex;
}
.item {
flex: 1;
text-align: center;
image {
width: 56px;
height: 56px;
margin-bottom: 6px;
}
div {
font-size: 28px;
color: #333;
}
}
}
.photo-bottom {
position: fixed;
bottom: 0;
left: 0;
z-index: 111;
width: 100%;
height: 474px;
background: #FFFFFF;
border-radius: 32px 32px 0px 0px;
transition: all ease 0.3s;
.waterlist {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
height: calc(100% - 96px);
padding: 18px 16px;
overflow-y: auto;
.water-item {
display: flex;
position: relative;
align-items: center;
justify-content: center;
width: 352px;
height: 240px;
margin-bottom: 16px;
background: #2A3540;
border-radius: 8px;
overflow: hidden;
&.active {
border: 6px solid #408EF6;
}
image {
width: 236px;
height: 200px;
}
span {
position: absolute;
left: 50%;
top: 50%;
z-index: 1;
width: 128px;
height: 56px;
line-height: 56px;
text-align: center;
background: rgba(0, 0, 0, 0.8);
border-radius: 8px;
color: #fff;
font-size: 32px;
transform: translate(-50%, -50%);
}
&:first-child {
flex-direction: column;
background: #E4E7EB;
& > image {
width: 64px;
height: 64px;
}
.water-item__bottom {
position: relative;
color: #8A93A4;
font-size: 28px;
background: transparent;
}
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
.water-item__bottom {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 56px;
line-height: 56px;
color: #fff;
text-align: center;
font-size: 28px;
background: rgba(0, 0, 0, 0.7);
}
}
}
.photo-bottom__top {
display: flex;
align-items: center;
justify-content: space-between;
height: 96px;
padding: 0 32px;
image {
width: 40px;
height: 40px;
}
h2 {
font-size: 28px;
color: #333;
}
span {
font-size: 32px;
color: #222;
font-weight: 600;
}
}
}
.photo-top {
display: flex;
position: fixed;
align-items: center;
justify-content: center;
top: 0;
left: 0;
z-index: 11;
width: 100%;
height: 128px;
padding: 0 32px;
background: rgba(0, 0, 0, 0.5);
& > image {
width: 28px;
height: 28px;
}
& > span {
color: #cbcbcb;
font-size: 32px;
}
.photo-top__middle {
display: flex;
align-items: center;
justify-content: center;
width: 400px;
height: 72px;
line-height: 1;
background: #0B111F;
border-radius: 40px;
font-size: 28px;
color: #cbcbcb;
span {
max-width: 70%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
image {
width: 32px;
height: 32px;
margin-left: 16px;
}
}
}
&.home-active {
.photo-bottom {
transform: translateY(100%);
}
.watermark {
border-color: transparent;
// bottom: 38px;
}
}
}
</style>

View File

@@ -1,212 +0,0 @@
<template>
<div class="AttendanceFiexdTime">
<div class="form-group">
<div class="form-group__item" @click.stop="onClick(item.editEnable)" hover-class="bg-hover" v-if="item.fieldType" v-for="(item, index) in config" :key="index">
<div class="left">
<switch @click.stop="onSwitchClick(item.editEnable)" :color="item.editEnable === '0' ? '#B7DBFD' : '#1088F9'" :checked="item.status === '1'" :disabled="item.editEnable === '0'" @change="e => onChange(e, index)" />
</div>
<div class="right" @click="toInput(item)" v-if="['6', '7'].indexOf(item.fieldType) === -1">
<div class="right-left">
<h2>{{ mapFieldLable(item.type) }}</h2>
<p :style="{color: item.defaultValue ? '#333' : '#999'}">{{ item.defaultValue || mapType(item.fieldType) }}</p>
</div>
<u-icon name="arrow-right" color="#E1E2E3" v-if="item.editEnable !== '0'"></u-icon>
</div>
<picker mode="date" :disabled="item.editEnable === '0'" style="flex: 1;" v-if="item.fieldType === '7'" :value="item.defaultValue" @change="e => onDateChange(e, index)">
<div class="right">
<div class="right-left">
<h2>{{ mapFieldLable(item.type) }}</h2>
<p>{{ item.defaultValue || '' }}</p>
</div>
<u-icon name="arrow-right" color="#E1E2E3" v-if="item.editEnable !== '0'"></u-icon>
</div>
</picker>
<picker mode="time" style="flex: 1;" :disabled="item.editEnable === '0'" v-if="item.fieldType === '6'" :value="item.defaultValue" @change="e => onDateChange(e, index)">
<div class="right">
<div class="right-left">
<h2>{{ mapFieldLable(item.type) }}</h2>
<p>{{ item.defaultValue || '' }}</p>
</div>
<u-icon name="arrow-right" color="#E1E2E3" v-if="item.editEnable !== '0'"></u-icon>
</div>
</picker>
</div>
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
import { mapFieldLable } from './config'
export default {
appName: '表单配置',
data () {
return {
config: [],
mapFieldLable
}
},
onLoad () {
this.config = uni.getStorageSync('waterConfig')
uni.$on('filedChange', e => {
this.config.forEach((v, index) => {
if (v.type === e.type) {
this.$set(this.config[index], 'defaultValue', e.defaultValue)
}
})
})
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
mapType (type) {
return {
'0': '请输入内容',
'1': '请输入内容',
'2': '请选择天气',
'3': '请选择地址',
'4': '请选择定位',
'5': '请选择经纬度',
'6': '请选择时间',
'7': '请选择日期'
}[type]
},
onDateChange (e, index) {
this.$set(this.config[index], 'defaultValue', e.detail.value)
},
onChange (e, index) {
this.$set(this.config[index], 'status', e.detail.value ? '1' : '0')
},
onSwitchClick (status) {
if (status === '0') {
return this.$u.toast('该选项不允许关闭')
}
},
onClick (status) {
if (status === '0') {
return this.$u.toast('该选项不允许修改内容')
}
},
toInput (e) {
if (e.editEnable === '0') return
if (e.fieldType === '2') return
if (e.fieldType === '3') {
uni.setStorageSync('formConfig', e)
this.linkTo('./ChooseAddess?type=address')
return false
}
uni.setStorageSync('formConfig', e)
this.linkTo('./Form')
},
save () {
for (let i = 0; i < this.config.length; i ++) {
if (['2', '3', '4', '5'].indexOf(this.config[i].fieldType) === -1 && this.config[i].fieldType && !this.config[i].defaultValue && this.config[i].status === '1') {
return this.$u.toast(`请输入${this.mapFieldLable(this.config[i].type)}`)
}
}
uni.$emit('change', this.config)
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.AttendanceFiexdTime {
padding-bottom: 130px;
* {
line-height: 1;
box-sizing: border-box;
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.form-group {
margin-bottom: 16px;
padding: 0 32px;
background: #fff;
.form-group__item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 32rpx 0;
font-size: 32px;
color: #333333;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border: none;
}
.right {
display: flex;
align-items: center;
flex: 1;
margin-left: 36px;
.right-left {
flex: 1;
h2 {
margin-bottom: 12px;
color: #999999;
font-size: 28px;
}
p {
line-height: 1.3;
font-size: 34px;
color: #333;
}
}
}
.left {
display: flex;
align-items: center;
margin-right: 10px;
}
}
}
}
</style>

View File

@@ -1,236 +0,0 @@
<template>
<div class="WatermarkSetting" v-if="pageShow">
<div class="title">
<h2>水印选择</h2>
<span>*选择水印后相册只能上传该水印照片</span>
</div>
<div class="cell-group">
<div class="cell-item" hover-class="bg-hover" @click="currIndex = 0, chooseIndex = -1">
<div class="cell-item__left">
<h2>不限</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 0 ? 'active' : '']"></div>
</div>
<div class="cell-item" hover-class="bg-hover" @click="currIndex = 1">
<div class="cell-item__left">
<h2>从库中选择水印</h2>
</div>
<div class="cell-item__check" :class="[currIndex === 1 ? 'active' : '']"></div>
</div>
</div>
<div class="title" v-if="currIndex === 1">
<h2>水印库</h2>
</div>
<div class="watermark-list" v-if="currIndex === 1">
<div class="item" @click="chooseIndex = index" v-for="(item, index) in list" :key="index" :class="[chooseIndex === index ? 'active' : '']">
<image class="checked" v-if="chooseIndex === index" src="./images/xuanzhong.png" />
<image class="watermark" :src="item.thum" mode="scaleToFill" />
</div>
</div>
<div class="form-btn" hover-class="text-hover" @click="save">保存</div>
</div>
</template>
<script>
import { config } from './config'
export default {
name: 'WatermarkSetting',
appName: '水印选择',
data () {
return {
currIndex: 0,
config,
list: [],
chooseIndex: -1,
id: '',
pageShow: false
}
},
onLoad (query) {
this.id = query.value
this.getList()
},
methods: {
getList () {
this.$loading()
this.$http.post(`/api/appalbumtemplate/list?size=1000&status=1`).then(res => {
if (res.code === 0) {
this.list = res.data.records
}
if (this.id) {
this.chooseIndex = this.list.map(v => v.id).indexOf(this.id)
this.currIndex = 1
}
this.pageShow = true
this.$hideLoading()
})
},
save () {
uni.$emit('watermarkChange', {
type: 'watermark',
value: this.chooseIndex > -1 ? this.list[this.chooseIndex].id : ''
})
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style lang="scss" scoped>
.WatermarkSetting {
padding-bottom: 130px;
* {
box-sizing: border-box;
}
.watermark-list {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
background: #fff;
padding: 16px;
.item {
display: flex;
position: relative;
align-items: center;
justify-content: center;
margin-bottom: 16px;
width: 352px;
height: 240px;
border-radius: 8px;
font-size: 0;
background: #2A3540;
&.active {
border: 4px solid #2477F1;
}
.checked {
position: absolute;
top: 0;
right: 0;
z-index: 1;
width: 64px;
height: 64px;
}
.watermark {
width: 236px;
height: 200px;
}
&:nth-of-type(2n) {
margin-right: 0;
}
}
}
.form-btn {
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
width: 100%;
height: 112px;
line-height: 112px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1365DD;
&:active {
opacity: 0.8;
}
}
.tips {
line-height: 44px;
margin: 32px;
font-size: 28px;
color: #999999;
white-space: pre-line;
}
.title {
display: flex;
align-items: center;
height: 96px;
padding: 0 32px;
h2 {
font-weight: normal;
color: #666666;
font-size: 32px;
}
span {
margin-left: 16px;
color: #999999;
font-size: 30px;
}
}
.cell-group {
.cell-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
margin-bottom: 16px;
padding: 0 32px;
background: #FFFFFF;
&:active {
background: #eee;
}
image {
width: 32px;
height: 32px;
}
&:last-child {
margin-bottom: 0;
}
h2 {
margin-bottom: 12px;
color: #333333;
font-size: 32px;
}
p {
color: #999999;
font-size: 28px;
}
.cell-item__check {
flex-shrink: 1;
width: 32px;
height: 32px;
border-radius: 50%;
border: 4px solid #CCCCCC;
transition: all ease 0.3s;
&.active {
border: 10px solid #1365DD;
}
}
}
}
}
</style>

View File

@@ -1,600 +0,0 @@
<template>
<div class="album-home" ref="home">
<div class="userinfo">
<image :src="$cdn + 'avatar.png'" />
<div class="right">
<h2><AiOpenData v-if="user.wxOpenUserId" type="userName" :openid="user.wxOpenUserId"></AiOpenData></h2>
<p>欢迎使用工作相册</p>
</div>
</div>
<div class="album-total">
<div class="album-total__item">
<span>今日拍照人数</span>
<i>{{ countPhotographer || 0 }}</i>
</div>
<div class="album-total__item">
<span>今日拍照数量</span>
<i>{{ countPhotoNo || 0 }}</i>
</div>
</div>
<div class="space">
<div class="space-top">
<h2>相册空间({{ user.editionName }})</h2>
<span>{{ user.usedStorageSpaceStr || 0 }} / {{ user.storageSpaceStr }}</span>
</div>
<div class="rate">
<span :style="{width: rate + '%'}"></span>
</div>
</div>
<div class="album-operate">
<div class="left">
<div class="left-item" @click="addPhoto">
<image src="../images/paizhao.png" />
<span>拍照</span>
</div>
<div class="left-item" @click="linkTo('./AddReport')">
<image src="../images/pintu.png" />
<span>拼图汇报</span>
</div>
</div>
<div class="right">
<div class="right-top">
<image class="right-top__left" src="../images/xiaoxizhushou.png"/>
<image @click="linkTo('./Message')" class="right-top__right" src="../images/gengduo1.png" />
</div>
<div class="right-info">
<div class="right-info__news" v-if="msgInfo.content">
<span>最新</span>
<i v-if="msgInfo.channel !== '0'">{{ msgInfo.content }}</i>
<div style="display: inline" v-else>
<i v-for="(item, index) in msgInfo.msg" :key="index">
<i v-if="item.type === 0">{{ item.value }}</i>
<AiOpenData style="display: inline" v-else type="userName" :openid="item.value"></AiOpenData>
</i>
</div>
</div>
<i v-else>暂无消息</i>
<p>{{ msgInfo.createTime || '' }}</p>
</div>
</div>
</div>
<div class="album-list">
<h2>工作相册</h2>
<div class="album-list__wrapper">
<div class="item" v-for="(item, index) in list" :key="index" @click="linkTo('./AlbumDetail?id=' + item.id)">
<image src="./../images/icon.png" :loading-img="$cdn + 'watermark/loading.png'" v-if="!item.lastPhotoUrl" />
<u-lazy-load class="item-img" img-mode="aspectFill" :height="328" :image="item.lastPhotoUrl" v-else></u-lazy-load>
<div class="item-bottom">
<h2>{{ item.albumName }}</h2>
<div class="item-bottom__info">
<div class="left">
<span>今日新增</span>
<i>{{ item.dayPhtoto }}</i>
<span></span>
</div>
<div class="right">
<image src="../images/zhaopianshuliang.png" />
<span>{{ item.photoTotal }}</span>
</div>
</div>
</div>
</div>
<div class="item item-add" @click="linkTo('./AddAlbum')">
<div class="item-add__btn"></div>
<p>添加相册</p>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Home',
data () {
return {
countPhotoNo: '',
countPhotographer: '',
list: [],
msgInfo: {}
}
},
computed: {
...mapState(['user']),
rate () {
if (!this.user.usedStorageSpace) {
return 0
}
return ((this.user.usedStorageSpace || 0) / this.user.storageSpace * 100)
}
},
mounted () {
this.getCountPhotoNo()
this.getAlbumList()
this.getMsgList()
this.getUserInfo()
},
destroyed () {
uni.$off('update')
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
},
update () {
this.getCountPhotoNo()
this.getAlbumList()
this.getMsgList()
this.getUserInfo()
},
getUserInfo () {
this.$http.post('/api/user/info').then(res => {
if (res.code === 0) {
this.$store.commit('setUser', res.data)
}
})
},
getCountPhotoNo () {
this.$http.post('/api/appalbumphoto/countPhotoNo').then(res => {
if (res.code === 0) {
this.countPhotoNo = res.data
}
})
this.$http.post('/api/appalbumphoto/countPhotographer').then(res => {
if (res.code === 0) {
this.countPhotographer = res.data
}
})
},
getMsgList () {
this.$http.post('/api/sysmessage/latestnews').then(res => {
if (res.code === 0) {
if (res.data) {
this.msgInfo = res.data
let msg = res.data.content
if (res.data.channel === '0') {
if (res.data.content.split('$').length === 3) {
msg = res.data.content.split('$').map((v, index) => {
if (index === 1) {
return {
type: 1,
value: v.split('=')[1]
}
}
return {
type: 0,
value: v
}
})
}
}
this.msgInfo.msg = msg
}
}
})
},
getAlbumList () {
this.$http.post('/api/appalbum/list', null, {
params: {
size: 10000
}
}).then(res => {
if (res.code === 0) {
this.list = res.data.records
}
})
},
addPhoto () {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: res => {
this.linkTo(`./Watermark?url=${encodeURIComponent(res.tempFilePaths[0])}`)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.album-home {
padding: 50px 32px 120px;
* {
box-sizing: border-box;
}
.space {
margin-top: 32px;
padding: 24px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.02);
border-radius: 16px;
.rate {
display: flex;
position: relative;
align-items: center;
width: 100%;
height: 8px;
background: #EEEEEE;
border-radius: 4px;
overflow: hidden;
span {
position: absolute;
top: 0;
left: 0;
height: 100%;
border-radius: 4px;
background: #2BB1FF;
}
}
.space-top {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
h2 {
font-size: 32px;
font-weight: 600;
color: #333;
}
span {
font-size: 36px;
font-weight: 600;
color: #3B424A;
}
}
}
.album-list {
& > h2 {
height: 96px;
line-height: 96px;
color: #333333;
font-size: 36px;
font-weight: 600;
}
.item-add {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: #EFF5FA;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 16px;
border: 2px solid #FFFFFF;
p {
margin-top: 16px;
font-size: 26px;
color: #999;
}
.item-add__btn {
position: relative;
width: 64px;
height: 64px;
border-radius: 50%;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
&::after {
position: absolute;
left: 50%;
top: 50%;
z-index: 1;
width: 4px;
height: 32px;
background: #333333;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 4px;
transform: translate(-50%, -50%);
content: ' ';
}
&::before {
position: absolute;
left: 50%;
top: 50%;
z-index: 1;
width: 32px;
height: 4px;
background: #333333;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 4px;
transform: translate(-50%, -50%);
content: ' ';
}
}
}
.album-list__wrapper {
display: flex;
align-items: center;
flex-wrap: wrap;
justify-content: space-between;
.item {
display: flex;
position: relative;
align-items: center;
justify-content: center;
width: 328px;
height: 328px;
margin-top: 32px;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 16px;
overflow: hidden;
background: #EFF5FA;
.item-bottom {
position: absolute;
left: 0;
bottom: 0;
z-index: 1;
width: 100%;
padding: 20px 16px 16px;
background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
& > h2 {
margin-bottom: 14px;
font-size: 32px;
color: #fff;
}
.item-bottom__info {
display: flex;
align-items: center;
justify-content: space-between;
.right {
display: flex;
align-items: center;
justify-content: space-between;
width: 86px;
height: 48px;
padding: 0 8px;
color: #fff;
background: rgba(0, 0, 0, 0.5);
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
image {
width: 28px;
height: 28px;
}
}
.left {
span {
color: #c6c5c4;
font-size: 28px;
}
i {
padding: 0 3px;
color: #fff;
font-size: 28px;
}
}
}
}
& > span {
position: absolute;
left: 16px;
top: 16px;
z-index: 1;
width: 94px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 28px;
background: #FF524F;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.1);
border-radius: 8px;
}
& > image {
width: 80px;
height: 80px;
}
.item-img {
width: 100%;
height: 100%;
}
}
}
}
.album-operate {
display: flex;
align-items: center;
margin: 48px 0 32px;
.right {
flex: 1;
height: 256px;
padding: 24px;
background: #2BB1FF;
box-shadow: 0px 4px 8px 0px rgba(25, 81, 129, 0.12);
border-radius: 16px;
.right-top {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 26px;
.right-top__left {
width: 136px;
height: 32px;
}
.right-top__right {
width: 32px;
height: 32px;
}
}
.right-info {
& > i {
display: block;
padding-top: 14px;
color: #f8fcff;
font-size: 28px;
}
.right-info__news {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
margin-bottom: 12px;
span {
display: inline-block;
width: 68px;
height: 40px;
line-height: 40px;
margin-right: 8px;
text-align: center;
background: #FFBC5E;
border-radius: 8px;
color: #FFFFFF;
}
i {
color: #fff;
font-size: 28px;
}
}
p {
color: #fff;
opacity: 0.8;
font-size: 28px;
}
}
}
.left {
display: flex;
align-items: center;
justify-content: space-between;
flex-direction: column;
width: 288px;
height: 256px;
margin-right: 16px;
.left-item {
display: flex;
align-items: center;
width: 288px;
height: 120px;
padding-left: 48px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.02);
border-radius: 16px;
&:first-child {
margin-bottom: 26px;
}
span {
color: #333333;
font-size: 32px;
font-weight: 600;
}
image {
width: 32px;
height: 32px;
margin-right: 16px;
}
}
}
}
.userinfo {
display: flex;
align-items: center;
margin-bottom: 50px;
image {
width: 112px;
height: 112px;
margin-right: 24px;
border-radius: 50%;
}
.right {
h2 {
margin-bottom: 10px;
font-weight: 600;
color: #333333;
font-size: 44px;
}
p {
font-size: 28px;
color: #999999;
}
}
}
i, em {
font-style: normal;
}
.album-total {
display: flex;
align-items: center;
.album-total__item {
display: flex;
flex: 1;
font-size: 28px;
i {
color: #3B424A;
font-weight: 600;
}
span {
margin-right: 16px;
color: #999999;
}
}
}
}
</style>

View File

@@ -1,391 +0,0 @@
<template>
<div class="Organize">
<div class="Organize-top">
<div>
<div class="left">
<h2>{{ DD }}</h2>
<div class="left-wrapper__right">
<h3>{{ yyyyMM }}</h3>
<p>·数据统计</p>
</div>
</div>
<div class="right" @click="isShow = true">
<image src="../images/qiehuan.png" />
<span>切换日期</span>
</div>
</div>
</div>
<div class="info">
<div class="info-item info-total">
<div class="info-item__title">
<h2>拍照统计</h2>
</div>
<div class="info-total__wrapper">
<div class="info-total__item">
<span>未拍照</span>
<div class="info-total__item--bottom">
<h3>{{ photoTotal.noPhtoto }}</h3>
<i></i>
</div>
</div>
<div class="info-total__item">
<span>已拍照</span>
<div class="info-total__item--bottom">
<h3>{{ photoTotal.userPhoto }}</h3>
<i></i>
</div>
</div>
<div class="info-total__item">
<span>拍照数</span>
<div class="info-total__item--bottom">
<h3>{{ photoTotal.allPhoto }}</h3>
<i></i>
</div>
</div>
</div>
</div>
<div class="info-item info-rank">
<div class="info-item__title">
<h2>成员拍照排名</h2>
<image src="../images/right.png" @click="linkTo('./PhotoRank?date=' + date.replace(/年|月/g, '-'))" />
</div>
<div class="info-rank__wrapper">
<div class="rank-item" v-for="(item, index) in list" :key="index">
<div class="rank-item__left">
<image src="../images/rank1.png" v-if="index === 0" />
<image src="../images/rank2.png" v-else-if="index === 1" />
<image src="../images/rank3.png" v-else-if="index === 2" />
<span v-else>{{ index + 1 > 9 ? index + 1 : '0' + (index + 1) }}</span>
<h2><AiOpenData v-if="item.name" type="userName" :openid="item.name"/></h2>
</div>
<div class="rank-item__right">
<span>已上传</span>
<i>{{ item.num }}</i>
<span></span>
</div>
</div>
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
</div>
</div>
</div>
<u-calendar v-model="isShow" mode="date" @change="onDateChange"></u-calendar>
</div>
</template>
<script>
export default {
name: 'Organize',
data () {
return {
photoTotal: {},
date: '',
list: [],
isMore: false,
isShow: false,
yyyyMM: '',
DD: ''
}
},
mounted () {
this.date = this.$dayjs(new Date).format('YYYY年MM月DD')
this.yyyyMM = this.$dayjs(new Date).format('YYYY年MM月')
this.DD = this.$dayjs(new Date).format('DD')
this.getPhotoTotal()
},
methods: {
getPhotoTotal () {
this.$http.post(`/api/appattendancerecord/punchclocksum?queryTime=${this.date.replace(/年|月/g, '-')}`).then(res => {
if (res.code === 0) {
this.photoTotal = res.data
}
})
this.$http.post(`/api/appattendancerecord/userphotosort?queryTime=${this.date.replace(/年|月/g, '-')}`).then(res => {
if (res.code === 0) {
this.list = Object.keys(res.data).map(v => {
return {
name: v,
num: res.data[v]
}
})
this.isMore = true
}
})
},
onDateChange (e) {
this.date = `${e.year}${e.month > 9 ? e.month : '0' + e.month}${e.day > 9 ? e.day : '0' + e.day}`
this.yyyyMM = `${e.year}${e.month > 9 ? e.month : '0' + e.month}`
this.DD = e.day > 9 ? e.day : '0' + e.day
this.$nextTick(() => {
this.getPhotoTotal()
})
},
linkTo (url) {
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Organize {
padding: 0 0 40px;
* {
box-sizing: border-box;
line-height: 1;
}
i, em {
font-style: normal;
}
.info {
position: relative;
top: -116px;
padding: 0 32px;
.info-item {
margin-bottom: 32px;
padding: 0 32px 32px;
background: #FFFFFF;
box-shadow: 0px 4px 8px 0px rgba(17, 67, 110, 0.02);
border-radius: 16px;
&:last-child {
margin-bottom: 0;
}
.info-rank__wrapper {
.rank-item {
display: flex;
align-items: center;
justify-content: space-between;
height: 112px;
border-bottom: 1px solid #DDDDDD;
&:last-child {
border-bottom: none;
}
& > div {
display: flex;
align-items: center;
}
.rank-item__right {
font-size: 28px;
color: #999999;
i {
color: #2E88FF;
}
}
.rank-item__left {
image {
width: 50px;
height: 50px;
margin-right: 32px;
}
span {
width: 60px;
margin-right: 22px;
padding-left: 6px;
color: #CCCCCC;
font-size: 32px;
font-weight: 600;
}
h2 {
color: #333333;
font-size: 32px;
}
}
}
}
.info-work__wrapper {
.top {
display: flex;
align-items: flex-end;
justify-content: space-between;
& > span {
font-size: 32px;
font-weight: 600;
color: #333333;
}
.left {
display: flex;
align-items: baseline;
h2 {
position: relative;
top: 6px;
color: #333;
font-size: 56px;
}
span {
font-size: 32px;
color: #333;
}
i {
margin-left: 12px;
font-size: 32px;
color: #999999;
}
}
}
.progress {
position: relative;
height: 16px;
margin-top: 32px;
margin-bottom: 16px;
background: #EEEEEE;
border-radius: 4px;
overflow: hidden;
& > div {
position: absolute;
top: 0;
left: 0;
height: 16px;
border-radius: 4px;
background: #2E88FF;
}
}
}
.info-total__wrapper {
display: flex;
align-items: center;
& > div {
display: flex;
justify-content: center;
flex-direction: column;
flex: 1;
height: 156px;
margin-right: 18px;
padding: 0 24px;
background: #FFFFFF;
border-radius: 8px;
border: 1px solid #E6E6E7;
&:last-child {
margin-right: 0;
}
.info-total__item--bottom {
display: flex;
align-items: center;
line-height: 1;
}
span {
margin-bottom: 20px;
font-size: 28px;
color: #333;
font-weight: 600;
}
i {
color: #333333;
font-size: 26px;
}
}
}
.info-item__title {
display: flex;
align-items: center;
justify-content: space-between;
height: 108px;
h2 {
font-weight: 600;
font-size: 32px;
color: #333;
}
image {
width: 32px;
height: 32px;
}
}
}
}
.Organize-top {
height: 320px;
width: 100%;
padding: 58px 32px 0;
background: #3975C6;
& > div {
display: flex;
justify-content: space-between;
align-items: center;
}
.right {
display: flex;
align-items: center;
height: 56px;
padding: 0 36px;
background: #285DA4;
border-radius: 28px;
image {
width: 36px;
height: 26px;
margin-right: 12px;
}
span {
color: #FFFFFF;
font-size: 28px;
}
}
.left {
display: flex;
align-items: center;
line-height: 1;
h2 {
margin-right: 16px;
font-size: 100px;
font-weight: 600;
color: #FFFFFF;
}
h3 {
margin-bottom: 8px;
color: #a9c3e6;
font-size: 28px;
}
p {
font-size: 32px;
color: #FFFFFF;
}
}
}
}
</style>

View File

@@ -1,64 +0,0 @@
<template>
<div class="form-wrapper">
<div class="form-content">
<Home ref="Home" v-if="currIndex === 0" @change="onChange"/>
<Organize ref="Organize" v-if="currIndex === 1" @change="onChange"/>
</div>
<AiTabbar :active.sync="currIndex" :list="tabBar"/>
</div>
</template>
<script>
import Home from './Home.vue'
import Organize from './Organize.vue'
export default {
name: 'Tabbar',
appName: '工作相册',
data() {
return {
currIndex: 0
}
},
components: {
Home,
Organize
},
computed: {
tabBar() {
const link = icon => `${this.$cdn}watermark/${icon}.png`
return [
{text: "相册", iconPath: "xiangce", selectedIconPath: "xiangce-active"},
{text: "组织", iconPath: "zuzhi", selectedIconPath: "zuzhi-active"}
].map(e => ({
...e,
iconPath: link(e.iconPath),
selectedIconPath: link(e.selectedIconPath)
}))
}
},
methods: {
onChange(e) {
this.$emit('change', e)
},
show() {
if (this.currIndex == 0) {
this.$nextTick(() => {
this.$refs.Home.update()
})
}
}
},
onReachBottom() {
if (this.currIndex === 0) {
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -1,954 +0,0 @@
<template>
<view style="width: 100%; height: 100%; position: relative;" v-show="url" :mode="modeValue" :change:mode="mwx.changeMode" :rotate="rotate" :change:rotate="mwx.changeRotate">
<!-- #ifdef MP-WEIXIN -->
<canvas type="2d" class="canvas" :style="{width: target.width + 'px', height: target.height + 'px'}"></canvas>
<!-- #endif -->
<!-- #ifdef APP-PLUS || H5 -->
<canvas :canvas-id="canvasId" :style="{width: target.width + 'px', height: target.height + 'px'}"></canvas>
<!-- #endif -->
<view class="panel">
<view class="body" @touchstart="mwx.touchstart" @touchmove="mwx.touchmove" @touchend="mwx.touchend" @touchcancel="mwx.touchcancel">
<view class="image-wrap" :class="{transit: transit}" :change:rect="mwx.changeImage" :rect="image">
<image class="image" mode="widthFix" :class="{transit: transit}" :src="url" @load="imageLoad"/>
</view>
<view class="mask"></view>
<view class="frame" :class="{transit: transit}" :change:rect="mwx.changeFrame" :rect="frame">
<view class="rect">
<view class="image-rect" :class="{transit: transit}">
<image class="image" :class="{transit: transit}" :src="url"/>
</view>
</view>
<view class="line-one"></view>
<view class="line-two"></view>
<view class="line-three"></view>
<view class="line-four"></view>
<view class="frame-left-top" @touchstart="mwx.touchstart"></view>
<view class="frame-left-bottom" @touchstart="mwx.touchstart"></view>
<view class="frame-right-top" @touchstart="mwx.touchstart"></view>
<view class="frame-right-bottom" @touchstart="mwx.touchstart"></view>
</view>
</view>
<!-- <view class="toolbar">
<view @tap="oncancle" class="btn-cancel">取消</view>
<view @tap="rotateAngle" class="btn-rotate">旋转</view>
<view @tap="onok" class="btn-ok">确定</view>
</view> -->
</view>
</view>
</template>
<script>
/**
* @property {String} mode 模式
* @value fixed 固定模式,裁剪出固定大小
* @value ratio 等比模式,宽高等比缩放
* @value free 自由模式,不限制宽高比
* @property {String} url 图片路径
* @property {Number} width 宽度
* @property {Number} height 高度
* @property {Number} maxWidth 最大宽带
* @property {Number} minHeight 最大高度
*/
export default {
props: {
mode: {
type: String,
default: "free"
},
url: {
type: String,
default: ""
},
width: {
type: Number,
default: 200
},
height: {
type: Number,
default: 200
},
maxWidth: {
type: Number,
default: 10240
},
maxHeight: {
type: Number,
default: 10240
}
},
data() {
return {
canvasId: Math.random().toString(36).slice(-6),
real: {
width: 100,
height: 100
},
target: {
width: 100,
height: 100
},
body: {
width: 100,
height: 100
},
frame: {
left: 50,
top: 50,
width: 200,
height: 300
},
image: {
left: 20,
top: 20,
width: 300,
height: 400
},
rotate: 0,
transit: false,
modeValue: ""
};
},
methods: {
imageLoad(event) {
this.real.width = event.detail.width;
this.real.height = event.detail.height;
this.target = {};
var query = uni.createSelectorQuery().in(this);
query.select(".body").boundingClientRect((data) => {
this.body.width = data.width;
this.body.height = data.height;
this.init();
}).exec();
},
init() {
this.modeValue = this.mode;
this.rotate = 0;
var rate = this.width / this.height;
var width = this.body.width * 0.7;
var height = this.body.height * 0.7;
if (width / height > rate) {
width = height * rate;
} else {
height = width / rate;
}
var left = (this.body.width - width) / 2;
var top = (this.body.height - height) / 2;
this.frame = {
left: left,
top: top,
width: width,
height: height
};
rate = this.real.width / this.real.height;
width = this.frame.width;
height = this.frame.height;
if (width / height > rate) {
height = width / rate;
} else {
width = height * rate;
}
left = (this.frame.width - width) / 2 + this.frame.left;
top = (this.frame.height - height) / 2 + this.frame.top;
this.image = {
left: left,
top: top,
width: width,
height: height
};
},
async updateData(data) {
this.frame = data.frame;
this.image = data.image;
await this.$nextTick();
this.trimImage();
},
trimImage() {
var rate = this.frame.width / this.frame.height;
var width = this.body.width * 0.7;
var height = this.body.height * 0.7;
if (width / height > rate) {
width = height * rate;
} else {
height = width / rate;
}
var left = (this.body.width - width) / 2;
var top = (this.body.height - height) / 2;
var mul = width / this.frame.width;
var ox = this.frame.left - this.image.left;
var oy = this.frame.top - this.image.top;
this.frame = {
left: left,
top: top,
width: width,
height: height
};
width = this.image.width * mul;
height = this.image.height * mul;
left = this.frame.left - ox * mul;
top = this.frame.top - oy * mul;
this.image = {
left: left,
top: top,
width: width,
height: height
};
if (mul != 1) {
this.transit = true;
setTimeout(() => {
this.transit = false;
}, 300);
}
},
rotateAngle() {
this.rotate -= 90;
var width = this.image.height;
var height = this.image.width;
var left = this.image.left;
var top = this.image.top;
var rate = width / height;
if (width < this.frame.width) {
width = this.frame.width;
height = width / rate;
}
if (height < this.frame.height) {
height = this.frame.height;
width = height * rate;
}
if (left > this.frame.left) {
left = this.frame.left;
}
if (top > this.frame.top) {
top = this.frame.top;
}
if (left + width < this.frame.left + this.frame.width) {
left = this.frame.left + this.frame.width - width;
}
if (top + height < this.frame.top + this.frame.height) {
top = this.frame.top + this.frame.height - height;
}
this.image = {
left: left,
top: top,
width: width,
height: height
};
this.transit = true;
setTimeout(() => {
this.transit = false;
}, 300);
},
onok() {
// #ifdef MP-WEIXIN
this.cropWx();
// #endif
// #ifdef APP-PLUS || H5
this.cropAppH5();
// #endif
},
oncancle() {
this.$emit("cancel");
},
async cropWx() {
var mx = this.computeMatrix();
this.target = {
width: mx.tw,
height: mx.th
};
var canvas = await new Promise((resolve) => {
uni.createSelectorQuery()
.in(this)
.select(".canvas")
.fields({node: true})
.exec((rst) => {
var node = rst[0].node;
resolve(node);
});
});
canvas.width = mx.tw;
canvas.height = mx.th;
uni.showLoading({
title: "处理中"
});
await new Promise((resolve) => {
setTimeout(resolve, 200);
});
var context = canvas.getContext("2d");
var image = canvas.createImage();
await new Promise((resolve, reject) => {
image.onload = resolve;
image.onerror = reject;
image.src = this.url;
});
context.save();
context.rotate(this.rotate * Math.PI / 180);
context.drawImage(image, mx.sx, mx.sy, mx.sw, mx.sh, mx.dx, mx.dy, mx.dw, mx.dh);
context.restore();
uni.canvasToTempFilePath({
canvas: canvas,
destWidth: mx.tw,
destHeight: mx.th,
success: (rst) => {
var path = rst.tempFilePath;
this.$emit("ok", {
path: path
});
},
complete: () => {
uni.hideLoading();
}
});
},
async cropAppH5() {
var mx = this.computeMatrix();
this.target = {
width: mx.tw,
height: mx.th
};
uni.showLoading({
title: "处理中"
});
await new Promise((resolve) => {
setTimeout(resolve, 200);
});
var context = uni.createCanvasContext(this.canvasId, this);
context.save();
context.rotate(this.rotate * Math.PI / 180);
context.drawImage(this.url, mx.sx, mx.sy, mx.sw, mx.sh, mx.dx, mx.dy, mx.dw, mx.dh);
context.restore();
await new Promise((resolve) => {
context.draw(false, resolve);
});
uni.canvasToTempFilePath({
canvasId: this.canvasId,
destWidth: mx.tw,
destHeight: mx.th,
success: (rst) => {
var path = rst.tempFilePath;
// #ifdef H5
var base64 = path;
path = this.parseBlob(path);
this.$emit("ok", {
path: path,
base64: base64
});
// #endif
// #ifdef APP-PLUS
this.$emit("ok", {
path: path
});
// #endif
},
complete: () => {
uni.hideLoading();
}
}, this);
},
computeMatrix() {
var width = this.width;
var height = this.height;
var mul = this.image.width / this.real.width;
if (this.rotate % 180 != 0) {
mul = this.image.height / this.real.width;
}
if (this.mode != "fixed") {
width = this.frame.width / mul;
height = this.frame.height / mul;
}
var rate = width / height;
if (width > this.maxWidth) {
width = this.maxWidth;
height = width / rate;
}
if (height > this.maxHeight) {
height = this.maxHeight;
width = height * rate;
}
var sx = (this.frame.left - this.image.left) / mul;
var sy = (this.frame.top - this.image.top) / mul;
var sw = this.frame.width / mul;
var sh = this.frame.height / mul;
var ox = sx + sw / 2;
var oy = sy + sh / 2;
if (this.rotate % 180 != 0) {
var temp = sw;
sw = sh;
sh = temp;
}
var angle = this.rotate % 360;
if (angle < 0) {
angle += 360;
}
if (angle == 270) {
var x = this.real.width - oy;
var y = ox;
ox = x;
oy = y;
}
if (angle == 180) {
var x = this.real.width - ox;
var y = this.real.height - oy;
ox = x;
oy = y;
}
if (angle == 90) {
var x = oy;
var y = this.real.height - ox;
ox = x;
oy = y;
}
sx = ox - sw / 2;
sy = oy - sh / 2;
var dr = {x: 0, y: 0, w: width, h: height};
dr = this.parseRect(dr, -this.rotate);
return {
tw: width,
th: height,
sx: sx,
sy: sy,
sw: sw,
sh: sh,
dx: dr.x,
dy: dr.y,
dw: dr.w,
dh: dr.h
};
},
parsePoint(point, angle) {
var result = {};
result.x = point.x * Math.cos(angle * Math.PI / 180) - point.y * Math.sin(angle * Math.PI / 180);
result.y = point.y * Math.cos(angle * Math.PI / 180) + point.x * Math.sin(angle * Math.PI / 180);
return result;
},
parseRect(rect, angle) {
var x1 = rect.x;
var y1 = rect.y;
var x2 = rect.x + rect.w;
var y2 = rect.y + rect.h;
var p1 = this.parsePoint({x: x1, y: y1}, angle);
var p2 = this.parsePoint({x: x2, y: y2}, angle);
var result = {};
result.x = Math.min(p1.x, p2.x);
result.y = Math.min(p1.y, p2.y);
result.w = Math.abs(p2.x - p1.x);
result.h = Math.abs(p2.y - p1.y);
return result;
},
parseBlob(base64) {
var arr = base64.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
for(var i = 0; i < n; i++) {
u8arr[i] = bstr.charCodeAt(i);
}
var url = URL || webkitURL;
return url.createObjectURL(new Blob([u8arr], {type: mime}));
},
}
};
</script>
<script module="mwx" lang="wxs">
var mode = "";
var rotate = 0;
var image = {
left: 0,
top: 0,
width: 0,
height: 0
};
var frame = {
left: 0,
top: 0,
width: 0,
height: 0
};
var touches = [];
var touchType = "";
var start = {
frame: {
left: 0,
top: 0,
width: 0,
height: 0
},
image: {
left: 0,
top: 0,
width: 0,
height: 0
}
};
function changeMode(value) {
mode = value;
}
function changeRotate(value, old, oi, instance) {
rotate = value;
updateStyle(oi);
}
function changeImage(value, old, oi, instance) {
image = value;
updateStyle(oi);
}
function changeFrame(value, old, oi, instance) {
frame = value;
updateStyle(oi);
}
function touchstart(event, oi) {
// #ifdef APP-PLUS || H5
event.preventDefault();
event.stopPropagation();
// #endif
touches = event.touches;
var instance = event.instance;
if (instance.hasClass("body")) {
touchType = "body";
} else if (instance.hasClass("frame-left-top")) {
touchType = "left-top";
} else if (instance.hasClass("frame-left-bottom")) {
touchType = "left-bottom";
} else if (instance.hasClass("frame-right-top")) {
touchType = "right-top";
} else if (instance.hasClass("frame-right-bottom")) {
touchType = "right-bottom";
}
start.frame.left = frame.left;
start.frame.top = frame.top;
start.frame.width = frame.width;
start.frame.height = frame.height;
start.image.left = image.left;
start.image.top = image.top;
start.image.width = image.width;
start.image.height = image.height;
return false;
}
function touchmove(event, oi) {
// #ifdef APP-PLUS || H5
event.preventDefault();
event.stopPropagation();
// #endif
var instance = event.instance;
if (touches.length == 1) {
if (touchType == "body") {
moveImage(touches[0], event.touches[0], oi);
} else {
scaleFrame(touches[0], event.touches[0], oi);
}
} else if (touches.length == 2 && event.touches.length == 2) {
var ta = touches[0];
var tb = touches[1];
var tc = event.touches[0];
var td = event.touches[1];
if (ta.identifier != tc.identifier) {
var temp = tc;
tc = td;
td = temp;
}
scaleImage(ta, tb, tc, td, oi);
}
}
function touchend(event, oi) {
touches = [];
oi.callMethod("updateData", {frame: frame, image: image});
}
function touchcancel(event, oi) {
touches = [];
oi.callMethod("updateData", {frame: frame, image: image});
}
function moveImage(ta, tb, oi) {
var ax = tb.clientX - ta.clientX;
var ay = tb.clientY - ta.clientY;
image.left = start.image.left + ax;
image.top = start.image.top + ay;
var left = frame.left;
var top = frame.top;
var width = frame.width;
var height = frame.height;
if (image.left > left) {
image.left = left;
}
if (image.top > top) {
image.top = top;
}
if (image.left + image.width < left + width) {
image.left = left + width - image.width;
}
if (image.top + image.height < top + height) {
image.top = top + height - image.height;
}
updateStyle(oi);
}
function scaleImage(ta, tb, tc, td, oi) {
var x1 = ta.clientX;
var y1 = ta.clientY;
var x2 = tb.clientX;
var y2 = tb.clientY;
var x3 = tc.clientX;
var y3 = tc.clientY;
var x4 = td.clientX;
var y4 = td.clientY;
var ol = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
var el = Math.sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4));
var ocx = (x1 + x2) / 2;
var ocy = (y1 + y2) / 2;
var ecx = (x3 + x4) / 2;
var ecy = (y3 + y4) / 2;
var ax = ecx - ocx;
var ay = ecy - ocy;
var scale = el / ol;
if (start.image.width * scale < frame.width) {
scale = frame.width / start.image.width;
}
if (start.image.height * scale < frame.height) {
scale = frame.height / start.image.height;
}
if (start.image.width * scale < frame.width) {
scale = frame.width / start.image.width;
}
image.left = start.image.left + ax - (ocx - start.image.left) * (scale - 1);
image.top = start.image.top + ay - (ocy - start.image.top) * (scale - 1);
image.width = start.image.width * scale;
image.height = start.image.height * scale;
if (image.left > frame.left) {
image.left = frame.left;
}
if (image.top > frame.top) {
image.top = frame.top;
}
if (image.left + image.width < frame.left + frame.width) {
image.left = frame.left + frame.width - image.width;
}
if (image.top + image.height < frame.top + frame.height) {
image.top = frame.top + frame.height - image.height;
}
updateStyle(oi);
}
function scaleFrame(ta, tb, oi) {
var ax = tb.clientX - ta.clientX;
var ay = tb.clientY - ta.clientY;
var x1 = start.frame.left;
var y1 = start.frame.top;
var x2 = start.frame.left + start.frame.width;
var y2 = start.frame.top + start.frame.height;
var cx1 = false;
var cy1 = false;
var cx2 = false;
var cy2 = false;
var mix = 30;
var rate = frame.width / frame.height;
if (touchType == "left-top") {
x1 += ax;
y1 += ay;
cx1 = true;
cy1 = true;
} else if (touchType == "left-bottom") {
x1 += ax;
y2 += ay;
cx1 = true;
cy2 = true;
} else if (touchType == "right-top") {
x2 += ax;
y1 += ay;
cx2 = true;
cy1 = true;
} else if (touchType == "right-bottom") {
x2 += ax;
y2 += ay;
cx2 = true;
cy2 = true;
}
if (x1 < image.left) {
x1 = image.left;
}
if (y1 < image.top) {
y1 = image.top;
}
if (x2 > image.left + image.width) {
x2 = image.left + image.width;
}
if (y2 > image.top + image.height) {
y2 = image.top + image.height;
}
if (cx1) {
if (x1 > x2 - mix) {
x1 = x2 - mix;
}
}
if (cy1) {
if (y1 > y2 - mix) {
y1 = y2 - mix;
}
}
if (cx2) {
if (x2 < x1 + mix) {
x2 = x1 + mix;
}
}
if (cy2) {
if (y2 < y1 + mix) {
y2 = y1 + mix;
}
}
if (cx1) {
if (mode != "free") {
var val = x2 - rate * (y2 - y1);
if (x1 < val) {
x1 = val;
}
}
}
if (cy1) {
if (mode != "free") {
var val = y2 - (x2 - x1) / rate;
if (y1 < val) {
y1 = val;
}
}
}
if (cx2) {
if (mode != "free") {
var val = rate * (y2 - y1) + x1;
if (x2 > val) {
x2 = val;
}
}
}
if (cy2) {
if (mode != "free") {
var val = (x2 - x1) / rate + y1;
if (y2 > val) {
y2 = val;
}
}
}
frame.left = x1;
frame.top = y1;
frame.width = x2 - x1;
frame.height = y2 - y1;
updateStyle(oi);
}
function updateStyle(oi) {
oi.selectComponent(".frame").setStyle({
"left": frame.left + "px",
"top": frame.top + "px",
"width": frame.width + "px",
"height": frame.height + "px"
});
oi.selectComponent(".image-wrap").setStyle({
"left": image.left + "px",
"top": image.top + "px",
"width": image.width + "px",
"height": image.height + "px"
});
oi.selectComponent(".image-rect").setStyle({
"left": image.left - frame.left + "px",
"top": image.top - frame.top + "px",
"width": image.width + "px",
"height": image.height + "px"
});
var left = 0;
var top = 0;
var width = image.width;
var height = image.height;
if (rotate % 180 != 0) {
width = image.height;
height = image.width;
top = width / 2 - height / 2;
left = height / 2 - width/ 2;
}
oi.selectComponent(".image-wrap .image").setStyle({
"left": left + "px",
"top": top + "px",
"width": width + "px",
"height": height + "px",
"transform": "rotate(" + rotate + "deg)"
});
oi.selectComponent(".image-rect .image").setStyle({
"left": left + "px",
"top": top + "px",
"width": width + "px",
"height": height + "px",
"transform": "rotate(" + rotate + "deg)"
});
}
module.exports = {
changeMode: changeMode,
changeRotate: changeRotate,
changeImage: changeImage,
changeFrame: changeFrame,
touchstart: touchstart,
touchmove: touchmove,
touchend: touchend,
touchcancel: touchcancel
};
</script>
<style scoped>
.panel {
position: absolute;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.canvas {
position: absolute;
top: 5000px;
left: 5000px;
}
.toolbar {
position: absolute;
width: 100%;
height: 100rpx;
left: 0rpx;
bottom: 0rpx;
display: flex;
justify-content: space-around;
align-items: center;
}
.btn-cancel {
font-size: 40rpx;
color: #d5dfe5;
font-weight: bold;
}
.btn-ok {
font-size: 40rpx;
color: #FFFFFF;
font-weight: bold;
}
.btn-rotate {
font-size: 40rpx;
color: #d5dfe5;
font-weight: bold;
}
.body {
position: absolute;
left: 0rpx;
right: 0rpx;
top: 0rpx;
bottom: 0rpx;
background: black;
overflow: hidden;
}
.mask {
position: absolute;
left: 0rpx;
right: 0rpx;
top: 0rpx;
bottom: 0rpx;
background: black;
opacity: 0.4;
}
.plank {
position: absolute;
left: 0rpx;
right: 0rpx;
top: 0rpx;
bottom: 0rpx;
}
.image-wrap {
position: absolute;
}
.image-rect {
position: absolute;
}
.image {
position: absolute;
}
.frame {
position: absolute;
left: 100px;
top: 100px;
width: 200px;
height: 200px;
}
.rect {
position: absolute;
left: -2px;
top: -2px;
width: 100%;
height: 100%;
border: 2px solid white;
overflow: hidden;
box-sizing:content-box;
}
.line-one {
position: absolute;
width: 100%;
height: 1px;
background: white;
left: 0;
top: 33.3%;
box-sizing:content-box;
}
.line-two {
position: absolute;
width: 100%;
height: 1px;
background: white;
left: 0;
top: 66.7%;
box-sizing:content-box;
}
.line-three {
position: absolute;
width: 1px;
height: 100%;
background: white;
top: 0;
left: 33.3%;
box-sizing:content-box;
}
.line-four {
position: absolute;
width: 1px;
height: 100%;
background: white;
top: 0;
left: 66.7%;
box-sizing:content-box;
}
.frame-left-top {
position: absolute;
width: 20px;
height: 20px;
left: -6px;
top: -6px;
border-left: 4px solid red;
border-top: 4px solid red;
box-sizing:content-box;
}
.frame-left-bottom {
position: absolute;
width: 20px;
height: 20px;
left: -6px;
bottom: -6px;
border-left: 4px solid red;
border-bottom: 4px solid red;
box-sizing:content-box;
}
.frame-right-top {
position: absolute;
width: 20px;
height: 20px;
right: -6px;
top: -6px;
border-right: 4px solid red;
border-top: 4px solid red;
box-sizing:content-box;
}
.frame-right-bottom {
position: absolute;
width: 20px;
height: 20px;
right: -6px;
bottom: -6px;
border-right: 4px solid red;
border-bottom: 4px solid red;
box-sizing:content-box;
}
.transit {
transition: width 0.3s, height 0.3s, left 0.3s, top 0.3s, transform 0.3s;
}
</style>

View File

@@ -1,307 +0,0 @@
<template>
<div class="Daily" ref="report">
<div class="top" @click="linkTo" v-if="isShowUnit">
<span>{{ unit }}</span>
</div>
<div class="body" @click="linkTo">
<h2 v-if="isShowTitle">{{ title }}</h2>
<div class="subtitle" v-if="subTitle">{{ subTitle }}</div>
</div>
<div class="bottom">
<div class="bottom-item__wrapper">
<div class="bottom-item" @click="linkTo">
<div class="left" v-if="isShowReporter">
<label>汇报人</label>
<span>{{ reporter }}</span>
</div>
<i v-if="isShowDate">{{ date }}</i>
</div>
<div class="bottom-item bottom-item__remark" @click="linkTo" v-if="isShowRemark">
<label>总结</label>
<span class="">{{ remark }}</span>
</div>
<RenderContent style="margin-top: 20px" :richList="richList" @onLongpress="onLongpress"></RenderContent>
</div>
<div class="add" data-html2canvas-ignore ref="add">
<div class="add-btn" @click.stop="addPhoto">
<span>添加图片</span>
</div>
<div class="add-btn" @click.stop="content = '', isShowText = true">
<span>添加文字</span>
</div>
</div>
</div>
<u-modal v-model="isShowText" @confirm="confirm" title="文本" show-cancel-button>
<view class="slot-content">
<textarea placeholder="请输入文本" :maxlength="-1" v-model="content"></textarea>
</view>
</u-modal>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
import RenderContent from './RenderContent.vue'
import { mapFieldLable } from './../../config'
export default {
name: 'Daily',
label: '日报',
props: ['config'],
components: {
RenderContent
},
data () {
return {
imgs: [],
configList: [],
title: '',
subTitle: '',
reporter: '',
date: '',
unit: '',
remark: '',
isShowTitle: true,
isShowSubTitle: true,
isShowDate: true,
isShowReporter: true,
isShowUnit: true,
isShowRemark: false,
richList: [],
isShowText: false,
content: '',
currIndex: -1
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const title = v.filter(v => v.type === '17')[0]
const subTitle = v.filter(v => v.type === '18')[0]
const reporter = v.filter(v => v.type === '19')[0]
const date = v.filter(v => v.type === '1')[0]
const unit = v.filter(v => v.type === '22')[0]
const remark = v.filter(v => v.type === '32')[0]
this.isShowTitle = title.status === '1'
this.isShowRemark = remark.status === '1'
this.isShowUnit = unit.status === '1'
this.isShowReporter = reporter.status === '1'
this.isShowDate = date.status === '1'
this.isShowSubTitle = subTitle.status === '1'
this.title = title.defaultValue || ''
this.subTitle = subTitle.defaultValue || ''
this.reporter = reporter.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.unit = unit.defaultValue || ''
this.remark = remark.defaultValue || ''
}
},
deep: true
},
},
mounted () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
}
return v
})
uni.$on('change', e => {
this.configList = e
})
},
methods: {
screenshot () {
for (let i = 0; i < this.configList.length; i ++) {
if (['2', '3', '4', '5'].indexOf(this.configList[i].fieldType) === -1 && this.configList[i].fieldType && !this.configList[i].defaultValue && this.configList[i].status === '1') {
this.$u.toast(`请输入${mapFieldLable(this.config[i].type)}`)
return false
}
}
const height = this.$refs.report.offsetHeight - this.$refs.add.offsetHeight
return html2canvas(this.$refs.report, {
allowTaint: true,
useCORS: true,
height
})
},
onLongpress (e) {
if (e.action === 'remove') {
this.richList.splice(e.index, 1)
} else if (e.action === 'edit') {
this.currIndex = e.index
this.content = e.value
this.isShowText = true
} else {
this.richList[e.index].value = e.value
}
},
addPhoto () {
uni.chooseImage({
count: 9,
sizeType: ['compressed'],
success: res => {
res.tempFilePaths.forEach(v => {
this.richList.push({
type: 'img',
value: v
})
})
}
})
},
confirm () {
if (this.currIndex >= 0) {
if (!this.content) {
this.richList.splice(this.currIndex, 1)
} else {
this.richList[this.currIndex].value = this.content
}
} else {
if (this.content) {
this.richList.push({
type: 'text',
value: this.content
})
}
}
this.isShowText = false
this.content = ''
this.currIndex = -1
},
linkTo () {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url: './WatermarkConfig'
})
}
}
}
</script>
<style lang="scss" scoped>
.Daily {
padding: 40px 32px 0;
background: #fff;
* {
box-sizing: border-box;
}
.slot-content {
margin-top: 20px;
padding: 0 30px;
textarea {
width: 100%;
}
}
.top {
display: flex;
align-items: center;
padding: 8px 0 16px;
color: #333333;
font-size: 32px;
border-bottom: 4px solid #000;
}
.body {
margin-top: 16px;
h2 {
font-size: 68px;
color: #333;
font-weight: 600;
}
.subtitle {
margin-top: 24px;
margin-bottom: 24px;
color: #000;
font-size: 34px;
}
}
.bottom {
margin-top: 24px;
.bottom-item__wrapper {
.bottom-item {
display: flex;
justify-content: space-between;
line-height: 64px;
margin-bottom: 16px;
padding: 0 16px;
color: #fff;
font-size: 28px;
background: #D84A36;
i {
font-style: normal;
}
&.bottom-item__remark {
height: auto;
line-height: 1.3;
padding: 12px 16px;
margin-bottom: 0;
color: #D84A36;
font-size: 28px;
text-align: justify;
border: 3px solid #DB6352;
background: #fff;
span {
flex: 1;
}
}
}
}
.add {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
height: 480px;
margin-top: 32px;
background: #F7F7F7;
border-radius: 8px;
.add-btn {
display: flex;
align-items: center;
justify-content: center;
width: 232px;
height: 80px;
color: #FFFFFF;
font-size: 32px;
background: #408EF6;
border-radius: 40px;
&:last-child {
margin-top: 48px;
color: #408EF6;
background: #E7F5FE;
}
}
}
}
}
</style>

View File

@@ -1,330 +0,0 @@
<template>
<div class="InspectLog" ref="report">
<div class="top" @click="linkTo">
</div>
<div class="body" @click="linkTo">
<h2 v-if="isShowTitle">{{ title }}</h2>
<div class="subtitle" v-if="isShowAddress">{{ address }}</div>
</div>
<div class="bottom">
<div class="bottom-item__wrapper" @click="linkTo">
<div class="bottom-item">
<div class="left" v-if="isShowAddress">
<label>巡查人</label>
<span>{{ reporter }}</span>
</div>
<div class="right">
<i v-if="isShowDate">{{ date }} </i>
<i v-if="isShowWeather"> {{ weather }}</i>
</div>
</div>
<div class="bottom-item bottom-item__remark" v-if="isShowRemark" @click="linkTo">
<label>巡查情况</label>
<span>{{ remark }}</span>
</div>
</div>
<RenderContent class="RenderContent" style="margin-top: 20px" :richList="richList" @onLongpress="onLongpress"></RenderContent>
<div class="add" data-html2canvas-ignore ref="add">
<div class="add-btn" @click="addPhoto">
<span>添加图片</span>
</div>
<div class="add-btn" @click.stop="content = '', isShowText = true">
<span>添加文字</span>
</div>
</div>
</div>
<u-modal v-model="isShowText" @confirm="confirm" title="文本" show-cancel-button>
<view class="slot-content">
<textarea placeholder="请输入文本" :maxlength="-1" v-model="content"></textarea>
</view>
</u-modal>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
import { mapFieldLable } from './../../config'
import RenderContent from './RenderContent.vue'
export default {
name: 'InspectLog',
label: '巡查日志',
props: ['config'],
components: {
RenderContent
},
data () {
return {
title: '巡查日志',
subTitle: '',
reporter: '',
date: '',
remark: '',
address: '',
weather: '',
isShowTitle: true,
isShowWeather: true,
isShowDate: true,
isShowReporter: false,
isShowAddress: false,
isShowRemark: false,
imgs: [],
configList: [],
richList: [],
isShowText: false,
content: '',
currIndex: -1
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const title = v.filter(v => v.type === '17')[0]
const reporter = v.filter(v => v.type === '24')[0]
const date = v.filter(v => v.type === '1')[0]
const address = v.filter(v => v.type === '23')[0]
const remark = v.filter(v => v.type === '25')[0]
const weather = v.filter(v => v.type === '2')[0]
this.isShowTitle = title.status === '1'
this.isShowRemark = remark.status === '1'
this.isShowReporter = reporter.status === '1'
this.isShowWeather = weather.status === '1'
this.isShowDate = date.status === '1'
this.isShowAddress = address.status === '1'
this.title = title.defaultValue || '巡查日志'
this.address = address.defaultValue || uni.getStorageSync('address').address
this.weather = uni.getStorageSync('address').weather || ''
this.reporter = reporter.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.remark = remark.defaultValue || ''
}
},
deep: true
},
},
mounted () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '2') {
v.defaultValue = uni.getStorageSync('address').weather || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
}
return v
})
uni.$on('change', e => {
this.configList = e
})
},
methods: {
screenshot () {
for (let i = 0; i < this.configList.length; i ++) {
if (['2', '3', '4', '5'].indexOf(this.configList[i].fieldType) === -1 && this.configList[i].fieldType && !this.configList[i].defaultValue && this.configList[i].status === '1') {
this.$u.toast(`请输入${mapFieldLable(this.config[i].type)}`)
return false
}
}
const height = this.$refs.report.offsetHeight - this.$refs.add.offsetHeight
return html2canvas(this.$refs.report, {
allowTaint: true,
useCORS: true,
height
})
},
onLongpress (e) {
if (e.action === 'remove') {
this.richList.splice(e.index, 1)
} else if (e.action === 'edit') {
this.currIndex = e.index
this.content = e.value
this.isShowText = true
} else {
this.richList[e.index].value = e.value
}
},
addPhoto () {
uni.chooseImage({
count: 9,
sizeType: ['compressed'],
success: res => {
res.tempFilePaths.forEach(v => {
this.richList.push({
type: 'img',
value: v
})
})
}
})
},
confirm () {
if (this.currIndex >= 0) {
if (!this.content) {
this.richList.splice(this.currIndex, 1)
} else {
this.richList[this.currIndex].value = this.content
}
} else {
if (this.content) {
this.richList.push({
type: 'text',
value: this.content
})
}
}
this.isShowText = false
this.content = ''
this.currIndex = -1
},
linkTo () {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url: './WatermarkConfig'
})
}
}
}
</script>
<style lang="scss" scoped>
.InspectLog {
min-height: calc(100vh - 240px);
padding: 48px 32px 0;
background: #133CA5;
* {
box-sizing: border-box;
}
::v-deep .RenderContent {
p {
color: #fff;
}
}
.slot-content {
margin-top: 20px;
padding: 0 30px;
textarea {
width: 100%;
}
}
.top {
width: 100%;
height: 16px;
background: url(./../../images/xc-icon.png) repeat;
background-size: 16px 16px;
}
.body {
margin-top: 32px;
h2 {
font-size: 112px;
color: #fff;
text-align: center;
font-weight: 600;
}
.subtitle {
margin-bottom: 32px;
color: #fff;
text-align: center;
font-size: 40px;
}
}
.bottom {
margin-top: 24px;
.bottom-item__wrapper {
.bottom-item {
display: flex;
justify-content: space-between;
line-height: 64px;
margin-bottom: 16px;
padding: 0 16px;
color: #133CA5;
font-size: 28px;
background: #F9FC4D;
.right {
display: flex;
align-items: center;
i {
font-style: normal;
&:last-child {
margin-left: 8px;
}
}
}
&.bottom-item__remark {
height: auto;
line-height: 1.3;
padding: 12px 16px;
margin-bottom: 0;
font-size: 28px;
text-align: justify;
border: 3px solid #F9FC4D;
span {
flex: 1;
}
}
}
}
.add {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
height: 480px;
margin-top: 72px;
background: #F7F7F7;
border-radius: 8px;
.add-btn {
display: flex;
align-items: center;
justify-content: center;
width: 232px;
height: 80px;
color: #FFFFFF;
font-size: 32px;
background: #408EF6;
border-radius: 40px;
&:last-child {
margin-top: 48px;
color: #408EF6;
background: #E7F5FE;
}
}
}
}
}
</style>

View File

@@ -1,302 +0,0 @@
<template>
<div class="MeetingMminutes" ref="report">
<table @click="linkTo" class="table" border="1" cellspacing="0" cellpadding="16px" bordercolor="#2774CE">
<tr v-if="isShowTitle">
<th colspan="4" class="title">{{ title }}</th>
</tr>
<tr v-if="isShowWeather || isShowDate">
<td v-if="isShowDate" class="nowrap">会议日期</td>
<td colspan="3" v-if="isShowDate">{{ date }}</td>
<!-- <td v-if="isShowWeather" class="nowrap">天气</td>
<td v-if="isShowWeather">{{ weather }}</td> -->
</tr>
<tr v-if="isShowTheme">
<td class="nowrap">会议主题</td>
<td colspan="3">{{ theme }}</td>
</tr>
<tr v-if="isShowRecorder || isShowHoster">
<td class="nowrap" v-if="isShowHoster">主持人</td>
<td v-if="isShowHoster">{{ hoster }}</td>
<td class="nowrap" v-if="isShowRecorder">记录人</td>
<td v-if="isShowRecorder">{{ recorder }}</td>
</tr>
<tr v-if="isShowAttendee">
<td class="nowrap">参与人</td>
<td colspan="3">{{ attendee }}</td>
</tr>
<tr v-if="isShowAddress">
<td class="nowrap">会议地点</td>
<td colspan="3">{{ address }}</td>
</tr>
<tr colspan="2" v-if="isShowRemark">
<td class="nowrap">会议内容</td>
<td colspan="3">{{ remark }}</td>
</tr>
</table>
<RenderContent style="margin-top: 20px" :richList="richList" @onLongpress="onLongpress"></RenderContent>
<div class="bottom" data-html2canvas-ignore ref="add">
<div class="add">
<div class="add-btn" @click="addPhoto">
<span>添加图片</span>
</div>
<div class="add-btn" @click.stop="content = '', isShowText = true">
<span>添加文字</span>
</div>
</div>
</div>
<u-modal v-model="isShowText" @confirm="confirm" title="文本" show-cancel-button>
<view class="slot-content">
<textarea placeholder="请输入文本" :maxlength="-1" v-model="content"></textarea>
</view>
</u-modal>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
import RenderContent from './RenderContent.vue'
import { mapFieldLable } from './../../config'
export default {
name: 'MeetingMminutes',
label: '会议纪要',
props: ['config'],
components: {
RenderContent
},
data () {
return {
title: '巡查日志',
date: '',
hoster: '',
remark: '',
address: '',
recorder: '',
attendee: '',
weather: '',
theme: '',
isShowRecorder: true,
isShowAttendee: true,
isShowTitle: true,
isShowWeather: true,
isShowDate: true,
isShowTheme: true,
isShowAddress: true,
isShowRemark: true,
isShowHoster: true,
imgs: [],
configList: [],
richList: [],
isShowText: false,
content: '',
currIndex: -1
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const title = v.filter(v => v.type === '17')[0]
const hoster = v.filter(v => v.type === '26')[0]
const date = v.filter(v => v.type === '1')[0]
const address = v.filter(v => v.type === '29')[0]
const remark = v.filter(v => v.type === '31')[0]
const theme = v.filter(v => v.type === '30')[0]
const attendee = v.filter(v => v.type === '28')[0]
const recorder = v.filter(v => v.type === '27')[0]
this.isShowTitle = title.status === '1'
this.isShowRemark = remark.status === '1'
this.isShowRecorder = recorder.status === '1'
this.isShowAttendee = attendee.status === '1'
this.isShowTheme = theme.status === '1'
this.isShowDate = date.status === '1'
this.isShowAddress = address.status === '1'
this.isShowHoster = hoster.status === '1'
this.title = title.defaultValue || ''
this.address = address.defaultValue || uni.getStorageSync('address').address
this.hoster = hoster.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.remark = remark.defaultValue || ''
this.theme = theme.defaultValue || ''
this.attendee = attendee.defaultValue || ''
this.recorder = recorder.defaultValue || ''
}
},
deep: true
}
},
mounted () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
}
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
return v
})
uni.$on('change', e => {
this.configList = e
})
},
methods: {
screenshot () {
for (let i = 0; i < this.configList.length; i ++) {
if (['2', '3', '4', '5'].indexOf(this.configList[i].fieldType) === -1 && this.configList[i].fieldType && !this.configList[i].defaultValue && this.configList[i].status === '1') {
this.$u.toast(`请输入${mapFieldLable(this.config[i].type)}`)
return false
}
}
const height = this.$refs.report.offsetHeight - this.$refs.add.offsetHeight
return html2canvas(this.$refs.report, {
allowTaint: true,
useCORS: true,
height
})
},
onLongpress (e) {
if (e.action === 'remove') {
this.richList.splice(e.index, 1)
} else if (e.action === 'edit') {
this.currIndex = e.index
this.content = e.value
this.isShowText = true
} else {
this.richList[e.index].value = e.value
}
},
addPhoto () {
uni.chooseImage({
count: 9,
sizeType: ['compressed'],
success: res => {
res.tempFilePaths.forEach(v => {
this.richList.push({
type: 'img',
value: v
})
})
}
})
},
confirm () {
if (this.currIndex >= 0) {
if (!this.content) {
this.richList.splice(this.currIndex, 1)
} else {
this.richList[this.currIndex].value = this.content
}
} else {
if (this.content) {
this.richList.push({
type: 'text',
value: this.content
})
}
}
this.isShowText = false
this.content = ''
this.currIndex = -1
},
linkTo () {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url: './WatermarkConfig'
})
}
}
}
</script>
<style lang="scss" scoped>
.MeetingMminutes {
padding: 48px 32px 0;
background: #fff;
.slot-content {
margin-top: 20px;
padding: 0 30px;
textarea {
width: 100%;
}
}
.table {
width: 100%;
margin: 0;
padding: 0;
border-spacing: none;
text-align: justify;
.title {
color: #2774CE;
font-size: 58px;
font-weight: 600;
letter-spacing: 2px;
}
.nowrap {
word-break: keep-all;
white-space: nowrap;
color: #2774CE;
font-size: 28px;
font-weight: 600;
}
}
* {
box-sizing: border-box;
}
.bottom {
margin-top: 48px;
.add {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
height: 480px;
margin-top: 72px;
background: #F7F7F7;
border-radius: 8px;
.add-btn {
display: flex;
align-items: center;
justify-content: center;
width: 232px;
height: 80px;
color: #FFFFFF;
font-size: 32px;
background: #408EF6;
border-radius: 40px;
&:last-child {
margin-top: 48px;
color: #408EF6;
background: #E7F5FE;
}
}
}
}
}
</style>

View File

@@ -1,225 +0,0 @@
<template>
<div class="rich">
<div
class="rich-item"
@click="onLongpress(item, index)"
v-for="(item, index) in richList"
:key="index"
:class="[currIndex === index ? 'active' : '']">
<p v-if="item.type === 'text'">{{ item.value }}</p>
<image v-else mode="widthFix" :src="item.value" />
</div>
<u-popup v-model="isShow" z-index="11" :closeable="false" border-radius="32" mode="bottom" @close="onClose">
<div class="rich-bottom">
<div class="top">
<h2>{{ type === 'text' ? '编辑文本' : '编辑图片' }}</h2>
<image @click="isShow = false, currIndex = -1" src="../../images/down_boldw.png" />
</div>
<div class="btns">
<div class="btn-item" hover-class="bg-hover" @click="remove">
<image src="../../images/remove-black.png" />
<span>删除</span>
</div>
<div class="btn-item" hover-class="bg-hover" v-if="type === 'text'" @click="toEditText">
<image src="../../images/xiugai.png" />
<span>修改</span>
</div>
<div class="btn-item" hover-class="bg-hover" @click="toClipping" v-else>
<image src="../../images/jiancai.png" />
<span>剪裁</span>
</div>
</div>
</div>
</u-popup>
</div>
</template>
<script>
export default {
props: ['richList'],
data () {
return {
currIndex: -1,
isShow: false,
type: '',
value: '',
action: ''
}
},
onShow () {
this.isShow = false
},
mounted () {
uni.$on('cropper', e => {
this.$emit('onLongpress', {
type: this.type,
value: e,
index: this.currIndex,
action: 'cropper'
})
this.isShow = false
})
},
methods: {
toEditText () {
this.$emit('onLongpress', {
type: this.type,
value: this.value,
index: this.currIndex,
action: 'edit'
})
this.currIndex = -1
this.isShow = false
},
onClose () {
this.isShow = false
this.currIndex = -1
},
remove () {
this.$confirm(this.type === 'text' ? '确定删除该条数据?' : '确定删掉该图片?').then(() => {
this.$emit('onLongpress', {
type: this.type,
value: this.value,
index: this.currIndex,
action: 'remove'
})
this.currIndex = -1
this.isShow = false
}).catch(() => {
})
},
toClipping () {
uni.navigateTo({
url: `./Clipping?url=${encodeURIComponent(this.value)}`
})
},
onLongpress (item, index) {
this.currIndex = index
this.type = item.type
this.value = item.value
this.isShow = true
},
prview (url) {
uni.previewImage({
urls: [url],
current: url
})
}
}
}
</script>
<style lang="scss" scoped>
.rich {
* {
box-sizing: border-box;
}
.rich-bottom {
// position: fixed;
bottom: 0;
left: 0;
z-index: 11;
width: 100%;
border-radius: 32px 32px 0px 0px;
transition: all ease 0.4s;
overflow: hidden;
background: #fff;
.top {
display: flex;
position: relative;
align-items: center;
justify-content: center;
height: 96px;
h2 {
font-size: 28px;
color: #333333;
line-height: 40px;
}
image {
position: absolute;
top: 50%;
right: 32px;
z-index: 1;
width: 32px;
height: 32px;
transform: translateY(-50%);
}
&.active {
transform: translateY(0);
}
}
.btns {
display: flex;
align-items: center;
height: 246px;
div {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex: 1;
image {
width: 80px;
height: 80px;
}
span {
color: #333333;
font-size: 28px;
}
}
}
&.active {
transform: translateY(0);
}
}
.rich-item {
margin-bottom: 20rpx;
border: 2px solid transparent;
&:last-child {
margin-bottom: 0;
}
&.active {
border: 2px solid #2477F1;
}
p {
line-height: 1.3;
word-break: break-all;
text-align: justify;
font-size: 30rpx;
color: #333;
}
image {
display: block;
width: 100%;
}
}
}
</style>

View File

@@ -1,361 +0,0 @@
<template>
<div class="WorkReport" ref="report">
<div class="top" @click="linkTo">
<span v-if="isShowUnit">{{ unit || '请输入汇报单位' }}</span>
<span v-if="isShowDate">{{ date || '请选择日期' }}</span>
</div>
<div class="body" @click="linkTo">
<h2 v-if="isShowTitle">{{ title }}</h2>
<div class="subtitle" v-if="isShowSubTitle">{{ subTitle || '请输入标题' }}</div>
<div class="partition">
<div><i></i></div>
</div>
</div>
<div class="bottom">
<div class="bottom-item__wrapper">
<div class="bottom-item" v-if="isShowReporter" @click="linkTo">
<label>汇报人{{ reporter || '请输入汇报人姓名' }}</label>
</div>
<div class="bottom-item" v-if="isShowRemark" @click="linkTo">
<span>备注{{ remark }}</span>
</div>
<RenderContent :richList="richList" @onLongpress="onLongpress"></RenderContent>
</div>
<div class="add" data-html2canvas-ignore ref="add">
<div class="add-btn" @click.stop="addPhoto">
<span>添加图片</span>
</div>
<div class="add-btn" @click.stop="content = '', isShowText = true">
<span>添加文字</span>
</div>
</div>
</div>
<u-modal v-model="isShowText" @confirm="confirm" title="文本" show-cancel-button>
<view class="slot-content">
<textarea placeholder="请输入文本" :maxlength="-1" v-model="content"></textarea>
</view>
</u-modal>
</div>
</template>
<script>
import html2canvas from 'html2canvas'
import RenderContent from './RenderContent.vue'
import { mapFieldLable } from './../../config'
export default {
name: 'WorkReport',
label: '工作汇报',
props: ['config'],
components: {
RenderContent
},
data () {
return {
title: '工作汇报',
subTitle: '',
reporter: '',
date: '',
unit: '',
remark: '',
isShowTitle: true,
isShowSubTitle: true,
isShowDate: true,
isShowReporter: true,
isShowUnit: true,
isShowRemark: false,
imgs: [],
configList: [],
richList: [],
isShowText: false,
content: '',
currIndex: -1
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const title = v.filter(v => v.type === '17')[0]
const subTitle = v.filter(v => v.type === '18')[0]
const reporter = v.filter(v => v.type === '19')[0]
const date = v.filter(v => v.type === '1')[0]
const unit = v.filter(v => v.type === '20')[0]
const remark = v.filter(v => v.type === '4')[0]
this.isShowTitle = title.status === '1'
this.isShowRemark = remark.status === '1'
this.isShowUnit = unit.status === '1'
this.isShowReporter = reporter.status === '1'
this.isShowDate = date.status === '1'
this.isShowSubTitle = subTitle.status === '1'
this.title = title.defaultValue || ''
this.subTitle = subTitle.defaultValue || ''
this.reporter = reporter.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.unit = unit.defaultValue || ''
this.remark = remark.defaultValue || ''
}
},
deep: true
},
},
mounted () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
}
return v
})
uni.$on('change', e => {
this.configList = e
})
},
methods: {
screenshot () {
for (let i = 0; i < this.configList.length; i ++) {
if (['2', '3', '4', '5'].indexOf(this.configList[i].fieldType) === -1 && this.configList[i].fieldType && !this.configList[i].defaultValue && this.configList[i].status === '1') {
this.$u.toast(`请输入${mapFieldLable(this.config[i].type)}`)
return false
}
}
const height = this.$refs.report.offsetHeight - this.$refs.add.offsetHeight
return html2canvas(this.$refs.report, {
allowTaint: true,
useCORS: true,
height
})
},
onLongpress (e) {
if (e.action === 'remove') {
this.richList.splice(e.index, 1)
} else if (e.action === 'edit') {
this.currIndex = e.index
this.content = e.value
this.isShowText = true
} else {
console.log(e)
this.richList[e.index].value = e.value
}
},
addPhoto () {
uni.chooseImage({
count: 9,
sizeType: ['compressed'],
success: res => {
res.tempFilePaths.forEach(v => {
this.richList.push({
type: 'img',
value: v
})
})
}
})
},
confirm () {
if (this.currIndex >= 0) {
if (!this.content) {
this.richList.splice(this.currIndex, 1)
} else {
this.richList[this.currIndex].value = this.content
}
} else {
if (this.content) {
this.richList.push({
type: 'text',
value: this.content
})
}
}
this.isShowText = false
this.content = ''
this.currIndex = -1
},
linkTo () {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url: './WatermarkConfig'
})
}
}
}
</script>
<style lang="scss" scoped>
.WorkReport {
padding: 40px 32px 0;
background: #F6F4F0;
* {
box-sizing: border-box;
}
.slot-content {
margin-top: 20px;
padding: 0 30px;
textarea {
width: 100%;
}
}
& > image {
position: fixed;
top: 0;
left: 0;
z-index: 111;
width: 100%;
height: 100vh;
}
.imgs {
margin-top: 20px;
image {
display: block;
width: 100%;
margin-bottom: 10px;
&:last-child {
margin-bottom: 20px;
}
}
}
.top {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
color: #333333;
font-size: 32px;
border-bottom: 4px solid #E3464B;
}
.body {
margin-top: 8px;
h2 {
font-size: 112px;
color: #E3464B;
font-weight: 600;
text-align: center;
border-top: 2px solid #E3464B;
}
.subtitle {
margin-top: 8px;
margin-bottom: 10px;
height: 60px;
line-height: 60px;
border-radius: 30px;
color: #E3464B;
font-size: 32px;
text-align: center;
border: 3px solid #E3464B;
}
.partition {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
div {
position: relative;
z-index: 1;
padding: 0 6px;
background: #F6F4F0;
i {
display: block;
width: 10px;
height: 10px;
border-radius: 50%;
background: #E3464B;
}
}
&::after {
position: absolute;
left: 0;
top: 50%;
width: 100%;
height: 2px;
background: #E3464B;
transform: translateY(-50%);
content: '';
}
}
}
.bottom {
margin-top: 6px;
padding-top: 16px;
border-top: 4px solid #E3464B;
.bottom-item__wrapper {
.bottom-item {
display: flex;
line-height: 44px;
margin-bottom: 16px;
color: #333333;
font-size: 32px;
span {
flex: 1;
text-align: justify;
}
&:last-child {
margin-bottom: 0;
}
}
}
.add {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
height: 480px;
margin-top: 32px;
background: #FFFFFF;
border-radius: 8px;
.add-btn {
display: flex;
align-items: center;
justify-content: center;
width: 232px;
height: 80px;
color: #FFFFFF;
font-size: 32px;
background: #408EF6;
border-radius: 40px;
&:last-child {
margin-top: 48px;
color: #408EF6;
background: #E7F5FE;
}
}
}
}
}
</style>

View File

@@ -1,197 +0,0 @@
<template>
<div class="Watermark1" @click.stop="linkTo('./WatermarkConfig')">
<div class="top">
<h2>打卡记录</h2>
<p>{{ time }}</p>
</div>
<div class="info">
<p>{{ date }} {{ weekCn }}</p>
<p>{{ address }}</p>
<p v-if="isShowWeather">{{ weather }}</p>
</div>
<div class="text" v-if="isShowRemark">{{ remark }}</div>
</div>
</template>
<script>
export default {
props: ['config', 'addressInfo'],
data () {
return {
date: '',
time: '',
week: '',
weather: '',
remark: '',
address: '',
timer: null,
configList: [],
isShowWeather: false,
isShowRemark: false
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const weather = v.filter(v => v.type === '2')[0]
const remark = v.filter(v => v.type === '4')[0]
this.isShowWeather = weather.status === '1'
this.isShowRemark = remark.status === '1'
this.remark = remark.defaultValue || ''
this.address = uni.getStorageSync('address').address || ''
this.weather = uni.getStorageSync('address').weather || ''
}
},
deep: true
},
addressInfo: {
handler: function (v) {
if (v.address) {
this.address = uni.getStorageSync('address').address || ''
this.weather = uni.getStorageSync('address').weather || ''
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '2') {
v.defaultValue = uni.getStorageSync('address').weather || ''
}
return v
})
}
},
deep: true
}
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '2') {
v.defaultValue = uni.getStorageSync('address').weather || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
return v
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.timer = setInterval(() => {
this.date = this.$dayjs().format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
}, 1000)
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark1 {
* {
box-sizing: border-box;
}
.text {
min-width: 274px;
height: 48px;
line-height: 48px;
margin-top: 32px;
padding: 0 16px;
font-size: 28px;
background: linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.2) 100%);
}
.top {
width: 184px;
background: #FEFFFE;
border-radius: 16px;
text-align: center;
overflow: hidden;
h2 {
height: 64px;
line-height: 64px;
background: #1ABDA6;
font-size: 34px;
font-weight: normal;
}
p {
height: 72px;
line-height: 72px;
font-weight: 600;
color: #333333;
font-size: 48px;
}
}
.info {
line-height: 40px;
margin: 32px 0 0;
padding-left: 22px;
border-left: 6px solid #F8BC58;
p:nth-of-type(2) {
margin: 8px 0;
}
}
}
</style>

View File

@@ -1,208 +0,0 @@
<template>
<div class="Watermark3" @click.stop="linkTo('./WatermarkConfig')">
<div class="top">
<h2 v-if="isShowTitle">{{ title }}</h2>
<span v-if="isShowName">{{ name }}</span>
</div>
<div class="middle">
<h2 v-if="isShowTime">{{ time }}</h2>
<span v-if="isShowWeather">{{ weather }}</span>
</div>
<p v-if="isShowDate">{{ date }} {{ weekCn }}</p>
<div class="text" v-if="isShowMatters && matters">
<span>{{ matters }}</span>
<image src="./../../images/quotes.png" />
</div>
</div>
</template>
<script>
export default {
props: ['config'],
data () {
return {
date: '',
time: '',
week: '',
timer: null,
name: '',
weather: '',
title: '巡检水印',
configList: [],
matters: '',
isShowWeather: false,
isShowDate: false,
isShowTitle: false,
isShowTime: false,
isShowName: false,
isShowMatters: false
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const weather = v.filter(v => v.type === '2')[0]
const date = v.filter(v => v.type === '1')[0]
const time = v.filter(v => v.type === '0')[0]
const title = v.filter(v => v.type === '5')[0]
const name = v.filter(v => v.type === '6')[0]
const matters = v.filter(v => v.type === '7')[0]
this.isShowWeather = weather.status === '1'
this.isShowDate = date.status === '1'
this.isShowTitle = title.status === '1'
this.isShowTime = time.status === '1'
this.isShowName = name.status === '1'
this.isShowMatters = matters.status === '1'
this.title = title.defaultValue || ''
this.name = name.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = time.defaultValue || this.$dayjs().format('HH:mm')
this.weather = uni.getStorageSync('address').weather || ''
this.matters = matters.defaultValue || ''
this.week = date.defaultValue ? this.$dayjs(date.defaultValue).day() : new Date().getDay()
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
if (v.fieldType === '2') {
v.defaultValue = uni.getStorageSync('address').weather || ''
}
return v
})
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark3 {
width: 348px;
line-height: 1;
padding: 16px;
background: rgba(56, 167, 255, 0.6);
border-radius: 4px;
* {
box-sizing: border-box;
}
.text {
position: relative;
margin-top: 20px;
padding-left: 10px;
font-size: 28px;
image {
position: absolute;
top: -6px;
left: 0;
width: 28px;
height: 24px;
}
}
.middle {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
h2 {
font-size: 68px;
font-weight: normal;
}
span {
color: #53FBFF;
font-size: 28px;
}
}
& > p {
margin-top: 16px;
font-weight: 500;
font-size: 28px;
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 6px 0 0 6px;
border-bottom: 4px solid #FFE97A;
h2 {
height: 56px;
line-height: 56px;
padding: 0 6px;
text-align: center;
color: #498abe;
font-size: 30px;
border-radius: 6px 6px 0 0;
background: #FFE97A;
}
span {
font-size: 28px;
}
}
}
</style>

View File

@@ -1,199 +0,0 @@
<template>
<div class="Watermark2" @click.stop="linkTo('./WatermarkConfig')">
<div class="top">
<div class="left">
<h2>{{ time }}</h2>
</div>
<div class="right">
<h2>{{ date }} </h2>
<p>{{ weekCn }}</p>
</div>
</div>
<p>{{ address }}</p>
<div class="text" v-if="isShowRemark">{{ remark }}</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: ['config'],
data () {
return {
date: '',
time: '',
week: '',
timer: null,
address: '',
remark: '',
configList: [],
isShowRemark: false
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const remark = v.filter(v => v.type === '4')[0]
this.isShowRemark = remark.status === '1'
this.remark = remark.defaultValue || ''
this.address = uni.getStorageSync('address').address || ''
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
return v
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.timer = setInterval(() => {
this.date = this.$dayjs().format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
}, 1000)
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
...mapActions(['injectJWeixin']),
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark2 {
* {
box-sizing: border-box;
}
.text {
min-width: 274px;
height: 48px;
line-height: 48px;
padding: 0 16px;
font-size: 28px;
background: linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.7) 100%);
}
.top {
display: flex;
align-items: center;
.left {
position: relative;
margin-right: 38px;
&:after {
position: absolute;
top: 50%;
right: -16px;
z-index: 1;
width: 6px;
height: 72px;
background: #F8BC58;
transform: translateY(-50%);
content: '';
}
h2 {
font-size: 68px;
font-weight: 500;
color: #FFFFFF;
line-height: 80px;
}
}
.right {
font-size: 24px;
font-weight: 500;
color: #FFFFFF;
h2 {
margin-bottom: 8px;
font-weight: 500;
font-size: 24px;
}
}
}
& > p {
margin: 20px 0 16px;
font-weight: 600;
color: #fff;
font-size: 24px;
}
.info {
line-height: 40px;
margin: 32px 0;
padding-left: 22px;
border-left: 6px solid #F8BC58;
p:nth-of-type(2) {
margin: 8px 0;
}
}
}
</style>

View File

@@ -1,204 +0,0 @@
<template>
<div class="Watermark6" @click.stop="linkTo('./WatermarkConfig')">
<div class="title">
<h2>{{ title }}</h2>
</div>
<div class="info">
<div class="info-item">
<label>时间</label>
<span>{{ date }} {{ weekCn}} {{ time }}</span>
</div>
<div class="info-item">
<label>地点</label>
<span>{{ address }}</span>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: ['config'],
data () {
return {
date: '',
timer: null,
week: '',
title: '定格在这一刻',
address: '',
configList: []
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v && v.length) {
const date = v.filter(v => v.type === '1')[0]
const time = v.filter(v => v.type === '0')[0]
const title = v.filter(v => v.type === '5')[0]
this.title = title.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = time.defaultValue || this.$dayjs().format('HH:mm')
this.week = date.defaultValue ? this.$dayjs(date.defaultValue).day() : new Date().getDay()
this.address = uni.getStorageSync('address').address || ''
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
this.address = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
return v
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
...mapActions(['injectJWeixin']),
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark6 {
width: 450px;
box-sizing: border-box;
h2 {
font-weight: normal;
}
* {
box-sizing: border-box;
}
.info {
padding: 24px;
background: rgba(255, 255, 255, 0.7);
.info-item {
display: flex;
line-height: 1.3;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
label {
color: #333;
font-size: 28px;
}
span {
flex: 1;
text-align: justify;
color: #000000;
font-size: 28px;
}
}
}
.title {
position: relative;
height: 60px;
line-height: 60px;
text-align: center;
color: #fff;
background: rgba(23, 91, 255, 0.7);
h2 {
font-size: 32px;
}
&::after {
position: absolute;
left: 16px;
top: 50%;
z-index: 1;
width: 12px;
height: 12px;
border-radius: 50%;
background: #FFCA32;
content: ' ';
transform: translateY(-50%);
}
&::before {
position: absolute;
right: 16px;
top: 50%;
z-index: 1;
width: 12px;
height: 12px;
border-radius: 50%;
background: #FFCA32;
content: ' ';
transform: translateY(-50%);
}
}
}
</style>

View File

@@ -1,206 +0,0 @@
<template>
<div class="Watermark4" @click.stop="linkTo('./WatermarkConfig')">
<div class="top">
<image src="./../../images/fangyishuiyin.png" />
<h2>{{ title }}</h2>
</div>
<div class="Watermark4-body">
<h2 v-if="isShowTime">{{ time }}</h2>
<p v-if="isShowDate">{{ date }} {{ weekCn }}</p>
<div class="info">
<div class="info-item" v-if="isShowAddress">
<label>地点</label>
<span>{{ address }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: ['config'],
data () {
return {
date: '',
time: '',
week: '',
timer: null,
title: '日常消杀',
address: '',
configList: [],
isShowAddress: true,
isShowDate: true,
isShowTime: true
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const title = v.filter(v => v.type === '5')[0]
const address = v.filter(v => v.type === '3')[0]
const date = v.filter(v => v.type === '1')[0]
const time = v.filter(v => v.type === '0')[0]
this.isShowAddress = address.status === '1'
this.isShowDate = date.status === '1'
this.isShowTime = time.status === '1'
this.title = title.defaultValue || ''
this.date = date.defaultValue || this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = time.defaultValue || this.$dayjs().format('HH:mm')
this.week = date.defaultValue ? this.$dayjs(date.defaultValue).day() : new Date().getDay()
this.address = address.defaultValue || ''
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
return v
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
...mapActions(['injectJWeixin']),
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark4 {
width: 400px;
line-height: 1;
border-radius: 4px;
* {
box-sizing: border-box;
}
.top {
position: relative;
width: 400px;
height: 60px;
line-height: 60px;
padding-left: 60px;
background: linear-gradient(270deg, rgba(67, 60, 255, 0) 0%, rgba(60, 163, 255, 0.8) 50%, #3B92FF 100%);
image {
position: absolute;
left: -32px;
top: -16px;
z-index: 1;
width: 92px;
height: 112px;
}
h2 {
font-weight: 500;
font-size: 32px;
color: #fff;
}
}
.Watermark4-body {
padding: 24px 20px;
background: linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.5) 50%, rgba(0, 0, 0, 0.5) 100%);
& > h2 {
line-height: 56px;
font-size: 48px;
font-weight: bold;
color: #FFFFFF;
}
& > p {
line-height: 36px;
margin-bottom: 16px;
font-size: 26px;
color: #FFFFFF;
}
.info {
.info-item {
display: flex;
line-height: 1.4;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
label {
color: #BADCFF;
font-size: 28px;
}
span {
flex: 1;
font-size: 28px;
}
}
}
}
}
</style>

View File

@@ -1,262 +0,0 @@
<template>
<div class="Watermark5" @click.stop="linkTo('./WatermarkConfig')">
<div class="top">
<h2>{{ title }}</h2>
<div class="right">
<h2>{{ time }}</h2>
<p>{{ date }}</p>
</div>
</div>
<div class="info">
<div class="info-item">
<label>网格员</label>
<span>{{ gridUserName }}</span>
</div>
<div class="info-item" v-if="isShowGridName">
<label>网格</label>
<span>{{ gridName }}</span>
</div>
<div class="info-item" v-if="isShowAddress">
<label>地点</label>
<span>{{ address }}</span>
</div>
<div class="info-item" v-if="isServiceName">
<label>服务对象</label>
<span>{{ serviceName }}</span>
</div>
</div>
<div class="bottom" v-if="isShowText">
<span>工作纪实</span>
<i>{{ text }}</i>
</div>
<div class="line"></div>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
props: ['config'],
data () {
return {
date: '',
time: '',
week: '',
address: '',
title: '',
timer: null,
gridUserName: '',
gridName: '',
isShowAddress: true,
isShowDate: true,
isShowTime: true,
isShowGridName: true,
serviceName: '',
isServiceName: false,
text: '',
isShowText: '',
configList: []
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const address = v.filter(v => v.type === '3')[0]
const gridUserName = v.filter(v => v.type === '9')[0]
const gridName = v.filter(v => v.type === '10')[0]
const title = v.filter(v => v.type === '8')[0]
const serviceName = v.filter(v => v.type === '11')[0]
const text = v.filter(v => v.type === '12')[0]
this.isShowAddress = address.status === '1'
this.isShowGridName = gridName.status === '1'
this.isServiceName = serviceName.status === '1'
this.isShowText = text.status === '1'
this.title = title.defaultValue || ''
this.gridUserName = gridUserName.defaultValue || ''
this.gridName = gridName.defaultValue || ''
this.serviceName = serviceName.defaultValue || ''
this.text = text.defaultValue || ''
this.address = address.defaultValue || ''
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
this.address = uni.getStorageSync('address').address || ''
}
return v
})
uni.$on('change', e => {
this.configList = e
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.timer = setInterval(() => {
this.date = this.$dayjs().format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
}, 1000)
},
destroyed () {
clearInterval(this.timer)
uni.$off('change')
},
methods: {
...mapActions(['injectJWeixin']),
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark5 {
width: 440px;
padding: 0 16px 22px;
color: #000;
box-sizing: border-box;
background: #fff;
h2 {
font-weight: normal;
}
* {
box-sizing: border-box;
}
.line {
margin-top: 4px;
height: 4px;
background: #2145C4;
}
.bottom {
display: flex;
align-items: center;
border: 3px solid #2145C4;
span {
width: 120px;
height: 48px;
line-height: 48px;
text-align: center;
color: #fff;
font-size: 26px;
background: #2145C4;
}
i {
flex: 1;
color: #2145C4;
font-size: 26px;
font-style: normal;
text-align: center;
}
}
.info {
margin-bottom: 16px;
.info-item {
display: flex;
line-height: 1.3;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
label {
color: #333;
font-size: 26px;
}
span {
flex: 1;
color: #000000;
font-size: 26px;
font-weight: 600;
}
}
}
.top {
display: flex;
align-items: center;
justify-content: space-between;
height: 90px;
margin-bottom: 20px;
color: #2145C4;
border-bottom: 4px solid #2145C4;
& > h2 {
font-size: 32px;
font-weight: 600;
}
.right {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
h2 {
width: 96px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 30px;
background: #2145C4;
}
p {
font-size: 24px;
}
}
}
}
</style>

View File

@@ -1,183 +0,0 @@
<template>
<div class="Watermark7" @click.stop="linkTo('./WatermarkConfig')">
<image src="../../images/hjws.png" />
<h2 v-if="isShowTitle">{{ title }}</h2>
<div class="middle">
<div class="top">
<h2>{{ time }}</h2>
<span>{{ weather }}</span>
</div>
<div class="bottom">{{ date }} {{ weekCn }}</div>
</div>
<div class="bottom" v-if="isShowAddress">{{ address }}</div>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
props: ['config'],
data () {
return {
date: '',
time: '',
title: '',
week: '',
weather: '',
address: '',
timer: null,
isShowTitle: true,
isShowAddress: true,
configList: []
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
watch: {
configList: {
handler: function (v) {
if (v.length) {
const address = v.filter(v => v.type === '3')[0]
const title = v.filter(v => v.type === '5')[0]
this.isShowAddress = address.status === '1'
this.isShowTitle = title.status === '1'
this.title = title.defaultValue || ''
this.address = address.defaultValue || ''
}
},
deep: true
},
},
created () {
this.configList = JSON.parse(JSON.stringify(this.config)).map(v => {
if (v.fieldType === '3') {
v.defaultValue = uni.getStorageSync('address').address || ''
}
if (v.fieldType === '2') {
v.defaultValue = uni.getStorageSync('address').weather || ''
}
if (v.fieldType === '7') {
v.defaultValue = this.$dayjs().format('YYYY-MM-DD')
this.week = new Date().getDay()
}
if (v.fieldType === '6') {
v.defaultValue = this.$dayjs().format('HH:mm')
}
return v
})
this.date = this.$dayjs(new Date).format('YYYY-MM-DD')
this.time = this.$dayjs().format('HH:mm')
this.week = new Date().getDay()
uni.$on('change', e => {
this.configList = e
})
},
destroyed () {
clearInterval(this.timer)
},
methods: {
linkTo (url) {
uni.setStorageSync('waterConfig', this.configList)
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark7 {
width: 400px;
font-size: 0;
box-sizing: border-box;
h2 {
font-weight: normal;
}
* {
box-sizing: border-box;
}
& > image {
width: 100%;
height: 64px;
}
& > .bottom {
line-height: 1.3;
padding: 10px 16px;
font-size: 26px;
text-align: justify;
background: rgba(27, 120, 65, 0.8);
}
.middle {
line-height: 1;
padding: 16px;
background: rgba(0, 0, 0, 0.5);
.top {
display: flex;
align-items: center;
margin-bottom: 6px;
h2 {
margin-right: 16px;
color: #FFFFFF;
font-size: 48px;
}
span {
color: #62CD8B;
font-size: 26px;
}
}
.bottom {
font-size: 26px;
}
}
& > h2 {
height: 64px;
line-height: 64px;
text-align: center;
color: #fff;
font-size: 32px;
background: #1B7841;
}
}
</style>

View File

@@ -1,102 +0,0 @@
<template>
<div class="Watermark8">
<h2>{{ date }}</h2>
<div>{{ day }}</div>
<p>{{ lunar }} {{ weekCn }}</p>
</div>
</template>
<script>
import lunar from '../../config/calendar'
export default {
data () {
return {
date: '',
week: '',
day: '',
lunar: '',
timer: null
}
},
computed: {
weekCn() {
if (this.week === 1) {
return '星期一'
}
if (this.week === 2) {
return '星期二'
}
if (this.week === 3) {
return '星期三'
}
if (this.week === 4) {
return '星期四'
}
if (this.week === 5) {
return '星期五'
}
if (this.week === 6) {
return '星期六'
}
return '星期天'
}
},
created () {
const date = this.$dayjs(new Date)
const result = lunar.solarToLunar(date.format('YYYY'), date.format('MM'), date.format('DD'))
this.date = date.format('YYYY年MM月')
this.day = date.format('DD')
this.lunar = `${result.monthStr}${result.dayStr}`
this.week = new Date().getDay()
},
destroyed () {
clearInterval(this.timer)
},
methods: {
linkTo (url) {
uni.navigateTo({
url
})
}
}
}
</script>
<style lang="scss" scoped>
.Watermark8 {
width: 292px;
height: 376px;
color: #FF5643;
box-sizing: border-box;
text-align: center;
background-image: url(../../images/rili.png);
background-size: 100% 100%;
h2 {
height: 68px;
padding-top: 106px;
text-align: center;
font-size: 32px;
color: #fff;
font-weight: normal;
}
div {
line-height: 1;
margin: 10px 0 8px;
font-size: 100px;
font-weight: 600;
}
p {
font-size: 26px;
}
}
</style>

View File

@@ -1,327 +0,0 @@
/*
* 农历数据表
*
* 农历分大小月大月30天小月29天但一年中哪个月为大月哪个月为小月是无规律的。
* 农历每十年有4个闰年但哪一年为闰年也是不确定的。
* 而闰月中,哪个闰月为大月,哪个为小月也是不确定的。
*
* 下面共20行每行10个数据。每个数据代表一年从阳历1900.1.31日起为第一个数据年的开始即阳历1900.1.31农历0.1.1。
* 200个数据可推200年的农历因此目前最大只能推算到2100年
*
* 对于每一个数据项5个十六进制数 = 20个二进制位
* 前4位即0在这一年是闰年时才有意义它代表这年闰月的大小月为1则闰大月为0则闰小月。
* 中间12位即4bd每位代表一个月为1则为大月为0则为小月。
* 最后4位即8代表这一年的闰月月份为0则不闰。首4位要与末4位搭配使用。
*/
const lunarInfo = new Array(
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900年~1909年
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910年~1919年
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920年~1929年
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930年~1939年
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940年~1949年
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950年~1959年
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960年~1969年
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, // 1970年~1979年
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980年~1989年
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, // 1990年~1999年
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000年~2009年
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010年~2019年
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020年~2029年
0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030年~2039年
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040年~2049年
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050年~2059年
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060年~2069年
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070年~2079年
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080年~2089年
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090年~2099年
0x0d520 // 2100年
);
const minYear = 1900; // 能计算的最小年份
const maxYear = 2100; // 能计算的最大年份
// 阳历每月天数遇到闰年2月需加1天
const solarMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
// 农历月份别称
const monthName = new Array('正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月');
// 二十四节气
const solarTerm = new Array(
'小寒', '大寒', '立春', '雨水', '惊蛰', '春分',
'清明', '谷雨', '立夏', '小满', '芒种', '夏至',
'小暑', '大暑', '立秋', '处暑', '白露', '秋分',
'寒露', '霜降', '立冬', '小雪', '大雪', '冬至'
);
// 二十节气相关系数
const termInfo = new Array(
0, 21208, 42467, 63836, 85337, 107014,
128867, 150921, 173149, 195551, 218072, 240693,
263343, 285989, 308563, 331033, 353350, 375494,
397447, 419210, 440795, 462224, 483532, 504758);
/**
* 检查年份是否输入正确
* @param year int 年份
*/
function _checkYear(year) {
if (year < minYear) {
throw new RangeError('年份不能小于' + minYear + '年');
} else if (year > maxYear) {
throw new RangeError('年份不能大于' + maxYear + '年');
}
return true;
}
/**
* 检查月份是否输入正确
* @param month int 月份
*/
function _checkMonth(month) {
if (month < 1) {
throw new RangeError('月份不能小于1');
} else if (month > 12) {
throw new RangeError('月份不能大于12');
}
return true;
}
/**
* 检查日期是否输入正确
* @param day int 日期
*/
function _checkDay(day) {
if (day < 1) {
throw new RangeError('日期不能小于1');
} else if (day > 31) {
throw new RangeError('日期不能大于31');
}
return true;
}
/**
* 返回农历year年中哪个月是闰月没有闰月返回0
* @param year int 年份
*/
function getLunarLeapMonth(year) {
if (_checkYear(year)) {
return lunarInfo[year - minYear] & 0xf; // 最后4位代表这一年的闰月月份为0则今年没有闰月
}
}
/**
* 返回农历year年闰月的天数如果没有闰月则返回0
* @param year int 年份
*/
function getLeapMonthDaysCount(year) {
if (getLunarLeapMonth(year)) {
return lunarInfo[year - minYear] & 0x10000 ? 30 : 29; // 前4位即0在这一年是闰年时才有意义它代表这年闰月的大小月
}
return 0;
}
/**
* 返回农历year年的总天数
* @param year int 年份
*/
function getLunarYearDaysCount(year) {
if (_checkYear(year)) {
let sum = 348; // 29天 * 12个月 = 348日
for (let i = 0x8000; i > 0x8; i >>= 1) {
sum += (lunarInfo[year - minYear] & i ? 1 : 0);
}
return sum + getLeapMonthDaysCount(year);
}
}
/**
* 返回农历year年month月的天数
* @param year int 年份
* @param month int 月份 1~12
*/
function getLunarYearMonthDaysCount(year, month) {
if (_checkYear(year) && _checkMonth(month)) {
return lunarInfo[year - minYear] & (0x10000 >> month) ? 30 : 29;
}
}
/**
* 农历日期的中文字符串
* @param day int 日期
*/
function getLunarDayString(day) {
if (_checkDay(day)) {
const nStr1 = new Array('日', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十');
const nStr2 = new Array('初', '十', '廿', '卅');
let str = '';
switch (day) {
case 10:
str = '初十';
break;
case 20:
str = '二十';
break;
case 30:
str = '三十';
break;
default:
str = nStr2[Math.floor(day / 10)];
str += nStr1[day % 10];
break;
}
return str;
}
}
/**
* 返回某年的第n个节气为几日(从0小寒起算)
* @param year int 年份
* @param n 节气编号 0~23
*/
function getLunarTermDay(year, n) {
if (_checkYear(year) && n <= 23 && n >= 0) {
const sTermInfo = new Array(0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758);
const offDate = new Date((31556925974.7 * (year - minYear) + sTermInfo[n] * 60000) + Date.UTC(minYear, 0, 6, 2, 5));
return offDate.getUTCDate();
}
}
/**
* 阳历日期转农历日期
* @param year int 年份
* @param month int 月份 1~12
* @param day int 日期 1~31
*/
function solarToLunar(year, month, day) {
if (_checkYear(year) && _checkMonth(month) && _checkDay(day)) {
const baseDate = new Date(minYear, 0, 31); // 基础日期1900年1月31日
const objDate = new Date(year, month - 1, day); // 目标日期
let offset = parseInt((objDate - baseDate) / 86400000); // 偏移天数 60 * 60 * 24 * 1000 = 864000001天的毫秒数
let temp = 0;
let i = 0;
for (i = minYear; i < maxYear && offset > 0; i++) {
temp = getLunarYearDaysCount(i); // 农历year年的总天数
if (offset < temp) {
break;
} else {
offset -= temp;
}
}
const lunarYear = i; // 农历年份
const leap = getLunarLeapMonth(lunarYear); // 当年闰月是哪个月
let isLeapMonth = false; // 当前农历月份是否是闰月
for (i = 1; i <= 12 && offset > 0; i++) {
if (leap > 0 && i == (leap + 1) && !isLeapMonth) {
--i;
isLeapMonth = true;
temp = getLeapMonthDaysCount(lunarYear);
} else {
isLeapMonth = false;
temp = getLunarYearMonthDaysCount(lunarYear, i);
}
if (offset < temp) {
break;
} else {
offset -= temp;
}
}
const lunarMonth = i; // 农历月份
const lunarDay = offset + 1; // 农历日期
let monthStr = '';
if (isLeapMonth) {
monthStr = '闰' + monthName[lunarMonth - 1];
} else {
monthStr = monthName[lunarMonth - 1];
}
return {
year: lunarYear, // 农历年份
month: lunarMonth, // 农历月份
day: lunarDay, // 农历日期
isLeap: isLeapMonth, // 是否闰月
monthStr: monthStr, // 月份字符串
dayStr: getLunarDayString(lunarDay) // 日期字符串
};
}
}
/**
* 阳历某个月份天数
* @param year int 年份
* @param month int 月份 1~12
*/
function getSolarMonthDaysCount(year, month) {
if (_checkYear(year) && _checkMonth(month)) {
if (month == 2) {
return (((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0)) ? 29 : 28);
} else {
return solarMonth[month - 1];
}
}
}
/**
* 获取指定日期是阳历年中的第几天
* @param year int 年份
* @param month int 月份 1-12
* @param day int 日期
*/
function getSolarDayNumber(year, month, day) {
if (_checkYear(year) && _checkMonth(month) && _checkDay(day)) {
const date = new Date(year, month - 1, day);
const d = date.getDate(); // 本月第几天
const m = month - 1;
let sum = d;
for (let i = 0; i < m; i++) {
sum += solarMonth[i];
}
if (m > 1 && (year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
sum += 1;
}
return sum;
}
}
/**
* 计算指定日期是否属于24节气
* @param year int 年份
* @param month int 月份 1~12
* @param day int 日期 1~31
*/
function getLunar24Days(year, month, day) {
if (_checkYear(year) && _checkMonth(month) && _checkDay(day)) {
const baseDate = new Date(1900, 0, 6, 2, 5, 0);
let str = false;
for (let i = 1; i <= 24; i++) {
const num = 525948.76 * (year - 1900) + termInfo[i];
const timestamp = baseDate.getTime() + num * 60 * 1000;
const newDate = new Date(timestamp);
if (getSolarDayNumber(newDate.getFullYear(), newDate.getMonth() + 1, newDate.getDate()) ==
getSolarDayNumber(year, month, day)) {
str = solarTerm[i];
break;
}
}
return str;
}
}
module.exports = {
getLunarLeapMonth, // 返回农历year年中哪个月是闰月没有闰月返回0
getLeapMonthDaysCount, // 返回农历year年闰月的天数如果没有闰月则返回0
getLunarYearDaysCount, // 返回农历year年的总天数
getLunarYearMonthDaysCount, // 返回农历year年month月的天数
getLunarDayString, // 农历日期的中文字符串
getLunarTermDay, // 返回某年的第n个节气为第几日
getSolarMonthDaysCount, // 获取阳历某个月份有多少天
getSolarDayNumber, // 获取指定日期是阳历年中的第几天
getLunar24Days, // 计算指定日期是否属于24节气
solarToLunar, // 阳历日期转农历日期
}

View File

@@ -1,85 +0,0 @@
export const config = [
{
name: '打卡水印',
type: '0',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/1.png'
},
{
name: '巡查水印',
type: '1',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/3.png'
},
{
name: '时间地点水印',
type: '2',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/2.png'
},
{
name: '标题水印',
type: '3',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/6.png'
},
{
name: '防疫水印',
type: '4',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/4.png'
},
{
name: '网格化水印',
type: '5',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/5.png'
},
{
name: '环境卫生水印',
type: '6',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/7.png'
},
{
name: '日历水印',
type: '7',
thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/8.png'
},
// {
// name: '自定义水印',
// type: '9',
// thum: 'https://cdn.cunwuyun.cn/dvcp/h5/watermark/1.png'
// }
]
export const mapFieldLable = type => {
return {
0: '时间',
1: '日期',
2: '天气',
3: '地点',
4: '备注',
5: '标题',
6: '巡检人',
7: '巡查事项',
8: '工作主题',
9: '网格员',
10: '网格名称',
11: '服务对象',
12: '工作纪实',
13: '日历',
14: '拍摄人',
15: '经纬度',
16: '自定义文字',
17: '大标题',
18: '小标题',
19: '汇报人',
20: '汇报单位',
21: '颜色设置',
22: '工作单位',
23: '巡查地点',
24: '巡查人',
25: '巡查情况',
26: '主持人',
27: '记录人',
28: '参与人',
29: '会议地点',
30: '会议主题',
31: '会议内容',
32: '总结',
}[type]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 972 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

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